24 .net c# wpf performance 2d
我写了一张显示财务数据的图表.性能很好,而我使用和s PathGeometry一起绘制的连接线显示不到10.000点.但是现在我需要同时显示多达100.000点(没有滚动),并且已经非常慢,只有50.000点.我在考虑,但我不确定,因为它与字节流的信息基本相同.有没有人有想法让这更高效,或者有人甚至做过类似的事情?PathFigureLineSegmentStreamGeometryPathGeometry
编辑:这些数据点一旦绘制就不会改变,所以如果有潜在的优化,请告诉我(线段现在被冻结).
编辑:我试过StreamGeometry.由于某种原因,创建图形的时间更长,但这不是问题.绘制所有点后在图表上绘制仍然与前一个方法一样慢.我认为WPF处理的数据点太多了.
编辑:我已经进行了一些实验,我注意到通过将先前为double的坐标转换为int来改善性能,以防止WPF抗锯齿子像素线.
编辑:感谢所有建议减少线段数的回复.对于阶梯线,我将它们降低到最多两倍的水平分辨率,对于简单的线条,最多是水平分辨率,现在性能相当不错.
Cra*_*rks 18
我会考虑对您尝试渲染的点数进行下采样.您可能拥有50,000点数据,但您不太可能将它们全部放在屏幕上; 即使您在一个显示器中绘制每个点,您也需要100,000像素的水平分辨率来绘制它们!即使在D3D中也是如此.
由于您更有可能拥有2,048像素,因此您可以减少绘图点并绘制适合屏幕的近似曲线,并且只有几千个顶点.例如,如果用户绘制包括10000个点的时间帧,则在绘图之前将那些10000点下采样到1000.您可以尝试许多技术,从简单平均到中间邻居到高斯卷积再到(我的建议)双三次插值.绘制大于1/2屏幕分辨率的任意数量的点将是一种浪费.
当用户放大图形的一部分时,您可以重新采样以获得更高的分辨率和更准确的曲线拟合.
当您开始处理几何中数十万个不同的顶点和向量时,您应该考虑将图形代码迁移到使用图形框架而不是依赖于WPF(它建立在Direct3D之上,因此能够非常高效矢量图形渲染,有很多额外的开销正在阻碍其效率).可以在WPF中托管Direct3D和OpenGL图形渲染窗口 - 我建议移动该方向,而不是继续仅在WPF中工作.
(编辑:将"DirectX"更改为"Direct3D"的原始答案)
刚刚遇到这个问题,但正如我在此线程中提到的,最高效的方法可能是针对 WPF 的 Visual layer 进行编程。
WPF 中的所有 Visual 最终都与这一层背道而驰……因此它是所有这些方法中最轻量级的方法。
有关更多信息,请参阅此和此。Matthew MacDonald's Pro WPF in C# 2008 book 的第 14 章也有一个很好的部分。
作为另一个参考...请参阅 Pavan Podila 的书WPF Control Development Unleashed 的第 2 章。在第 13 页,他讨论了 DrawingVisuals 如何成为图表组件的绝佳选择。
最后,我刚刚注意到Charles Petzold写了一篇 MSDN 杂志文章,其中最好的整体(无论如何都是高性能的)解决方案(对于散点图)是 DrawingVisual 方法。
小智 5
另一个想法是使用Image控件,并将Source属性设置为您动态创建的DrawingImage.
根据WPF Control Development Unleashed的Pavan Podila所说,当你有成千上万的不需要任何交互性的视觉效果时,这种方法会非常有用.查看他的书的第25页了解更多信息.
这是一个旧线程,但我认为值得一提的是,您可以通过使用MouseUp()事件与上述方法实现交互.您知道图像视口的大小,图像的分辨率和鼠标的位置.例如,您可以通过附加到UserControl_SizeChanged事件的计时器来维护集合actualScreenPoints:
double xworth = viewport.ActualWidth / (XEnd - XStart);
double xworth = viewport.ActualHeight / (YEnd - YStart);
List<Point> actualScreenPoints = new List<Point>();
for (var i = 0; i < points.Count; i++)
{
double posX = points[i].X * xworth;
double posY = points[i].Y * yworth;
actualScreenPoints.Add(posX, posY);
}
Run Code Online (Sandbox Code Playgroud)
然后当您的MouseUp()事件触发时,检查集合中的任何点是否在+ -2px范围内.在给定的点上有你的MouseUp.