2013-02-11 88 views
1

我正在創建一個自定義控件,我正在嘗試爲列表框項目創建部分指定的模板。該模板具有一些預定義的部分,並且在使用該控件時應該有另一個可以模板化的部分。部分模板ListBox.ItemTemplate

爲此,我已經創建了一個名爲SuggestionItemTemplate一個依賴屬性,像這樣:

public static readonly DependencyProperty SuggestionItemTemplateProperty = 
    DependencyProperty.Register("SuggestionItemTemplate", 
     typeof(DataTemplate), 
     typeof(AutoSuggestTextBox), 
     new PropertyMetadata(null)); 

在我的自定義控件generic.xaml我:

<Style TargetType="local:AutoSuggestTextBox"> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="local:AutoSuggestTextBox"> 
       <Grid> 
        <ListBox x:Name="ItemsControl"> 
         <ListBox.ItemsPanel> 
          <ItemsPanelTemplate> 
           <StackPanel /> 
          </ItemsPanelTemplate> 
         </ListBox.ItemsPanel> 
         <ListBox.ItemTemplate> 
          <DataTemplate> 
           <Grid> 
            <Grid.ColumnDefinitions> 
             <ColumnDefinition Width="*" /> 
             <ColumnDefinition Width="Auto" /> 
            </Grid.ColumnDefinitions> 
            <ContentPresenter Grid.Column="0" 
                 ContentTemplate="{TemplateBinding SuggestionItemTemplate}" 
                 Content="{Binding}" /> 
            <ToggleButton Grid.Column="1" 
                x:Name="DetailsHover" 
                ClickMode="Hover" 
                Style="{StaticResource DetailsToggleButtonStyle}" /> 
           </Grid> 
          </DataTemplate> 
         </ListBox.ItemTemplate> 
        </ListBox> 
       </Grid> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

可惜的是,這也不行,因爲它是不可能從內嵌在DataTemplate中的ContentPresenter中使用TemplateBinding。 (會員「SuggestionItemTemplate」無法識別或無法訪問。)

我還試圖用祖先綁定(可在Silverlight 5),如:

<ContentPresenter Grid.Column="0" 
        ContentTemplate="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=local:AutoSuggestTextBox}, Path=SuggestionItemTemplate}" 
        Content="{Binding}" /> 

但這會導致綁定錯誤:

Error: System.Exception: BindingExpression_CannotFindAncestor 

我想這會發生,因爲我在我的自定義控件的ControlTemplate中,並且「local:AutoSuggestTextBox」沒有在樣式中的任何位置定義。

,我試圖將第三個方案是在OnApplyTemplate重寫應用的ContentTemplate但這也不起作用:

var cp = itemsControlElement.ItemTemplate.LoadContent() as ContentPresenter; 
cp.ContentTemplate = SuggestionItemTemplate; 

在任何情況下,我把我的網格,兩列,切換按鈕是可見的,但內容主持人簡單打印視圖模型的類型名稱。 (如果ContentTemplate爲空,我相信這是默認行爲)。

這甚至有可能嗎?是否有其他方法來指定部分模板,然後在必要時僅添加自定義模板部分?

至於現在要解決此問題,我可以指定

ItemTemplate="{TemplateBinding SuggestionItemTemplate}" 

列表框,然後複製/粘貼的通用模板,無論我用這個控制。但這是我希望首先避免的行爲。

謝謝!

編輯:我使用了所有代碼塊的代碼標籤,但由於某些原因,它們沒有突出顯示。 :/

回答

0

我設法用不同的方法解決這個問題。我使用祖先綁定,但不是試圖從DataTemplate到達根控件(我的AutoSuggestTextBox),我請求參考我的ListBox(這裏命名爲ItemsControl)。

但是,由於ListBox沒有SuggestionItemTemplate屬性,我將它分爲我自己的CustomListBox,在那裏我實現了該屬性。這一切歸結爲這段代碼片段:

<Style TargetType="local:AutoSuggestTextBox"> 
    <Setter Property="Template"> 
    <Setter.Value> 
     <ControlTemplate TargetType="local:AutoSuggestTextBox"> 
     <Grid> 
      <local:CustomizableListBox x:Name="ItemsControl" 
            SuggestionItemTemplate="{TemplateBinding SuggestionItemTemplate}"> 
      <local:CustomizableListBox.ItemTemplate> 
       <DataTemplate> 
       <Grid> 
        <Grid.ColumnDefinitions> 
        <ColumnDefinition Width="*" /> 
        <ColumnDefinition Width="Auto" /> 
        </Grid.ColumnDefinitions> 
        <ContentPresenter Grid.Column="0" 
            ContentTemplate="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=local:CustomizableListBox}, Path=SuggestionItemTemplate}" 
            Content="{Binding}" /> 
        <ToggleButton Grid.Column="1" 
           x:Name="DetailsHover" 
           ClickMode="Hover" 
           Style="{StaticResource DetailsToggleButtonStyle}" /> 
       </Grid> 
       </DataTemplate> 
      </local:CustomizableListBox.ItemTemplate> 
      </local:CustomizableListBox> 
     </Grid> 
     </ControlTemplate> 
    </Setter.Value> 
    </Setter> 
</Style> 
0

可以在OnApplyTemplate方法中遍歷Visual Ancestors,找到ContentPresenter並在其上設置ItemTemplate。在我看來,這對單個項目來說很好,但在ItemsControl場景中並不那麼多。

使用自己的自定義控件後,您可以實現自己的目標。只需給它一個Object類型的內容依賴項屬性和一個DataTemplate類型的模板DP(如果你喜歡這兩個類型的倍數),並且可以爲你的控件設置默認樣式的根視覺樣式和模板。

在這種特殊情況下,我建議最好的方法是將您的ToggleButton放入ListBoxItem模板中,而不是自定義ListBox.ItemContainerStyle。使用Expression Blend修改默認的控制模板很容易,並且ToggleButton的DataContext不會改變,所以對自己的邏輯的改變應該是最小的。

編輯:如果你的意思是使用許多不同的數據模板,也許Implicit Data Templates會更加適合。

+0

感謝您的答案!如果我正確理解你,你的建議是在ListBox.ItemContainerStyle內重新定義'ListBoxItem'的'ControlTemplate'而不是'ListBox.ItemTemplate'?如果我現在正在嘗試通過'TemplateBinding'來爲ContentPresenter提供'ContentTemplate'嗎?或者我還需要創建另一個自定義控件? – lukeguy 2013-02-12 08:49:09

+0

在這種情況下,TemplateBinding將成爲可能,但是該綁定的上下文將是ListBoxItem。在這種情況下,祖先綁定將起作用,因爲您的綁定將存在於控件模板的上下文中,而不是數據模板。 – 2013-02-12 20:33:20

+0

好的,謝謝你的幫助!我會嘗試一下,讓你知道它是怎麼回事。 – lukeguy 2013-02-13 09:46:56