2010-04-22 114 views
2

我正在开发一个应用程序,我需要在屏幕上绘制图形。 为此,我使用了一个Canvas,并且我在其上放置了控件。WPF,我如何优化线条和圆圈的绘制?

如在应用中显示这样一个平局的例子可以在这里找到: http://free0.hiboox.com/images/1610/d82e0b7cc3521071ede601d3542c7bc5.png

它工作正常进行简单的图形,但我也希望能够吸引非常大图(几百个节点) 。当我尝试绘制一个非常大的图形时,需要很多时间来渲染。

我的问题是,代码没有被优化,我只是想让它工作。直到现在,我一方面拥有帆布,另一方面拥有多个控件。实际上,圈子和线条被列在集合中,并且对于这些集合中的每个项目,我使用定义红色圆圈,黑色圆圈,线条等的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并在一个控件中绘制所有内容,而不是拥有数百个控件?

回答

4

我看到很多,我总是有同样的答案。这就是当你构建图形时发生的情况。不要构建图形,绘制图形。换句话说,不要在应用程序数据之上创建大量的数据结构(大量的控件)。相反,有涂料事件处理程序,可以借助于油漆的DrawLineDrawEllipse

的这是格言的特定实例是数据仇敌

只有当你知道你有一个能够响应鼠标在绘制对象上的接触的需求时,做出某种对象才是有意义的,甚至可能不是。

如果渲染导致大量闪烁,因为您有太多的对象需要显着的时间来渲染它们,请尝试绘制到内存位图并将其复制到屏幕。确保预绘事件不会清除屏幕。这就是我所做的,而且总是看起来不错。

补充:我知道你不能总是避免管理很多控件,所以我有一个策略。例如,我经常需要编写UI对话框,其中根据控件的内容随着底层应用程序数据的变化而动态地改变。处理这个标准的众所周知的方法,我发现原油,难以编码,并容易出错。幸运的是,我偶然发现了我认为更好的方法,dynamic dialogs。我不认为这是为了模糊不清。我确实声称它可以节省大量的代码,像钟表一样工作,并且把我的手放在管理控制,绑定以及所有事件的时候。