2010-04-22 113 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。我不認爲這是爲了模糊不清。我確實聲稱它可以節省大量的代碼,像鐘錶一樣工作,並且把我的手放在管理控制,綁定以及所有事件的時候。