WPF开发之2D绘图
WPF绘图的工具可以用到路径Path、Geometry对象、可视化对象DrawingVisual,这三种的量级从高到低,刚开始接触2D绘图的时候一开始接触的是路径Path,后来发现如果需要渲染大量的图形的时候,Path的效率可能会不太好,而通过可视化对象绘图是非常轻量级的,每一个Path是作为一个一元素在WPF中渲染的,而可视化元素可以数千个封装到单个元素里面进行渲染,就像我们用手提包装钱,Path就像人民币,虽然也能装不少,但是不如银行卡,存的是巨款,而可视化对象就是银行卡里面的数据,这是个人对于这两种绘图工具的理解,下面说一下可视化对象
1.绘制可视化对象(DrawingVisual)
为使用DrawingVisual类绘制内容,需要调用DrawVisual.RenderOpen()方法,以下代码演示了绘制直线、矩形、圆的简单功能
DrawingVisual visual = new DrawingVisual();
using (DrawingContext dc = visual.RenderOpen())
{
//定义一只绘制的画笔,颜色为黑色,厚度为0.5
Pen pen = new Pen(Brushes.Black, 0.5);
//1.绘制直线坐标(100,100)到(200,100)
dc.DrawLine(pen,new Point(100, 100), new Point(200, 100));
//2.绘制一个矩形,先定义一个矩形实例,起点坐标为(100,200),长宽分别为100
Rect rect = new Rect(100, 200, 100, 100);
//将实例用画笔绘制出来,填充黄色
dc.DrawRectangle(Brushes.Yellow, pen, rect);
//绘制一个圆,圆心(400,200),半径为50,填充黄色
dc.DrawEllipse(Brushes.Yellow, pen, new Point(400, 200), 50, 50);
}
2.在元素中封装可视化对象
在这里我们需要定义一个继承至UIElement类的子类用于驻留我们的可视化对象,这里我们直接继承至Canvas,需要做的是为可视化对象注册AddVisualChild()和AddLogicalChild(),以及重写VisualChildrenCount属性和重写GetVisualChild()方法,代码如下
public class VisualHost:Canvas
{
private List<Visual> visuals = new List<Visual>();
//获取Visual的个数
protected override int VisualChildrenCount
{
get { return visuals.Count; }
}
//获取Visual
protected override Visual GetVisualChild(int index)
{
return visuals[index];
}
//添加Visual
public void AddVisual(Visual visual)
{
visuals.Add(visual);
base.AddVisualChild(visual);
base.AddLogicalChild(visual);
}
//删除Visual
public void RemoveVisual(Visual visual)
{
visuals.Remove(visual);
base.RemoveVisualChild(visual);
base.RemoveLogicalChild(visual);
}
//命中测试
public DrawingVisual GetVisual(Point point)
{
HitTestResult hitResult = VisualTreeHelper.HitTest(this, point);
return hitResult.VisualHit as DrawingVisual;
}
}
有的时候我想要能够既能够渲染可视化对象,也可以在Canvas中放置例如Button等元素控件,遗憾的是,当我们重写了上面提到的属性和方法之后,Canvas的其他元素将不被渲染,只会看到添加的可视化对象,对此我们可以将上述封装了许多可视化对象的VisualHost实例添加到Canvas画板中,即将VisualHost实例添加到Canvas的Children中,然后再将其他控件元素添加到Canvas中,这样可视化对象和其他元素控件都能够被渲染,看下面代码
后台代码:
public partial class MainWindow : Window
{
private VisualHost host;
public MainWindow()
{
InitializeComponent();
host = new VisualHost();
canvas.Children.Add(host);
Draw();
}
public void Draw()
{
DrawingVisual visual = new DrawingVisual();
using (DrawingContext dc = visual.RenderOpen())
{
//定义一只绘制的画笔,颜色为黑色,厚度为0.5
Pen pen = new Pen(Brushes.Black, 0.5);
//1.绘制直线坐标(100,100)到(200,100)
dc.DrawLine(pen,new Point(100, 100), new Point(200, 100));
//2.绘制一个矩形,先定义一个矩形实例,起点坐标为(100,200),长宽分别为100
Rect rect = new Rect(100, 200, 100, 100);
//将实例用画笔绘制出来
dc.DrawRectangle(Brushes.Yellow, pen, rect);
//绘制一个圆,圆心(400,200),半径为50
dc.DrawEllipse(Brushes.Yellow, pen, new Point(400, 200), 50, 50);
}
host.AddVisual(visual);
}
}
前台代码:
<Window x:Class="Test.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:Test"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Canvas x:Name="canvas">
<Button Content="Button" Canvas.Left="375" Canvas.Top="43" Width="75"/>
</Canvas>
</Grid>
</Window>
渲染结果: