【问题标题】:Improve drawingvisual render's speed提高绘图视觉渲染的速度
【发布时间】:2009-11-18 11:59:43
【问题描述】:

我创建自己的 FrameworkElement 并通过返回我自己的 DrawingVisual 集合实例来覆盖 VisualChildrenCount{get;} 和 GetVisualChild(int index)。我已经覆盖了 OnRender。

我将在这个 FrameworkElement 中添加 20-50 个 DrawingVisual,每个 DrawingVisual 将有 2000 个线段。这些点的逻辑值在 0 到 60000 之间。当我放大 1:1 时,FrameworkElement 的高度将为 60000,播放时间为 15 分钟!!

如何提高渲染性能?

【问题讨论】:

    标签: wpf performance


    【解决方案1】:

    对于这种数据量,我建议您为每个点构建一个包含单个折线的 GeometryDrawing 和 StreamGeometry。然后将它们全部组合在一个 DrawingGroup 中,并使用单个 DrawingVisual 显示它。

    这将是 XAML:

    <DrawingVisual Drawing="{Binding CurrentDrawing}" />
    

    这将是更新 CurrentDrawing 的代码:

    var group = new DrawingGroup();
    foreach(var data in myData)
    {
      StreamGeometry geo = new StreamGeometry();
      using(geoContext = geo.Open())
      {
        geoContext.BeginFigure(myData.StartPoint, false, false);
        geoContext.PolyLineTo(myData.AdditionalPoints, true, false);
      }
      group.Add(new GeometryDrawing
      {
        Geometry = geo,
        Pen = myData.Pen,
      });
    }
    CurrentDrawing = group;
    ...
    

    如果您的数据正在发生变化,最好分别创建存储每个 GeometryDrawing 对象,因此只需重新创建源数据已更改的那些 GeometryDrawings。

    更新

    您在评论中提到您需要分别对 20-50 个数据项中的每一个进行命中测试。在这种情况下,您可能确实想为每个使用单独的DrawingVisual。为了获得最佳性能,您需要将RenderOpen()DrawingContext 一起使用:

    IEnumerable<Visual> BuildVisuals()
    {
      return
        from var data in myData
        select BuildVisualForData(data);
    }
    
    void BuildVisualForData(MyDataType data)
    {
      var geo = new StreamGeometry();
      using(geoContext = geo.Open())
      {
        geoContext.BeginFigure(myData.StartPoint, false, false);
        geoContext.PolyLineTo(myData.AdditionalPoints, true, false);
      }
    
      var visual = new DrawingVisual();
      using(drawingContext = visual.RenderOpen())
      {
        drawingContext.DrawGeometry(null, myData.Pen, geo);
      }
      return visual;
    }
    

    【讨论】:

    • 嗨,Ray 感谢您的回答,我会尽快尝试。
    • 我需要使用 hittesting 来突出显示每个视觉对象。如果我使用单个 DrawingVisual 显示它们,我认为它可能不会完成。
    • 在这种情况下,将每个数据项放在自己的 DrawingVisual 中,并使用 RenderOpen() 和 DrawingContext。我已经编辑了我的答案以展示如何做到这一点。
    • 你的更新看起来像我现有的代码。它的性能很差。
    • @mackenir 你完全错了,StreamGeometry 比 Shapes 对象更高效的原因有很多。
    【解决方案2】:

    我需要使用 hittesting 来突出显示每个视觉对象。如果我使用单个 DrawingVisual 显示它们,我认为可能不会这样做。

    对于这种数据量,我建议您为每个点构建一个包含单个折线的 GeometryDrawing 和 StreamGeometry。然后将它们全部组合在一个 DrawingGroup 中,并使用单个 DrawingVisual 显示它。

    这将是 XAML:

    <DrawingVisual Drawing="{Binding CurrentDrawing}" />
    

    这将是更新 CurrentDrawing 的代码:

    var group = new DrawingGroup();
    foreach(var data in myData)
    {
      StreamGeometry geo = new StreamGeometry();
      using(geoContext = geo.Open())
      {
        geoContext.BeginFigure(myData.StartPoint, false, false);
        geoContext.PolyLineTo(myData.AdditionalPoints, true, false);
      }
      group.Add(new GeometryDrawing
      {
        Geometry = geo,
        Pen = myData.Pen,
      });
    }
    CurrentDrawing = group;
    ...
    

    如果您的数据正在发生变化,最好分别创建存储每个 GeometryDrawing 对象,因此只需重新创建源数据已更改的那些 GeometryDrawings

    【讨论】:

      猜你喜欢
      • 2016-11-17
      • 1970-01-01
      • 2011-08-12
      • 2011-07-21
      • 1970-01-01
      • 2012-06-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多