0

I got a List<Point> containing about 500 points. Those points are supposed to be drawn as a path. But every once in a while I need to be able to switch to a "Points only" mode that shows not a continuous line, but just the points my line is based on.

If found a simple solution using an ItemsControl which is not very performant:

<ItemsControl ItemsSource="{Binding Line}">
    <ItemsControl.ItemContainerStyle>
        <Style TargetType="FrameworkElement">
            <Setter Property="Canvas.Left" Value="{Binding X}" />
            <Setter Property="Canvas.Top" Value="{Binding Y}" />
        </Style>
    </ItemsControl.ItemContainerStyle>
    <ItemsControl.ItemTemplate>
        <DataTemplate DataType="Point">
                <Ellipse Fill="GreenYellow" Width="2" Height="2" Margin="-1,-1,1,1"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas IsItemsHost="True" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

When drawing my line using a Path-object, the performance is much better (but it's a continous path and not single dots):

<Path Data="{Binding Path=Line, Converter={StaticResource ResourceKey=PointsToPath}}"
      Stroke="GreenYellow"
      StrokeThickness="2"/>

Is there a way to achieve the same (or at least similar) performance when just drawing the points of my line? The drawn dot's don't need to be in a certain shape or size for now...

If found this question: Most performant way to graph thousands of data points with WPF?, but there they are talking about up to 100 000 points - I hope to find a simpler way, since I'm dealing with a lot less points in my case.

I need to have those points drawn interactively as smooth as possible at at least 15 FPS

Community
  • 1
  • 1
DIF
  • 2,470
  • 6
  • 35
  • 49
  • is `allowTransparency` enabled? – Sebastian L Feb 15 '17 at 08:24
  • There are far too many possibilities, especially given the lack of a [mcve] showing what you've already tried. The question you found does in fact include a number of options; you want "a simpler way", but compared to _which_ of those several answers? Some don't seem that bad to me. Other options include using `DrawingVisual`, either rendering directly into the object's context, or constructing your own `Drawing` for it. Please narrow and improve the question. – Peter Duniho Feb 15 '17 at 08:26
  • I just tried it and even if i have 50000 there is only a delay when they are loaded. Once drawn everything is smooth. If youre not loading new points every second i think you slowdown is elsewhere. – Sebastian L Feb 15 '17 at 08:43
  • @SebastianL: I need to have those points drawn interactively multiple times per second - based on mouse movement. I added that information to the question. – DIF Feb 15 '17 at 08:48
  • 1
    Try using a `Canvas` instead of an `ItemsControl` and append to `Canvas.Children` instead of binding to the `ItemsSource` of an `ItemsControl`. You will of course lose the beautiful MVVM binding wizardry, but you're looking for speed, not separation of concerns. The fastest way would be using code-behind. – Mike Eason Feb 15 '17 at 08:57
  • 1
    Too bad that the question is closed. I was about to show how a binding converter would look like that converts from `IEnumerable` into a `StreamGeometry` consisting of a set of zero-length lines. That Geometry would be visualized by a Path with `StrokeStartLineCap` and `StrokeEndLineCap` set to `Round` and thus show circles. @DIF You may perhaps just ask a new question, that explicitly ask for such a converter. – Clemens Feb 15 '17 at 09:48
  • 1
    https://gist.github.com/hrkrx/6087bc6380287d51c8ea5528b8ad1362 i achieved what you need with a canvas up to 20 FPS – Sebastian L Feb 15 '17 at 09:51
  • 1
    I can't answer your question since it is put on hold, but perhaps [this paste](http://pastebin.com/grHhhQ4c) will be of some help to you. It turns out it's an elaboration on @Clemens' suggestion. – Grx70 Feb 15 '17 at 10:23
  • Thanks for your comments despite the question being closed. I also tried a few things and build myself a converter that converts the `List` into a `GeometryGroup`. The performance is far better than using the `ItemsControl`-version, alas not as good as just drawing the line itself. – DIF Feb 15 '17 at 10:26
  • 1
    See here: http://stackoverflow.com/q/42246896/1136211 – Clemens Feb 15 '17 at 10:37
  • @Clemens: Thanks, this is exactly what I was looking for! It's a simple yet performant solution for my problem! – DIF Feb 15 '17 at 10:45

1 Answers1

1

Just out of interest try changing your Ellipse to a rectangle. At those sizes you won't see the rounded edges and a rectangle is quicker to draw. Also if the points don't move change your binding to OneTime

EDIT:

Ok now that you have added that this has to be updated at 15fps and not a one time draw I would echo the comments of Mike and would bypass binding and just have a canvas control. You would "load" the children once with all the rectangles and then using a timer loop through the children X times a seconds and change their canvas.left and canvas.top properties directly.

Kevin Ross
  • 7,185
  • 2
  • 21
  • 27
  • Changing the `Ellipse` to `Rectangle` does indeed improve the performance - but just a little. On the backside, the Ellipses do look smoother, even at that small scale. – DIF Feb 15 '17 at 08:51