Reputation: 18034
I am currently developing an application that shows data items based on their timestamp on a timeline. The following screenshot gives you an idea:
(source: antiserum.ch)
The timeline contains index lines every ten milliseconds. It uses a Canvas to render the data items at the right position, and a StackPanel to display the index lines.
What you see in the sceenshot is exactly what I want to achieve. However, to display the index lines, I am currently populating a list of TimeSpan objects, incremented by 10ms each, to get the complete data set duration. That list is displayed in an ItemsControl with an items data template that draws a white line, a black box and the text.
As you can imagine, this is maybe the worst approach from a performance point of view, because the ItemsControl contains already 1000 elements for only ten seconds of data.
So my question is, how do I draw the index markers efficiently?
I already considered using a VirtualizingStackPanel to display the TimeSpan items. This is not an option, because the ScrollViewer does not contain the index list directly. It seems virtualization does not work in this case.
For clarification, here is a snippet of my xaml code (I removed templating and styling code):
<ScrollViewer x:Name="timelineScroller">
<Grid>
<ItemsControl x:Name="IndexMarkers" ItemsSource="{Binding IndexMarkers}" />
<ItemsControl x:Name="TimelineList" ItemsSource="{Binding Lines}" />
</Grid>
</ScrollViewer>
A possible solution may be to subclass the ScrollViewer and draw the index lines and text to the background of the ScrollViewer when rendering. This should be efficient, as it can only render the lines that are actually visible. However, I didn't find information on how to implement such a rendering customization.
Any ideas are appreciated.
Regards, Daniel
Upvotes: 0
Views: 494
Reputation: 18034
The approach that I finally took seems to work very well, and without any virtualization:
The list of index markers is constant, but gets RenderTransform-ed according to the current time modulo the marker width. This makes the ScrollViewer background move with the mouse, and suddenly jump back into the original position (this happens just when the value gets "wrapped around" by the modulo operation.
All that remains to be done is updating the labels of the markers at exactly that moment. This approach works so well that the jumps of the labels is not perceivable for the user.
Upvotes: 1
Reputation: 15569
It sounds like you might need to implement Virtualization explicitly.
Keep in mind that you might want to pool the markers (as in reuse the same elements where possible because creating / destroying markers might cause some serious garbage collector thrashing as it tries to clean up all of those objects.
If you used a Canvas, you could basically modify the children of the canvas in code to display the elements you want it to (specifying their coordinates).
Upvotes: 0