• 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重叠起来。





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





  • 相关阅读:
    【bzoj1616】[Usaco2008 Mar]Cow Travelling游荡的奶牛 bfs
    【bzoj1614】[Usaco2007 Jan]Telephone Lines架设电话线 二分+SPFA
    【bzoj1609】[Usaco2008 Feb]Eating Together麻烦的聚餐 dp
    【codevs1404】字符串匹配 KMP
    【bzoj4196】[Noi2015]软件包管理器 树链剖分+线段树
    【codevs3160】最长公共子串 后缀数组
    【bzoj4698】[Sdoi2008] Sandy的卡片 后缀数组
    【bzoj4278】[ONTAK2015]Tasowanie 贪心+后缀数组
    【bzoj1692】[Usaco2007 Dec]队列变换 贪心+后缀数组
    【bzoj1717】[Usaco2006 Dec]Milk Patterns 产奶的模式 后缀数组+离散化
  • 原文地址:https://www.cnblogs.com/kevinWu7/p/10163554.html
Copyright © 2020-2023  润新知