Reputation: 41
I create my own FrameworkElement and override VisualChildrenCount{get;} and GetVisualChild(int index) by returning my own DrawingVisual collection instance.I have override OnRender .
I will add 20-50 DrawingVisuals in this FrameworkElement ,every DrawingVisual will have 2000 line segments.The logic value of these points between 0 to 60000.when I zoom into 1:1 the FrameworkElement 's Height will be 60000, the rending time will be 15 minutes!!
How do I improve the rending performance ?
Upvotes: 4
Views: 4036
Reputation: 41
I need use hittesting to highlight every visual . If I display them using a single DrawingVisual , I think that it maybe not to be done.
For this kind of data volume, I would suggest you build a GeometryDrawing and StreamGeometry containing a single PolyLine for each of your points. Then combine them all together in a single DrawingGroup and display it using a single DrawingVisual.
This would be the XAML:
<DrawingVisual Drawing="{Binding CurrentDrawing}" />
and this would be the code to update CurrentDrawing:
var group = new DrawingGroup();
foreach(var data in myData)
{
StreamGeometry geo = new StreamGeometry();
using(geoContext = geo.Open())
{
geoContext.BeginFigure(myData.StartPoint, false, false);
geoContext.PolyLineTo(myData.AdditionalPoints, true, false);
}
group.Add(new GeometryDrawing
{
Geometry = geo,
Pen = myData.Pen,
});
}
CurrentDrawing = group;
...
If your data is changing it may be advantageous to create store each GeometryDrawing object separately so it is only necessary to recreate those GeometryDrawings whose source data has changed
Upvotes: 0
Reputation: 62919
For this kind of data volume, I would suggest you build a GeometryDrawing and StreamGeometry containing a single PolyLine for each of your points. Then combine them all together in a single DrawingGroup and display it using a single DrawingVisual.
This would be the XAML:
<DrawingVisual Drawing="{Binding CurrentDrawing}" />
and this would be the code to update CurrentDrawing:
var group = new DrawingGroup();
foreach(var data in myData)
{
StreamGeometry geo = new StreamGeometry();
using(geoContext = geo.Open())
{
geoContext.BeginFigure(myData.StartPoint, false, false);
geoContext.PolyLineTo(myData.AdditionalPoints, true, false);
}
group.Add(new GeometryDrawing
{
Geometry = geo,
Pen = myData.Pen,
});
}
CurrentDrawing = group;
...
If your data is changing it may be advantageous to create store each GeometryDrawing object separately so it is only necessary to recreate those GeometryDrawings whose source data has changed.
Update
You mention in your comment that you need to separately hittest each of the 20-50 data items. In that case, you probably do want to use a separate DrawingVisual
for each. For maximum performance you will want to use RenderOpen()
with DrawingContext
:
IEnumerable<Visual> BuildVisuals()
{
return
from var data in myData
select BuildVisualForData(data);
}
void BuildVisualForData(MyDataType data)
{
var geo = new StreamGeometry();
using(geoContext = geo.Open())
{
geoContext.BeginFigure(myData.StartPoint, false, false);
geoContext.PolyLineTo(myData.AdditionalPoints, true, false);
}
var visual = new DrawingVisual();
using(drawingContext = visual.RenderOpen())
{
drawingContext.DrawGeometry(null, myData.Pen, geo);
}
return visual;
}
Upvotes: 4