WPF, how can I optimize drawing lines and circles?

I am developing an application where I need to draw a graph on the screen. For this purpose I am using Canvas

and I am clicking the controls on it.

An example of such a draw as shown in the appendix can be found here: http://free0.hiboox.com/images/1610/d82e0b7cc3521071ede601d3542c7bc5.png

It works great for simple graphs, but I also want to be able to draw very large graphs (hundreds of nodes). And when I try to draw a very large graph, it takes a long time to render.

My problem is that the code is not optimized at all, I just wanted it to work. So far, I have a Canvas on one side and a few controls in the other hands. In fact, circles and strings are listed in collections, and for each item in those collections I use ControlTemplate

by defining a red circle, black circle, string, etc.

Here's an example, defining a circle of a graph:

<!--
STYLE : DISPLAY DATA NODE
-->
<Style TargetType="{x:Type flow.elements:DisplayNode}">
    <Setter Property="Canvas.Left" Value="{Binding X, RelativeSource={RelativeSource Self}}" />
    <Setter Property="Canvas.Top" Value="{Binding Y, RelativeSource={RelativeSource Self}}" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type flow.elements:DisplayNode}">

                <!--TEMPLATE-->
                <Grid x:Name="grid" Margin="-30,-30,0,0">
                    <Ellipse x:Name="selectionEllipse" StrokeThickness="0" Width="60"
                            Height="60" Opacity="0" IsHitTestVisible="False">
                        <Ellipse.Fill>
                            <RadialGradientBrush>
                                <GradientStop Color="Black" Offset="0.398" />
                                <GradientStop Offset="1" />
                            </RadialGradientBrush>
                        </Ellipse.Fill>
                    </Ellipse>
                    <Ellipse Stroke="Black" Width="30" Height="30" x:Name="ellipse">
                        <Ellipse.Fill>
                            <LinearGradientBrush EndPoint="0,1">
                                <GradientStop Offset="0" Color="White" />
                                <GradientStop Offset="1.5" Color="LightGray" />
                            </LinearGradientBrush>
                        </Ellipse.Fill>
                    </Ellipse>
                    <TextBlock x:Name="tblock"
                            Text="{Binding NodeName, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                            Foreground="Black" VerticalAlignment="Center"
                            HorizontalAlignment="Center" FontSize="10.667" />
                </Grid>

                <!--TRIGGERS-->
                <ControlTemplate.Triggers>
                    <!--DATAINPUT-->
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="SkinMode" Value="NODETYPE" />
                            <Condition Property="NodeType" Value="DATAINPUT" />
                        </MultiTrigger.Conditions>
                        <Setter TargetName="tblock" Property="Foreground" Value="White" />
                        <Setter TargetName="ellipse" Property="Fill">
                            <Setter.Value>
                                <LinearGradientBrush EndPoint="0,1">
                                    <GradientStop Offset="-0.5" Color="White" />
                                    <GradientStop Offset="1" Color="Black" />
                                </LinearGradientBrush>
                            </Setter.Value>
                        </Setter>
                    </MultiTrigger>

                    <!--DATAOUTPUT-->
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="SkinMode" Value="NODETYPE" />
                            <Condition Property="NodeType" Value="DATAOUTPUT" />
                        </MultiTrigger.Conditions>
                        <Setter TargetName="tblock" Property="Foreground" Value="White" />
                        <Setter TargetName="ellipse" Property="Fill">
                            <Setter.Value>
                                <LinearGradientBrush EndPoint="0,1">
                                    <GradientStop Offset="-0.5" Color="White" />
                                    <GradientStop Offset="1" Color="Black" />
                                </LinearGradientBrush>
                            </Setter.Value>
                        </Setter>
                    </MultiTrigger>

                    ....... THERE IS A TOTAL OF 7 MULTITRIGGERS .......

                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

      

In addition, the lines are drawn using the control Line

.

<!--
STYLE : DISPLAY LINK
-->
<Style TargetType="{x:Type flow.elements:DisplayLink}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type flow.elements:DisplayLink}">

                <!--TEMPLATE-->
                <Line X1="{Binding X1, RelativeSource={RelativeSource TemplatedParent}}"
                        X2="{Binding X2, RelativeSource={RelativeSource TemplatedParent}}"
                        Y1="{Binding Y1, RelativeSource={RelativeSource TemplatedParent}}"
                        Y2="{Binding Y2, RelativeSource={RelativeSource TemplatedParent}}"
                        Stroke="Gray" StrokeThickness="2" x:Name="line" />

                <!--TRIGGERS-->
                <ControlTemplate.Triggers>
                    <!--BRANCH : ASSERTION-->
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="SkinMode" Value="BRANCHTYPE" />
                            <Condition Property="BranchType" Value="ASSERTION" />
                        </MultiTrigger.Conditions>
                        <Setter TargetName="line" Property="Stroke" Value="#E0E0E0" />
                    </MultiTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

      

So, I need your advice. How can I significantly improve rendering performance? Do I have to define each circle rendering capability MultiTrigger

in my own ControlTemplate? Is there a better way to draw lines?

Should I open DrawingContext

and draw everything in one control instead of having hundreds of controls?

+2


a source to share


1 answer


I see this a lot and I always have the same answer. What happens when you build graphics. Don't create graphics, draw graphics. In other words, don't create a lot of data structures (many controls) on top of the application data. Rather, a Paint event handler that can draw with DrawLine, DrawEllipse, etc.

This is a specific copy of the saying. Be a witness to the data.

Only if you know that you have a requirement to be able to react to mouse contacts on drawn objects does it make sense to do some kinds of objects, and even then, perhaps not.



If rendering is causing a lot of blinking because you have so many objects that it takes a significant amount of time to render, try painting into a memory bitmap and copying it to the screen. Make sure the preprint event does not clear the screen. This is what I do and it always looks good.

Added: I understand that you cannot always avoid managing multiple controls, so I have a strategy for that. For example, I often find myself writing UI dialog boxes where the content in terms of controls dynamically changes a lot as the underlying application data changes. I find the standard, well-known ways of handling this to be crude, difficult to code, and prone to errors. Luckily, I stumbled upon what I find to be much better, dynamic dialogs . I do not pretend to be for the faint of heart. My claim is that it preserves the order of the code, runs like a clock, and takes my hands off the control of the controls, the binding and this whole hoo-haw event.

+4


a source







All Articles