如前所述,WPF“标准”方式不能获得所需的性能。尝试了几种不同的免费和商业产品,但都没有得到我需要的结果,因此开始尝试以下方法:
- 使用WPF几何图形。
- 使用Direct2D。
两者在性能方面都不好。
我知道的一件事是,WPF很擅长渲染图像(BitmapSource),因此我决定沿着这个方向前进,并使用WriteableBitmapEx在WriteableBitmap上绘制图形,然后传递它...
WriteableBitmapEx库的一个问题是其没有像GDI那样多的绘图功能。那么为什么不直接使用GDI呢?只要正确操作,效果并无差别。
示例:
public void BeginDraw()
{
_writeable_bitmap = new WriteableBitmap((int)Math.Max(_size.Width, 1),
(int)Math.Max(_size.Height, 1), 96.0, 96.0, PixelFormats.Pbgra32, null);
_gdi_bitmap = new System.Drawing.Bitmap(_writeable_bitmap.PixelWidth,
_writeable_bitmap.PixelHeight,_writeable_bitmap.BackBufferStride,
System.Drawing.Imaging.PixelFormat.Format32bppPArgb,
_writeable_bitmap.BackBuffer);
_writeable_bitmap.Lock();
_g = System.Drawing.Graphics.FromImage(_gdi_bitmap);
_g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
_g.Clear(System.Drawing.Color.Transparent);
}
public void DrawSeries(IEnumerable<System.Drawing.PointF> points)
{
_g.DrawCurve(dataSeries.GdiPen, points.ToArray());
}
public void EndDraw()
{
_writeable_bitmap.AddDirtyRect(new Int32Rect(0, 0,
_writeable_bitmap.PixelWidth, _writeable_bitmap.PixelHeight));
_writeable_bitmap.Unlock();
var cloned = _writeable_bitmap.Clone();
cloned.Freeze();
Dispatcher.BeginInvoke(new Action((() =>
{
Image = cloned;
})));
_g.Dispose();
}
如您所见,我正在使用一种“特殊技巧”,通过GDI直接将图形绘制到本地WPF BitmapSource中。
我不确定这是否是正确的测量方法,但使用此方法,我已经成功获得了一些非常不错的结果:
- 超过10亿个数据点。
- 5FPS的刷新率。
- 每秒100次推送1万个新数据点。
- i7 Core笔记本电脑上10%的CPU。
- WPF UI和渲染线程完全可以执行其他操作。
我是开源库RealTimeGraphX(适用于WPF和UWP)的作者,它正是这样做的。
https://github.com/royben/RealTimeGraphX
除了实际的线系列之外,其余的图形组件都是使用标准的WPF控件和形状制作的,因此它们可以轻松定制和操作。