2011-11-29 30 views
1

應用:改變從代碼的ControlTemplate背後

你好,我是動態地添加自定義控件WPF應用程序。該控件是一個自定義滑塊。我在XAML文件中創建了一個ControlTemplate,我想用它作爲這些動態創建控件的模板。我目前使用應用模板:

newControl.Template = (ControlTemplate)parent.Resources["nameOfTheControlTemplate"]; 

目前這個工程確定(即編譯,運行和applys模板)。

模板看起來是這樣的:(對不起,文字的牆)

<ControlTemplate x:Key="errorRangeSliderRight" TargetType="{x:Type Slider}"> 
<Border SnapsToDevicePixels="true" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto"/> 
      <RowDefinition Height="Auto" MinHeight="{TemplateBinding MinHeight}"/> 
      <RowDefinition Height="Auto"/> 
     </Grid.RowDefinitions> 
     <Track x:Name="PART_Track" Grid.Row="1"> 
      <Track.Thumb> 
       <Thumb x:Name="Thumb" HorizontalContentAlignment="Right" Width="7"> 
        <Thumb.Template> 
         <ControlTemplate TargetType="Thumb"> 
          <Path x:Name="nameOfPath" Stroke="Black" StrokeThickness="0" Fill="Red"> 
           <Path.Data> 
            <GeometryGroup FillRule="NonZero"> 
             <PathGeometry> 
              <PathGeometry.Figures> 
               <PathFigure IsClosed="True" StartPoint="7,150"> 
                <PathFigure.Segments> 
                 <PathSegmentCollection> 
                  <LineSegment Point="5,150" /> 
                  <LineSegment Point="5,0" /> 
                  <LineSegment Point="7,0" /> 
                 </PathSegmentCollection> 
                </PathFigure.Segments> 
               </PathFigure> 
               <PathFigure IsClosed="True" StartPoint="0,75"> 
                <PathFigure.Segments> 
                 <PathSegmentCollection> 
                  <LineSegment Point="7,70" /> 
                  <LineSegment Point="7,80" /> 
                  <LineSegment Point="0,75" /> 
                 </PathSegmentCollection> 
                </PathFigure.Segments> 
               </PathFigure> 
              </PathGeometry.Figures> 
             </PathGeometry> 
            </GeometryGroup> 
           </Path.Data> 
          </Path> 
         </ControlTemplate> 
        </Thumb.Template> 
       </Thumb> 
      </Track.Thumb> 
     </Track> 
    </Grid> 
</Border> 
</ControlTemplate> 

推理:

我爲什麼選擇來定義XAML控件模板,而不是動態創建的原因使用FrameworkElementFactory的數百萬行代碼的模板是因爲它更簡單,更清潔,更易於維護/讀取。

我想要什麼:

我想使控件模板內的輕微改動此對照模板(僅Path對象的填充顏色)。如果可能,我想獲得對ControlTemplate對象的引用。

我曾嘗試:

我試圖調用該模板的FindName(「nameOfPath」),它返回一個空對象。

Object o = newControl.Template.FindName("nameOfPath",newControl); 

我曾嘗試創建使用大量FrameworkElementFactory實例和構建的ControlTemplate這樣的ContentTemlpate,這是不成功的(該控件模板對象是相當複雜的,有許多子元素)。

+0

+1只是爲了具有這樣的精心佈置的問題 – mydogisbox

回答

2

我會強烈鼓勵以這種方式在運行時的模板(或者更確切地說,從模板實例化控件)篡改,它是壞的設計。

你想要做的是使用屬性。例如將Path.Fill綁定到Foreground?如果你認爲這在語義上不夠合適,你最好從Slider繼承並創建你需要的屬性,而不是在運行時搞亂模板。

在你的情況下,你有嵌套的模板,所以你必須轉發TemplateBinding或做一些與RelativeSource綁定,這取決於你。例如使用轉發:

<!-- ... --> 
<Thumb x:Name="Thumb" HorizontalContentAlignment="Right" Width="7" 
      Background="{TemplateBinding Foreground}"> 
     <Thumb.Template> 
      <ControlTemplate TargetType="Thumb"> 
       <Path x:Name="nameOfPath" Stroke="Black" StrokeThickness="0" 
         Fill="{TemplateBinding Background}"> 

此結合Path.FillThumb.Background(它是),並且Thumb.Background勢必這似乎合理以及所述Slider.Foreground。現在你只需要在Slider上設置Foreground來設置路徑的Fill,不錯吧?


順便說一句:你應該保留你想要的抽象概念。

我想略作改動此控件模板...

這其實不是你想要的,但需要您認爲結果得到你想要的東西。你把你真的想要什麼到括號:「[改動] Path對象的填充顏色」

+0

謝謝。你的解決方案'感覺'更清潔。 – user989056

+0

哦,它*更清潔,真的:) –

1

您可能不想在代碼隱藏中更改您的模板,因爲這會改變使用該模板的每個控件。

相反,一旦你的控件已經被渲染,你可以瀏覽它的可視化樹來找到需要修改的特定元素並進行修改。在所有Render事件得到處理後,Loaded事件纔會運行,因此您應該能夠在任何Loaded事件期間調整控件模板中的控件。

我寫了一套VisualTreeHelpers,我經常用它來查找WPF的可視化樹中的控件。它們可以像這樣使用:

Path path = VisualTreeHelpers.FindChild<Path>(newControl, "nameOfPath"); 
+0

你好,我曾嘗試沒有成功您的建議。當我調用'VisualTreeHelper.GetChildrenCount(parent);'它返回0.我甚至嘗試過用ControlTemplate傳遞一個非動​​態創建的控制對象,並且它仍然返回一個0的子計數。 – user989056

+0

@ user989056您的控件是否呈現?如果您在代碼隱藏中創建了控件,那麼您可能需要爲其添加一個'Loaded'事件來完成更改,然後將控件添加到您的UI中以便渲染。完成渲染後,Loaded事件應該會觸發,VisualTreeHelper將能夠找到它的子項。 – Rachel

+0

好的電話,謝謝。 – user989056