您的位置:首页 > 其它

WPF如何把东西画出来

2015-08-19 15:26 316 查看
你或许已经通过重载OnRender函数非常熟练的画出了图形。那么OnRender方法中的DrawingContext参数到底来自哪呢?

因为DrawingContext是抽象类,所以微软创建了一个叫做RenderDataDrawingContext的具体类以及它的子类VisualDrawingContext,我们所用的DrawingContext实际上就是VisualDrawingContext这个类,不过微软把他们都定义成internal,我们在程序集外部无法访问,既然无法访问,那么当我们需要多个这样的对象时如何创建呢?

DrawingVisual这个类为我们实现多个DrawingContext成为可能,因为它的实例犯法RenderOpen()在内部创建了VisualDrawingContext。DrawingVisual也可以说继承于Visual,当我们用DrawingContext的Drawing绘制一些东西的时候i,其实产生的是绘图数据,数据有了,可要把数据给UI线程才能被显示,WPF似乎使用ContextLayoutManager这个类来把UI重绘的请求发送到Dispatcher队列,用Visual里的DUCE发送消息和线程对话。

我们创建可视数据的代码可以写成这样:

DrawingVisual boardVisual = new DrawingVisual();
using(DrawingContext drawingContext=boardVisual.RenderOpen())
{
    //绘制
}


以上是创建画图的数据,那么怎么用ContextLayoutManager把数据给Dispatcher队列呢?UIElement中的ProgpagateResumeLayout方法循环递归把需要刷新的Visual对象放到队列中,经过这样的分装我们只需要把需要呈现的Visual扔给系统就可以了,系统自己会判断是否需要刷新。

怎么把Visual给系统呢?微软要求我们先给Visual的数量,这需要我们通过以下方式来给定

protected override int VisualChildrenCount
{
    return visual的数量;
}


然后系统会用一个for循环来得到需要的Visual对象

for(int I=0;i<internalVisualChildrenCount;i++)
{
    Visual visualChild = v.InternalGetVisualChild(i);
    if(visualChild!=null)
    {
        PropagateResumeLayout(v,visualChild);
    }
}


internalVisualChildrenCount的数量就是VisualChildrenCount的返回值,InternalGetVisualChild的方法实际做的就是调用我们重载的GetVisualChild()方法。

protected override Visual GetVisualChild(int index)
{
    return visual对象;
}


一个WPF应用程序从两个线程开始,分别负责用户界面(UI)的管理和渲染。托管代码为用户提供构建WPF所需要的各种功能,如布局和绑定等,通常用户界面管理线程使用该部分代码;非托管代码主要负责图形的叠加显示和渲染,那么使用该部分代码的是不能被用户接触的渲染线程,这两个线程之间通过消息来传递数据。



1.在最上层 是逻辑树,如在页面中添加一个按钮或矩形,其实质都是在逻辑树上添加一个节点。
2.WPF的托管代码部分包含一个重要的子系统,即Visual System,它是托管代码与非托管代码沟通的桥梁,其内部保存WPF程序需要显示的可视树结构。从可视树的角度来 说,其实质是添加多个Visual到可视树。
3.前两步均在用户界面线程中,添加Visual之后用户界面线程和渲染线程会通过消息传递可视化数据。
4.非托管代码部分(Milcore)又称为“媒体整合层(Media Integration Layer)”。其中包含了合成子系统(Composition System)和渲染引擎(Rendering Engine)。合成子系统接受Visual之后会将其转换为Composition节点,并添加到Composition Tree中。
5.渲染引擎将Composition Tree转换为DirectX可以识别的三角形,这个过程称为“Tesellate(三角剖分)”。
6.DirectX经过驱动(WDDM或者XPDM)通知显卡开始绘制像素到屏幕。

通过VisualChildrenCount和GetVisualChild()方法会将Visual传递给VisualSystem。

需要Composition Tree的原因如下:
1.可视树只存在用户界面线程中,如果渲染线程需要绘制WPF的用户界面,则也需要一个数据结构。这个数据结构就是Composition Tree,它存在于渲染线程中。也就是说Composition System会将Visual System传递过来的Visual Tree转换为Composition Tree。
2.渲染引擎并不知道可视树,它只知道Composition Tree,并将其转换为DirectX可以识别的三角形。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: