Я испытываю странную проблему, пытаясь использовать WPF для рендеринга ряда полилиний (64 полилинии около 400-500 вершин в каждом на холсте 2300x1024). Полилинии обновляются каждые 50 мс.WPF-рендеринг слишком медленный
По какой-то причине мой пользовательский интерфейс приложения становится очень вялым и почти не отвечает на ввод пользователя.
Я использую в следующий класс, чтобы избежать обновления коллекции точек во время отображения:
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());
}
}
}
Я обновляю рабочий буфер закадровый, а затем вызвать своп(), чтобы он показывался. Все 64 полилинии (DoubleBufferPlot.Display) добавляются в Canvas как дети.
Я использовал средство анализа Concurrency Analyzer Visual Studio, чтобы узнать, что происходит, и обнаружил, что после каждого обновления основной поток тратит 46 мс на выполнение некоторых связанных с WPF задач: System.Widnows.ContextLayoutManager.UpdateLayout() и System.Windows.Media. MediaContex.Render().
Я также обнаружил, что есть еще одна нить, которая работает почти нон-стоп рендеринга wpfgfx_v0400.dll! CPartitionThread :: ThreadMain ... wpfgfx_v0400.dll! CDrawingContext :: Рендер ... и т.д.
Я прочитал ряд статей по 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, так как в остальной части проекта используется API форм WPF.
Любая идея, почему это так медленно? Я даже попытался отключить сглаживание (RenderOptions.SetEdgeMode (mCanvas, EdgeMode.Aliased)), но это не очень помогло.
Почему обновление макета занимает так много времени. Кто-нибудь, кто является экспертом в составе WPF?
спасибо.
Повторное добавление и удаление фигур не будет быстрым. Формы похожи на элементы управления в WPF в том смысле, что визуальная протяженность холста должна быть пересчитана всякий раз, когда вы добавляете или удаляете ее. –
Я не добавляю и не удаляю фигуры. DoubleBufferPlot.Display добавляется один раз, и я только обновляю коллекцию точек (Polyline.Points). –