原文:WPF的逻辑树与视觉树(3)Visual呈现

这篇就点到为止,挑重点讲

绘图方式有两种

1.继承UIElement,重写OnRender方法

public partial class Window5 : Window
{
public Window5()
{
InitializeComponent();
this.Content = new RectangleElement();
}
} public class RectangleElement : UIElement
{
protected override void OnRender(DrawingContext drawingContext)
{
drawingContext.DrawRectangle(Brushes.Red, null, new Rect(0, 0, 100, 20));
base.OnRender(drawingContext);
}
}

2.DrawingVisual 轻量级绘图,只提供显示和测试点击功能,DrawingVisual继承自ContainerVisual,所以其也是Visual集合容器

public class RectangleElement : UIElement
{
DrawingVisual visual;
public RectangleElement()
{
visual = new DrawingVisual();
var drawingContext = visual.RenderOpen();
drawingContext.DrawRectangle(Brushes.Red, null, new Rect(0, 0, 100, 20));
drawingContext.Close();
this.AddVisualChild(visual);
} protected override Visual GetVisualChild(int index)
{
return visual;
} protected override int VisualChildrenCount
{
get
{
return 1;
}
}
}

DrawingVisual无法单独存在,必须放在一个容器中(需要有布局系统)呈现.我们看到每次添加一个Visual的时候,总还是难免要实现GetVisualChild和VisualChildrenCount这两个成员.除了ContainerVisual这些轻量级的对象,Panel会帮我们做掉上面这些工作.但基类却变成了UIElement.事实上当添加Visual以后,同时还要计算布局的尺寸,所以有必要的话,可以对UIElement或者FrameworkElement重写以上两个成员。因为有时候我们只需要一次布局和添加多个Visual,以提升性能

重写默认窗体的视觉树

public partial class Window5 : Window
{
DrawingVisual dv;
public Window5()
{
InitializeComponent();
dv = new DrawingVisual();
} protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
var drawingContext = dv.RenderOpen();
drawingContext.DrawRectangle(Brushes.Red, null, new Rect(0, 0, this.ActualWidth, ActualHeight));
drawingContext.Close();
base.OnRenderSizeChanged(sizeInfo);
} protected override Visual GetVisualChild(int index)
{
return dv;
}
}

重写后的窗体视觉树达到了最小化
WPF的逻辑树与视觉树(3)Visual呈现-LMLPHP

上面看到并没有调用AddVisualChild方法,而视觉树的判断依据还是根据GetVisualChild和VisualChildrenCount,不过还是乖乖地加上AddVisualChild方法以免出现什么问题.

05-11 19:35