【发布时间】:2014-11-12 20:45:15
【问题描述】:
我在尝试使用 WPF 渲染多条折线时遇到了一个奇怪的问题(64 条折线,每个折线在 2300x1024 画布上大约 400-500 个顶点)。折线每 50 毫秒更新一次。
由于某种原因,我的应用程序 UI 变得非常缓慢,几乎对用户输入没有响应。
我正在使用以下类以避免在显示点集合时更新它:
class DoubleBufferPlot
{
/// <summary>
/// Double-buffered point collection
/// </summary>
private readonly PointCollection[] mLineBuffer =
{
new PointCollection(),
new PointCollection()
};
private int mWorkingBuffer; //index of the workign buffer (buffer being modified)
#region Properties
//Polyline displayed
public Polyline Display { get; private set; }
/// <summary>
/// index operator to access points
/// </summary>
/// <param name="aIndex">index</param>
/// <returns>Point at aIndex</returns>
public Point this[int aIndex]
{
get { return mLineBuffer[mWorkingBuffer][aIndex]; }
set { mLineBuffer[mWorkingBuffer][aIndex] = value; }
}
/// <summary>
/// Number of points in the working buffer
/// </summary>
public int WorkingPointCount
{
get { return mLineBuffer[mWorkingBuffer].Count; }
set
{
SetCollectionSize(mLineBuffer[mWorkingBuffer], value);
}
}
#endregion
public DoubleBufferPlot(int numPoints = 0)
{
Display = new Polyline {Points = mLineBuffer[1]};
if (numPoints > 0)
{
SetCollectionSize(mLineBuffer[0], numPoints);
SetCollectionSize(mLineBuffer[1], numPoints);
}
}
/// <summary>
/// Swap working and display buffer
/// </summary>
public void Swap()
{
Display.Points = mLineBuffer[mWorkingBuffer]; //display workign buffer
mWorkingBuffer = (mWorkingBuffer + 1) & 1; //swap
//adjust buffer size if needed
if (Display.Points.Count != mLineBuffer[mWorkingBuffer].Count)
{
SetCollectionSize(mLineBuffer[mWorkingBuffer], Display.Points.Count);
}
}
private static void SetCollectionSize(IList<Point> collection, int newSize)
{
while (collection.Count > newSize)
{
collection.RemoveAt(collection.Count - 1);
}
while (collection.Count < newSize)
{
collection.Add(new Point());
}
}
}
我在屏幕外更新工作缓冲区,然后调用 Swap() 使其显示。所有 64 条折线 (DoubleBufferPlot.Display) 作为子项添加到 Canvas。
我使用 Visual Studio 并发分析器工具查看发生了什么,发现每次更新后主线程花费 46 毫秒执行一些与 WPF 相关的任务:System.Widnows.ContextLayoutManager.UpdateLayout() 和 System.Windows.Media.MediaContex 。使成为()。
我还发现有另一个线程在运行几乎不间断的渲染 wpfgfx_v0400.dll!CPartitionThread::ThreadMain ... wpfgfx_v0400.dll!CDrawingContext::Render ... 等等
我阅读了许多关于 WPF 的文章,其中包括:Can WPF render a line path with 300,000 points on it in a performance-sensitive environment? 还有这篇文章http://msdn.microsoft.com/en-us/magazine/dd483292.aspx。
我(或者我的公司)试图避免使用 DrawingVisual,因为项目的其余部分使用 WPF 形状 API。
知道为什么这么慢吗?我什至尝试禁用抗锯齿 (RenderOptions.SetEdgeMode(mCanvas, EdgeMode.Aliased)),但没有太大帮助。
为什么布局更新需要这么长时间。有谁是 WPF 内部的专家?
非常感谢。
【问题讨论】:
-
反复添加和删除形状不会很快。形状类似于 WPF 的控件,因为无论何时添加或删除画布,都需要重新计算画布的视觉范围。
-
我不添加和删除形状。 DoubleBufferPlot.Display 添加一次,我只更新点集合(Polyline.Points)。
标签: wpf