WPF类层次结构

各种视觉相关的类

下图来自 <<Wpf控件开发>>

DispatcherObject

  • 位于System.Windows.Threading 名字空间中
  • 为WPF 的所有对象提供了基本的消息与多线程支持
  • 主要需要关注其Dispatcher 属性,它允许你访问对象相关的Dispatcher(调度者,译注:与多线程访问相关)。顾名思义,该类所引入的调度系统负责监听各种消息,在界面所在的线程中将消息发送给相应的对象

DependencyObject

  • 用于支持WPF 中的依赖属性系统,依赖属性系统的主要用途是计算属性的值,在属性值改变时,该系统负责提供通知.
  • WPF 依赖属性系统与标准属性的主要区别是依赖属性可以通过数据绑定与其它属性相关联;同时当由于各种原因使得属性值需要发生变化时,依赖属性会自动重算。
  • 为了实现上述功能,需要为每个依赖属性维护各自的**元数据(metadata)**以及相应的处理逻辑。
  • DependencyObject 同时支持附加属性属性继承

VisualDrawingVisual
System.Windows.Media.Visual 是个抽象类,它是WPF 中所有绘图相关活动的枢纽。WPF 中,所有具有可视性质的类都直接或间接地继承自Visual 类。这个类提供了显示所需的基本服务,如渲染,缓存绘制命令,变换,裁剪,当然也包括了边框设置与命中测试(HitTest)
操作。

虽然Visual 类中包含了大量实用的功能,但我们一般不直接使用该类,而是使用其间接子类DrawingVisual.DrawingVisual 继承自ContainerVisual。ContainerVisual 用于包含可视对象的集合。集合中的子元素通过Drawing 属性(DrawingGroup 类型)设置显示内容。

DrawingVisual 是个轻量级类,仅用于低级渲染,不涉及高级内容(如布局、事件、数据绑定等).如果你的任务仅限于绘制图形,而所涉及的交互也仅限于命中测试,则你可以用DrawingVisual 完成任务,不需要使用更复杂的类,花费更多成本。

使用DrawingVisual 的典型例子是图表程序。通过绘制基础元素:如线条、贝塞尔曲线、弧、文本等,之后使用实心或渐变画刷填充其内部。你就可以建立各种图表了。

FrameworkElement
System.Windows.FrameworkElement类继承自UIElement。UIElement提供了一些核心服务,如布局事件、以及用户输入等.

虽然UIElement是公有的,但一般来说,不会从UIElement类派生,而是从FrameworkElement类派生,因为这个类提供了用户需要的服务如 布局、样式、触发器、数据绑定,同时在这个类中,可以自定义这些服务。

FrameworkElement同时是个轻量级的容器,包含可视元素集合.由于它继承自UIElement,因此它能被加到逻辑树中,作为容器包含更基础的视觉元素.

可以用如下方式使用FrameworkElement

  1. 重载其OnRender方法,在该方法内部引入简单的数据可视化呈现代码;
  2. 定义其内部的视觉树,用这种方法使用FrameworkElement时,实际是将其看成了容器;
  3. 在其中包含自定义的布局逻辑,设置包含元素的大小与位置
  4. 将上述的几种方式组合使用;
DispatcherObject,DependencyObject,Visual,UIElement 以及FrameworkElement,它们放在一起被称为脊
柱(Spine)。

通过 SectorVisual 和 VisualContainer 演示Visual类和FrameworkElement类的使用

SectorVisual
using System.Windows;
using System.Windows.Media;

namespace Demo.Visual
{
public class SectorVisual:DrawingVisual
{
public SectorVisual()
{
StreamGeometry geometry = new StreamGeometry();
using (StreamGeometryContext c = geometry.Open())
{
c.BeginFigure(new Point(200, 200), true, true);

            c.LineTo(new Point(175, 50), true, true);

            c.ArcTo(new Point(20, 150), new Size(1, 1), 0, true, SweepDirection.Counterclockwise,
                true, true);

            c.LineTo(new Point(200, 200), true, true);
        }

        using (DrawingContext context = RenderOpen())
        {
            Pen pen = new Pen(Brushes.Black, 1);
            context.DrawGeometry(Brushes.CornflowerBlue, pen, geometry);
        }
    }
}

}

VisualContainer
using System.Windows;

namespace Demo.Visual
{
public class VisualContainer:FrameworkElement
{
private readonly SectorVisual _visual = new SectorVisual();

    protected override System.Windows.Media.Visual GetVisualChild(int index)
    {
        return _visual;
    }

    protected override int VisualChildrenCount =&gt; 1;
}

}

前台 MainWindow.xaml 代码,演示了如何使用上面定义的两个类
<Window x:Class="Demo.Visual.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Demo.Visual"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <local:VisualContainer/>
</Window>

效果图:

需要指出的是,由于VisualContainer类中没有涉及任何自定义的布局,因此这个类也可以从UIElement中继承,而不需要从FrameworkElement中继承。FrameworkElement更适合于需要自定义元素大小、位置、数据绑定,以及样式的情形。

Shape 类
Shape类提供了比DrawingVisual更高级的抽象,在Shape类中,你无需使用基本的DrawingContext绘制图形;取而代之的,我们使用几何图形(geometry)这个概念确定要绘制的内容。

当建立自定义Shape时,开发者要使用Shape类中的DefiningGeometry属性定义原始形状。使用形状以及该类中的一些其它信息,如笔划样式(stroke),笔划线条粗细(Stroke Thickness),以及填充(fill),就可以决定如何对其进行渲染。

Shape类继承自FrameworkElement(FrameworkElement是大多数容器类——如Panel类——的基类),这就使得Shape类的实例可以参与布局,同时使其更容易进行事件处理。Shape类同时定义了伸缩属性(Stretch Property),用于定义在Shape对象的尺寸改变时,其内部的几何图形如何相应地变形。

Control
在视觉相关类所组成的继承关系树中,Control类已经接近树的顶端了。它提供了一个强大的Template属性(ControlTemplate类型),用于改变控件的外观与用户体验

Image
Image 类继承自FrameworkElement,因此它可以被加入到逻辑树中,同时提供了丰富的事件处理接口与布局支持。它包含Source 属性,可以设定为ImageSource 对象的实例,Image 依据这个实例进行渲染。ImageSource 类可以表示一个矢量图(DrawingImage 从ImageSource 派生,用于绘制矢量图);也可以表示一个栅格图或位图(BitmapSource 从ImageSource 派生,用于表示位图)。

当需要显示大量的数据,而显示结果与用户的交互很有限时,Image 可能会很有用。这些情况包括:要显示大批的图形,或者在网络监控程序中显示成千上万的网络结点。在这样的情况下,即使用rawingVisual 绘制复杂度都会非常高。因为采用DrawingVisual 绘制时,每个条目均是单独的可视元素,需要单独处理,因此会耗费大量的CPU 与内存资源。如果数据点根本不需要交互,那么你就可以利用图像进行显示,无需要占用计算机主要的资源。

  </div>
posted @ 2019-02-25 17:32  Laggage  阅读(862)  评论(0编辑  收藏  举报