I'm trying to implement a chart that can handle real time data, which comes in every 1 ms. I poll for 50ms of data so that I'm not trying to redraw the screen every single ms. I am using a PathGeometry on a Canvas to add line segments. I always see the framerate steadily tick downwards, as the redraws grow slower and slower. I did not think that a Line with roughly 10,000 points would be so difficult for m开发者_运维技巧y computer to render. Is there something I'm doing wrong? Or is there some other design philosophy that may be more adept at handling real time data in WPF?
In the ViewModel I have:
public PointCollection LinePoints;
In the View I listen to this collection being changed and add line segments:
_viewModel.LinePoints.Changed += LinePoints_Changed;
void LinePoints_Changed(object sender, System.EventArgs e)
{
while (_viewModel.LinePoints.Count - 1 > pathFigure.Segments.Count)
{
// pathFigure is part of the PathGeometry on my canvas
pathFigure.Segments.Add(new LineSegment(_viewModel.LinePoints[pathFigure.Segments.Count], true));
}
}
For simulation purposes I am injecting points using a BackgroundWorker:
void addPointsWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bw = sender as BackgroundWorker;
DateTime startTime = DateTime.Now;
int numPointsAdded = 0;
while (!bw.CancellationPending && (DateTime.Now - startTime).Seconds < 10)
{
List<Point> points = new List<Point>();
for (int i = 0; i < 50; i++)
{
Math.Sin(numPointsAdded++/(500*Math.PI))));
}
System.Threading.Thread.Sleep(50);
bw.ReportProgress(0, points);
}
}
public void addPointsWorker_ProgressChanged(List<Point> pointsToAdd)
{
foreach(Point point in pointsToAdd)
{
// triggers CollectionChanged which will add the line segments
ViewModel.LinePoints.Add(point);
}
}
Along with slowdown I also experience UI unresponsiveness. I figured it's because I'm making too many ReportProgress calls and filling up the message pump, but if I could resolve the slow rendering I think this other issue would go away as well. I am open to any suggestions!
I have two suggestions:
- Make sure your collection only contains the points that will be rendered to the screen. An easy way to do this would be to use a queue and remove from the front as more points are added. I doubt that all 10,000 points need to be rendered at once.
- If this is still not getting you the performance you need, you may want to use a lower-level drawing mechanism. StreamGeometry would be the first thing to try. After that, WriteableBitmap would provide the best performance possible in WPF.
After a bit of time tweaking things, I've found that Charlie's is the best solution. I also discovered that instead of using a LineSegment every time a point is added, using a PolyLineSegment with the 50 or so points of data I'm already queuing up does wonders for performance.
However, it doesn't delay the inevitable slowdown that occurs. But using a combination of PolyLineSegment with only the last several hundred or even thousand points has given me the best performance while showing the most amount of data possible.
精彩评论