2013-02-11 86 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