Повторное использование элементов и DataContext - PullRequest
2 голосов
/ 01 апреля 2012

У меня есть два класса, которые ссылаются на третий:

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>

Итак, разметкаотличается, за исключением TreeViewItem, который отображает Named класс.Я хотел бы повторно использовать разметку для этого 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>

Как видите, имя свойства Data1для Named - Xxx, а для Data2 имя свойства Named - Yyy.Итак, я должен передать это как-то на мой ресурс.Но как?

Например, как мне установить DataContext этого StaticResource поддерева на Xxx для Data1?

Что-то подобное не работает:

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

Извините за длинный вопрос.

Edit :

Все, что мне нужно, это кусок XAML, способный отображать экземпляр Named.Итак, я хочу иметь возможность указать, где взять экземпляр (из Xxx или Yyy) вне этого фрагмента, чтобы я мог использовать его повторно.

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}" />
    ...

Ответы [ 4 ]

1 голос
/ 01 апреля 2012

Вы должны изучить всю тему шаблонов.Вместо того, чтобы вручную создавать экземпляры TreeViewItem, вы должны привязать список элементов к свойству TreeView.ItemsSource, а затем указать TreeView.ItemTemplate, который является вашим повторно используемым статическим ресурсом.Если у вас смешанные типы данных, то вы можете использовать TreeView.ItemTemplateSelector для динамического выбора DataTemplate, который вы хотите

См. http://msdn.microsoft.com/en-us/library/system.windows.controls.itemscontrol.itemtemplateselector.aspx для получения дополнительной информации

0 голосов
/ 07 апреля 2012

Если вы хотите Binding s в StaticResource, используйте замораживаемый трюк Хиллберга

0 голосов
/ 07 апреля 2012

Хорошо, я вздремнул сегодня, и когда я проснулся, я вдруг понял, что ответ! Вот оно:

<!-- 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}" />
    ...
0 голосов
/ 02 апреля 2012

Согласно вашим комментариям, Торвин, вы должны использовать DataTemplate.Не только ItemsControl поддерживает шаблоны, ContentControl также имеет эту функцию.Есть свойство ContentTemplate.ContentControl также автоматически перехватывает шаблон с помощью свойства DataTemplate.DataType.

Таким образом, вы можете создать DataTemplate, представляющий именованный объект:

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

Затем вы должны установить именованный объект в качестве содержимого:

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

Вот и все!Надеюсь, я вас правильно понял в этот раз:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...