WPF DrawingVisual详解

在WPF中,如果需要绘制大量图形元素,并且对性能要求严苛的话,最好使用DrawingVisual,当然,你也可以选用

Path类和比Path类更轻量级的Geometry(几何形状)来实现你的需求,但是开销会比DrawingVisual来的大。


DrawingVisual继承自ContainerVisual,该类有一个RenderOpen方法,返回一个可用于定义可视化内容的DrawingContext对象,绘制完毕后需要调用DrawingContext.Close()方法来结束绘图。


DrawingContext中有各种绘图的方法,包括DrawLine,DrawRectangle,DrawText等等,今天我们举一个较复杂的例子DrawGeometry().


在此之前,我们需要做一些准备工作:参考自<WPF编程宝典>第三部分--图画和动画--330页

1.为元素调用AddVisualChild()和AddLogicalChild()方法来注册可视化元素

2.重写VisualChildrenCount属性和重写GetVisualChild()方法,本质上是劫持了那个元素,如果使用一些能包含控件的例如Panel,Window,则这些panel,window中除了DrawingVisual,其他的控件将不再可见。


代码如下:


 public partial class MainWindow : Window
    {
        private DrawingVisual _drawingVisual = new DrawingVisual();
        public MainWindow()
        {
            InitializeComponent();
            this.AddVisualChild(_drawingVisual);
            var dc = _drawingVisual.RenderOpen();
            PathFigure pthFigure = new PathFigure();
            pthFigure.IsClosed = false;   //是否封闭
            pthFigure.IsFilled = false;   //是否填充
            pthFigure.StartPoint = new Point(10, 100);

            System.Windows.Point Point1 = new System.Windows.Point(10, 100);
            System.Windows.Point Point2 = new System.Windows.Point(100, 200);
            System.Windows.Point Point3 = new System.Windows.Point(200, 30);
            System.Windows.Point Point4 = new System.Windows.Point(250, 200);
            System.Windows.Point Point5 = new System.Windows.Point(200, 150);

            PolyLineSegment plineSeg = new PolyLineSegment();
            plineSeg.Points.Add(Point1);
            plineSeg.Points.Add(Point2);
            plineSeg.Points.Add(Point3);
            plineSeg.Points.Add(Point4);
            plineSeg.Points.Add(Point5);

            PathSegmentCollection myPathSegmentCollection = new PathSegmentCollection();
            myPathSegmentCollection.Add(plineSeg);

            pthFigure.Segments = myPathSegmentCollection;

            PathFigureCollection pthFigureCollection = new PathFigureCollection();

            pthFigureCollection.Add(pthFigure);

            PathGeometry pthGeometry = new PathGeometry();

            pthGeometry.Figures = pthFigureCollection;


            dc.DrawGeometry(Brushes.White, new Pen(Brushes.White,1), pthGeometry);
           
            dc.Close();
        }
        //必须重载这两个方法,不然是画不出来的
        // 重载自己的VisualTree的孩子的个数,由于只有一个DrawingVisual,返回1
        protected override int VisualChildrenCount
        {
            get { return 1; }
        }

        // 重载当WPF框架向自己要孩子的时候,返回返回DrawingVisual
        protected override Visual GetVisualChild(int index)
        {
            if (index == 0)
                return _drawingVisual;

            throw new IndexOutOfRangeException();
        }
    }


WPF还为DrawingVisual提供了可以命中测试,用以实现点击,拖拽等功能,主要是依靠方法VisualTreeHelper.HitTest,

我尝试着用了下,这个方法比较消耗性能,而且只适合那种面积较大的按钮,方块,一点就中的情况,如果是一条线或者一个小点,则很难点击命中。我会建议使用Path,自带了各种鼠标事件。这个在WPF编程宝典中有详解,不再赘述!


如果既需要大量的图形,又需要能支持鼠标事件的控件,我建议的做法是,在Grid中放置Panel用于绘制DrawingVisual,然后在放置Canvas来内置各种控件。Panel和Canvas重叠起来。





未完待续。。。。。。。。





posted @ 2016-09-19 11:23  birdhumen鸟人  阅读(3287)  评论(1编辑  收藏  举报