WPF异步高效绘制过万级别的矩形图形矢量图,无限放大缩小,显示效果极佳

发布时间:2024年01月18日

WPF异步高效绘制过万级别的矩形图形矢量图,无限放大缩小,显示效果极佳,先看效果如下:
在这里插入图片描述
在这里插入图片描述
想在WPF上绘制图形,有哪些方式?

1.通过Canvas静态绘图方法,例如:

<Canvas>
    <Ellipse Width="50" Height="50" Fill="Blue" Canvas.Left="10" Canvas.Top="10"/>
    <Rectangle Width="80" Height="40" Fill="Red" Canvas.Left="50" Canvas.Top="50"/>
</Canvas>

2.DrawingContext进行绘图,例如:

protected override void OnRender(DrawingContext drawingContext)
{
    base.OnRender(drawingContext);

    // 创建一个画刷和画笔
    SolidColorBrush brush = new SolidColorBrush(Colors.Green);
    Pen pen = new Pen(Brushes.Black, 2);

    // 绘制一个矩形
    drawingContext.DrawRectangle(brush, pen, new Rect(10, 10, 100, 50));
}

3.使用DrawingVisual进行低级别的绘图

DrawingVisual是一个轻量级的可视化对象,允许你在低级别上执行绘图。通过重写OnRender方法,你可以使用DrawingContext在DrawingVisual上进行绘图。

例如:

protected override void OnRender(DrawingContext drawingContext)
{
    base.OnRender(drawingContext);

    using (DrawingContext dc = drawingContext.RenderOpen())
    {
        // 在DrawingVisual上进行绘图
        dc.DrawEllipse(Brushes.Blue, new Pen(Brushes.Black, 2), new Point(50, 50), 30, 30);
    }
}

4.使用graphics绘制Image流可以直接绑定到界面

但是如果要考率绘制大批量图形,我们就要性能和内存等多个方面考虑了,否则绘制1w的矩形需要1分钟,哪个客户也接受不了啊。

我们考虑这些方面:

  • 1.使用UI 虚拟化控件: 如果你有过万级别的矩形,不要一次性全部绘制。考虑采用虚拟化的方式,只在当前视图区域内绘制可见的矩形。这可以通过一些控件如VirtualizingStackPanel或者自定义的虚拟化机制来实现。
  • 2.使用独立的绘制线程: 考虑在一个独立的绘制线程中进行绘制操作,以避免对UI主线程的影响。这样可以更好地控制绘制操作的调度和频率。
  • 3.多线程异步绘制 将绘制操作异步化,可以避免UI主线程阻塞。使用Task或async/await模式来在后台线程进行绘制操作,然后在UI线程更新视图。
  • 4.自定义UIElement: 如果使用WPF,可以考虑创建自定义的UIElement,通过重写OnRender方法实现高效的绘制。确保只在需要更新时进行绘制。
  • 5.可以使用Freezable类来冻结Pen对象,这个对提高性能有非常明显的对比,最后我在这里做个测评

实现过程:

XAML代码

<Window x:Class="WpfAppTest.shiliangTest"
        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:WpfAppTest" PreviewMouseWheel="Window_PreviewMouseWheel"
        mc:Ignorable="d"
        Title="shiliangTest" Height="800" Width="1000">
    <Grid>
        <Canvas x:Name="DrawingContainer" Width="800" Height="800" Panel.ZIndex="1" />

    </Grid>
</Window>

后台代码:

   public class VisualHost1 : FrameworkElement
   {
       private readonly DrawingVisual _drawingVisual;

       public VisualHost1()
       {
           _drawingVisual = new DrawingVisual();
       }

       public DrawingContext RenderOpen()
       {
           return _drawingVisual.RenderOpen();
       }

       protected override void OnRender(DrawingContext drawingContext)
       {
           base.OnRender(drawingContext);
           drawingContext.DrawDrawing(_drawingVisual.Drawing);
       }
   }
  public VisualHost1 _visualHost;
  double scale;
  public shiliangTest()
  {
      InitializeComponent();

      _visualHost = new VisualHost1();
      DrawingContainer.Children.Add(_visualHost);

      double canvasWidth = DrawingContainer.Width;
      double canvasHeight = DrawingContainer.Height;
      //double canvasWidth = 3000;
      //double canvasHeight = 3000;
      new SelectBoxRect(DrawingContainer);

      using (new PerformanceCounter("ghfgh"))
      {
          DrawRectangles1(canvasWidth, canvasHeight);
      }
      scale = 1;
  }

private void Window_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
        {

            if (Keyboard.IsKeyDown(Key.LeftCtrl))
            {
                if (e.Delta < 0)
                {
                    scale -= 0.01;
                }
                else
                {
                    scale += 0.01;
                }
                // scale += (double)e.Delta / 35000;
                ScaleTransform transfrom = new ScaleTransform();
                transfrom.ScaleX = transfrom.ScaleY = scale;
                this.DrawingContainer.RenderTransform = transfrom;
            }
}  

  private Pen CreateAndFreezePen()
  {
      // 创建Pen
      Pen pen = new Pen(Brushes.Black, 1);

      // 冻结Pen
      if (pen.CanFreeze)
      {
          pen.Freeze();
      }

      return pen;
  }

  private void DrawRectangles1(double canvasWidth, double canvasHeight)
  {
      int rows = 100; // 纵向矩形数量
      int columns = 100; // 横向矩形数量


      using (DrawingContext drawingContext = _visualHost.RenderOpen())
      {

          double rectangleWidth = canvasWidth / columns;
          double rectangleHeight = canvasHeight / rows;

          var pen = CreateAndFreezePen();
          for (int i = 0; i < columns; i++)
          {
              for (int j = 0; j < rows; j++)
              {
                  double x = i * rectangleWidth;
                  double y = j * rectangleHeight;

                  // 创建矩形几何图形
                  Rect rectangleRect = new Rect(new Point(x, y), new Size(rectangleWidth, rectangleHeight));
                  Geometry rectangleGeometry = new RectangleGeometry(rectangleRect);

                  // 绘制矩形
                  //drawingContext.DrawGeometry(Brushes.Blue, new Pen(Brushes.Black, 1), rectangleGeometry);
                  drawingContext.DrawGeometry(Brushes.Blue, pen, rectangleGeometry);

              }
          }
      }
  }
        

对比是否冻结Pen的结果

这是未冻结的耗时
在这里插入图片描述

这是冻结后的耗时
在这里插入图片描述

文章来源:https://blog.csdn.net/zuiyuewentian/article/details/135657989
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。