WPF를 사용하여 여러 폴리 라인 (2300x1024 캔버스에서 각각 400-500 정점의 폴리 라인 64 개)을 렌더링하는 데 이상한 문제가 발생했습니다. 폴리 라인은 50ms마다 업데이트됩니다.WPF 렌더링이 너무 느립니다.
어째서 내 응용 프로그램 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());
}
}
}
내가 오프 스크린 작업 버퍼를 업데이트 한 다음이를 표시하도록 스왑()를 호출합니다. 64 개의 폴리 라인 (DoubleBufferPlot.Display)이 모두 Canvas에 자식으로 추가됩니다.
Visual Studio Concurrency Analyzer 도구를 사용하여 진행 상황을 확인하고 각 업데이트 후에 메인 스레드가 46ms에 WPF 관련 작업 (System.Windows.ContextLayoutManager.UpdateLayout() 및 System.Windows.Media)을 소비하는 것을 확인했습니다. MediaContext.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.
저는 프로젝트의 나머지 부분에서 WPF 셰이프 API를 사용하기 때문에 DrawingVisual을 피하려고 노력하고 있습니다 (또는 내 회사).
왜 이렇게 느린가요? 나는 심지어 앤티 앨리어싱 (RenderOptions.SetEdgeMode (mCanvas, EdgeMode.Aliased))을 비활성화하려고했지만 너무 도움이되지 못했습니다.
왜 레이아웃 업데이트가 오래 걸릴까요? WPF 내부 전문가가 누구입니까?
대단히 감사합니다.
반복적으로 모양을 추가하거나 제거하는 것은 빠르지 않을 것입니다. 셰이프는 캔바스의 시각적 범위를 추가하거나 제거 할 때마다 다시 계산해야한다는 점에서 WPF에 대한 컨트롤과 같습니다. –
도형을 추가하거나 제거하지 않습니다. DoubleBufferPlot.Display가 한 번 추가되고 포인트 콜렉션 (Polyline.Points) 만 업데이트됩니다. –