我正在开发一个应用程序,我需要在屏幕上绘制图形。
为此,我使用Canvas
并将控件放在上面。
可在此处找到应用程序中显示的此类绘图示例: http://free0.hiboox.com/images/1610/d82e0b7cc3521071ede601d3542c7bc5.png
它适用于简单的图形,但我也希望能够绘制非常大的图形(数百个节点)。当我尝试绘制一个非常大的图形时,渲染需要很多时间。
我的问题是代码根本没有优化,我只是想让它起作用。到现在为止,我一方面有Canvas,另一方面有多个控件。实际上,圆圈和线条列在集合中,对于这些集合中的每个项目,我使用ControlTemplate
,定义红色圆圈,黑色圆圈,线条等。
这是一个例子,图圈的定义:
<!--
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>
此外,使用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>
所以,我需要你的建议。如何大幅提升渲染性能?我应该在自己的ControlTemplate中定义每个MultiTrigger
圆圈渲染的可能性吗?是否有更好的画线技术?
我应该打开DrawingContext
并在一个控件中绘制所有内容,而不是拥有数百个控件吗?
答案 0 :(得分:4)
我看到了很多,我总是有同样的答案。当你构建图形时会发生这种情况。不要构建图形,绘制图形。换句话说,不要在应用程序数据之上创建大量数据结构(许多控件)。相反,有一个 Paint 事件处理程序,可以通过 DrawLine , DrawEllipse 等绘制。
这是格言是数据持有者的特定实例。
只有当你知道你需要能够对绘制的对象上的鼠标接触做出响应时,制作某些类型的对象才有意义,即使这样,也可能没有。
如果渲染导致大量闪烁,因为你有太多的对象需要花费相当长的时间来渲染它们,请尝试绘制到内存位图,然后将其复制到屏幕上。确保预绘制事件不会清除屏幕。这就是我的工作,它看起来总是很好。
补充:我意识到你不能总是避免管理很多控件,所以我有一个策略。例如,我经常不得不编写UI对话框,其中控件方面的内容会随着底层应用程序数据的变化而动态变化。处理这个标准的众所周知的方法我发现粗糙,难以编码,并且容易出错。幸运的是,我偶然发现了我认为更好的方式,dynamic dialogs。我并不认为这是为了胆小的人。我声称它可以保存一个数量级的代码,像时钟一样工作,并且完成管理控制,绑定和所有事件的工作。