WPF 使用DrawingVisual和DispatchFrame快速提升绘图速度

参考资料:

https://www.jianshu.com/p/d308641498aa

https://zhuanlan.zhihu.com/p/37167062

 

这是一个来自很久以前的代码

通过DrawingVisual和DispatchFrame快速提升绘图速度

代码里有两种,一种是组合线形成矩形,另外一种是直接生成矩形,两者不同就是是否可以精确控制某个矩形。

第一种形成的矩形会比第二多很多,也不会卡。如果某些绘图,单一颜色,效果会很好。

也可以通过变换矩形块在设置颜色也会有很多造型,或者重新编写图形。

WPF 使用DrawingVisual和DispatchFrame快速提升绘图速度

 

截图2

WPF 使用DrawingVisual和DispatchFrame快速提升绘图速度

 

最主要的是继承DrawingVisual和修改canvas。

  public class BaseCanvas : Canvas
    {
        public ObservableCollection<BaseDrawVisual> Visuals
        {
            get;
            private set;
        }
        ScaleTransform Scale;
        public BaseCanvas()
        {
            Visuals = new ObservableCollection<BaseDrawVisual>();
            Scale = new ScaleTransform();
            this.RenderTransform = Scale;
        }
        double sc = 1;
        protected override void onm ouseWheel(MouseWheelEventArgs e)
        {
           // base.OnMouseWheel(e);
           if(e.Delta>0)
            {
                sc += 0.5;
            }
            else
            {
                sc -= 0.5;
            }
            if (sc > 48)
                sc = 48;
            if (sc < 0.5)
                sc = 0.5;
            Scale.CenterX = 0;
            Scale.CenterY = 0;
            Scale.ScaleX = sc;
            Scale.ScaleY = sc;
            Console.WriteLine("sc:"+sc);
           // base.OnMouseWheel(e);
        }
        protected override Visual GetVisualChild(int index)
        {
            return Visuals[index];
        }
        protected override int VisualChildrenCount => Visuals.Count;

        public void AddVisual(BaseDrawVisual drawVisual)
        {
            Visuals.Add(drawVisual);
            AddVisualChild(drawVisual);
            AddLogicalChild(drawVisual);
        }
        public void DelAllVisual()
        {
            foreach (var item in Visuals)
            {
                RemoveVisualChild(item);
                RemoveLogicalChild(item);
            }
            Visuals.Clear();
        }


    }

 

部分元素

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;

namespace DrawCanvas
{
    public class RectByLineDrawVisual : BaseDrawVisual //也可以直接继承DrawingVisual
    {
        public RectByLineDrawVisual()
        {

        }


        public RectByLineDrawVisual(double X, double Y, double width, double height, double rectW, double rectH)
        {
            this.LocationX = X;
            this.LocationY = Y;
            this.DrawWidth = width;
            this.DrawHeight = height;
            this.RectWidth = rectW;
            this.RectHeight = rectH;

            MaxItems = (int)(DrawHeight / RectHeight * DrawWidth / RectWidth);
            SelectItem = new List<int[]>();
        }


        public double DrawHeight { get; set; }
        public double DrawWidth { get; set; }
        public double RectHeight { get; set; }
        public double RectWidth { get; set; }
        public double LocationX { get; set; }
        public double LocationY { get; set; }

        public Pen DrawPen = DrawSetting.Instance.DrawPen;

        public override void Draw()
        {
            DrawPen.Freeze();
            using (var BaseDrawing = this.RenderOpen())
            {
                GeometryGroup gp = new GeometryGroup();
                gp.Children.Add(new RectangleGeometry(new Rect(LocationX, LocationY, DrawWidth, DrawHeight)));

                for (double x = LocationX; x < LocationX + DrawWidth; x += RectWidth)
                {
                    gp.Children.Add(
                      new LineGeometry(new Point(x, LocationY), new Point(x, LocationY+DrawHeight)));
                   
                }
                for (double y = LocationY; y < LocationY + DrawHeight; y += RectHeight)
                {
                    gp.Children.Add(
                   new LineGeometry(new Point(LocationX, y), new Point(LocationX+DrawWidth, y)));
                }
                BaseDrawing.DrawDrawing(new GeometryDrawing(DrawColor, DrawPen, gp));
            }
        }
    }
}

 

主界面cs

public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();


        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            //   Draw();

            e.Handled = true;
        }
        Random GetRandom = new Random();
        int k = 0;
        private void Draw()
        {
            draw.DelAllVisual();
            for (double i = 0; i < draw.ActualWidth; i +=100)
            {
                for (double j = 0; j < draw.ActualHeight; j += 100)
                {
                    //NormColor=new SolidColorBrush(Color.FromRgb((byte)GetRandom.Next(1,255), (byte)GetRandom.Next(1, 255), (byte)GetRandom.Next(1, 255))) 
                    //draw.AddVisual(new RectByLineDrawVisual(i, j, 80, draw.ActualHeight, 5, 5));
                    draw.AddVisual(new RectDrawVisual(i, j, 100, 100, 4, 4));
                }
            }
        }

        private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            // Draw();

        }
        private void ProcessMsgs()
        {

            DoEvents();
        }
        public void DoEvents()
        {
            DispatcherFrame frame = new DispatcherFrame();
            Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
                new DispatcherOperationCallback(ExitFrames), frame);
            Dispatcher.PushFrame(frame);
        }

        public object ExitFrames(object f)
        {
            ((DispatcherFrame)f).Continue = false;

            return null;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Draw();
            for (int i = 0; i < draw.Visuals.Count; i++)
            {

                draw.Visuals[i].Draw();
                if (i % 10 == 0)
                    ProcessMsgs();
            }
            //   this.IsEnabled = true;
        }
        DispatcherTimer Timer = new DispatcherTimer();
        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            if (Timer.IsEnabled)
            {
                Timer.Stop();
                return;
            }
            Timer.Interval = TimeSpan.FromMilliseconds(50);
            Timer.Tick += Timer_Tick;
            Timer.Start();

        }

        private void Timer_Tick(object sender, EventArgs e)
        {
          Changed1();
            //Changed2();
        }
        void Changed1()
        {
            for (int i = 0; i < draw.Visuals.Count;)
            {
                var index = GetRandom.Next(0, draw.Visuals.Count);

                var item = draw.Visuals[index] as RectDrawVisual;
                //  item.SelectItem.Clear();
                var k = new[] { GetRandom.Next(0, 20), GetRandom.Next(0, 20) };
                if (!item.SelectItem.Contains(k))
                    item.SelectItem.Add(k);
                else
                    item.SelectItem.Remove(k);
                item.SelectItemBackGround = new SolidColorBrush(Colors.Red);//new SolidColorBrush(Color.FromRgb((byte)GetRandom.Next(1, 255), (byte)GetRandom.Next(1, 255), (byte)GetRandom.Next(1, 255)));
                item.Draw();
                ProcessMsgs();
                Console.WriteLine(index);
                if (i == draw.Visuals.Count - 1)
                {
                    i = 0;
                    ProcessMsgs();
                    continue;

                }
                else
                    i++;
            }
        }
        void Changed2()
        {
            var index = GetRandom.Next(0, draw.Visuals.Count - 1);
            var item = draw.Visuals[index];
            item.DrawColor = new SolidColorBrush(Color.FromRgb((byte)GetRandom.Next(1, 255), (byte)GetRandom.Next(1, 255), (byte)GetRandom.Next(1, 255)));
            item.Draw();
           // ProcessMsgs();
        }
    }

 

 

下载代码

上一篇:WPF 性能优化-高刷新绘图


下一篇:PAT 甲级 1155  Heap Paths