重用元素和DataContext

本文关键字:DataContext 元素 | 更新日期: 2023-09-27 18:29:36

我有两个类,它们引用第三个:

class Data1
{
   public Named Xxx { get; set; }
   public SomeClass1 Foo { get; set; }
   ...
}
class Data2
{
   public Named Yyy { get; set; }
   public SomeClass2 Bar { get; set; }
   ...
}
class Named
{
   public string Name { get; set; }
   ...
}

现在,我想显示Data1&Data2:

<TreeView DataContext={Binding Path=Data1}>
  <TreeView.Items>
    <TreeViewItem>
      <TreeViewItem.Header>
        <StackPanel Orientation="Horizontal">
          <ContentControl xml:space="preserve">Name: </ContentControl>
          <ContentControl Content="{Binding Path=Xxx.Name}" />
        </StackPanel>
      </TreeViewItem.Header>
    </TreeViewItem>
    <TreeViewItem><!-- somehow display Foo --></TreeViewItem>
    <!-- More TreeViewItems, specific to Data1 -->
  </TreeView.Items>
</TreeView>
<TreeView DataContext={Binding Path=Data2}>
  <TreeView.Items>
    <TreeViewItem>
      <TreeViewItem.Header>
        <StackPanel Orientation="Horizontal">
          <ContentControl xml:space="preserve">Name: </ContentControl>
          <ContentControl Content="{Binding Path=Yyy.Name}" />
        </StackPanel>
      </TreeViewItem.Header>
    </TreeViewItem>
    <TreeViewItem><!-- somehow display Bar --></TreeViewItem>
    <!-- More TreeViewItems, specific to Data2 -->
  </TreeView.Items>
</TreeView>

因此,除了显示Named类的TreeViewItem之外,标记是不同的。我想为这个TreeViewItem重用标记。制作UserControl太简单了,但它仍然比示例中显示的要复杂一些。所以,我真的很想做这样的事情:

<ResourceDictionary>
  <TreeViewItem x:Key="Named">
    <TreeViewItem.Header>
      <StackPanel Orientation="Horizontal">
        <ContentControl xml:space="preserve">Name: </ContentControl>
        <ContentControl Content="{Binding Path=Name}" />
      </StackPanel>
    </TreeViewItem.Header>
  </TreeViewItem>
</ResourceDictionary>

然后像这样使用:

<TreeView DataContext={Binding Path=Data1}>
  <TreeView.Items>
    <StaticResource ResourceKey="Named" />
  </TreeView.Items>
</TreeView>

如您所见,Data1Named的属性名称为Xxx,而Data2Named的属性名称则为Yyy。所以,我必须以某种方式将其传递给我的资源。但是怎么做呢?

例如,如何将此StaticResource子树的DataContext设置为Data1Xxx

这样的东西不起作用:

    <StaticResource ResourceKey="Named" DataContext={Binding Path=Xxx} />

很抱歉问题太长。

编辑

我只想要一个XAML,能够显示一个Named实例。因此,我希望能够指定在哪里获取该片段外部的实例(来自XxxYyy),这样我就可以重用它。

Edit2:这是ControlTemplate的解决方案,但效果不佳:TreeViewItem变得不可选择。怎么了?

<ControlTemplate x:Key="Named" TargetType="TreeViewItem">
    <TreeViewItem>
        <TreeViewItem.Header>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="Name: " />
                <TextBlock Text="{Binding Path=Name}" />
            </StackPanel>
        </TreeViewItem.Header>
    </TreeViewItem>
</ControlTemplate>
<!-- now use the template: -->
<TreeView>
  <TreeView.Items>
    <TreeViewItem Template="{StaticResource Named}" 
                  DataContext="{Binding Path=Xxx}" />
    ...

重用元素和DataContext

您应该了解整个模板主题。与其手动创建TreeViewItem的实例,不如将项目列表绑定到TreeView.ItemsSource属性,然后指定一个TreeView.ItemTemplate,它是可重用的静态资源。如果您有混合数据类型,那么您可以使用TreeView.ItemTemplateSelector动态选择您想要的 DataTemplate

请参阅http://msdn.microsoft.com/en-us/library/system.windows.controls.itemscontrol.itemtemplateselector.aspx有关更多信息,

根据您的评论,torvin,您应该使用DataTemplate。ItemsControl不仅支持模板化,ContentControl也具有此功能。存在ContentTemplate属性。ContentControl还通过使用DataTemplate.DataType属性自动挂接模板。

因此,您可以创建表示命名对象的DataTemplate:

<...Resources>
    <DataTemplate DataType="{x:Type local:Named}">
        <TextBlock Text="{Binding Name}"/>
    </DataTemplate>
</...Resources>

然后您应该将Named对象设置为Content:

<TreeViewItem.Header>
    <StackPanel Orientation="Horizontal">
        <ContentControl xml:space="preserve">Name: </ContentControl>
        <ContentControl Content="{Binding Path=Xxx}" />
    </StackPanel>
</TreeViewItem.Header>

仅此而已!我希望这次能正确理解你:)

如果您想要StaticResource中的Binding s,请使用Hillberg的可冻结技巧

好吧,我今天睡了个午觉,当我醒来时,我突然意识到答案是什么!这是:

<!-- In resources: -->
<Style TargetType="TreeViewItem" x:Key="Named">
  <Setter Property="Header" Value="{Binding Name}" />
  <Setter Property="HeaderTemplate">
    <Setter.Value>
      <DataTemplate>
        <StackPanel Orientation="Horizontal">
          <TextBlock Text="Name: " />
          <TextBlock Text="{Binding}" />
        </StackPanel>
      </DataTemplate>
    </Setter.Value>
  </Setter>
</Style>
<!-- now use the template: -->
<TreeView>
  <TreeView.Items>
    <TreeViewItem Style="{StaticResource Named}" 
                  DataContext="{Binding Path=Xxx}" />
    ...