1

我正在创建一个自定义控件,并且正在尝试为列表框项创建部分指定的模板。模板有一些预定义的部分,并且应该有另一个部分可以在使用控件时进行模板化。

为此,我创建了一个名为 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}"

对于列表框,然后在我使用此控件的任何地方复制/粘贴通用模板。但这是我希望首先避免的行为。

谢谢!

编辑:我对所有代码块都使用了代码标签,但由于某种原因它们没有突出显示。:/

4

2 回答 2

0

可以在 OnApplyTemplate 方法中遍历 Visual Ancestors,找到您的 ContentPresenter(s) 并在其上设置 ItemTemplate。在我看来,这对于单个项目来说很好,但在 ItemsControl 场景中则不然。

使用自己的自定义控件后,您可以实现自己的目标。只需给它一个 Object 类型的 Content 依赖属性和一个 DataTemplate 类型的 Template DP(如果你愿意,可以为两者的倍数),你可以为你的 Control 设置默认样式的根视觉样式和模板。

在这种特定情况下,我建议最好的方法是将您的 ToggleButton 放在 ListBoxItem 模板中,而不是通过自定义 ListBox.ItemContainerStyle。使用 Expression Blend 很容易修改默认的 Control Template,并且 ToggleButton 的 DataContext 不会改变,因此对您自己的逻辑的更改应该是最小的。

编辑:如果您打算使用许多不同的数据模板,也许隐式数据模板会更合适。

于 2013-02-11T19:05:14.833 回答
0

我设法使用不同的方法解决了这个问题。我使用了祖先绑定,但我没有尝试从 访问根控件(my AutoSuggestTextBoxDataTemplate,而是要求引用 my 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>
于 2013-02-14T14:47:50.980 回答