Есть ли способ использовать наследование шаблонов данных в WPF? - PullRequest
49 голосов
/ 14 декабря 2010

Возможно ли иметь DataTemplate композицию или наследование (аналогично "BasedOn" в стилях)? Есть 2 случая, когда мне это нужно.

  1. Для унаследованных классов: у меня есть базовый класс с несколькими унаследованными классами. Я не хочу дублировать шаблон базового класса в каждом из производных классов DataTemplate.

  2. Различные виды: для одного и того же класса я хочу определить табличку с данными, а затем добавить ее в соответствующий шаблон. Ex. базовый шаблон будет отображать данные в объекте, а затем мне нужны разные шаблоны, которые могут выполнять различные действия над объектом при отображении данных (наследуя базовый шаблон).

Ответы [ 2 ]

43 голосов
/ 14 декабря 2010

Единственное, что я нашел для такого рода вещей, это:

<DataTemplate x:Key="BaseClass">
  <!-- base class template here -->
</DataTemplate>
<DataTemplate DataType="{x:Type app:BaseClass}">
  <ContentPresenter Content="{Binding}" 
                    ContentTemplate="{StaticResource BaseClass}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type app:DerivedClass}">
  <StackPanel>
    <ContentPresenter Content="{Binding}" 
                      ContentTemplate="{StaticResource BaseClass}"/>
    <!-- derived class extra template here -->
  </StackPanel>
</DataTemplate>

По сути, это создает «общий» шаблон, на который можно ссылаться с помощью ключа (в данном случае BaseClass). Затем мы определяем реальный DataTemplate для базового класса и любых производных классов. Затем производный шаблон класса добавил бы свои собственные «вещи».

Некоторое время назад обсуждалось это на msdn , но никто не придумал лучшего решения, которое я видел.

22 голосов
/ 07 мая 2011

@ Fragilerus и @Liz, на самом деле я думаю, что придумал что-то лучшее. Вот еще один подход, который не только избегает дополнительной привязки ContentPresenter, но также устраняет необходимость применения шаблона в шаблоне, поскольку разделяемый контент - это прямой контент, который устанавливается во время компиляции. Единственное, что происходит во время выполнения, это привязки, которые вы устанавливаете в прямом контенте. Таким образом, это значительно ускоряет интерфейс по сравнению с другим решением.

<!-- Content for the template (note: not a template itself) -->
<Border x:Shared="False" 
        x:Key="Foo" 
        BorderBrush="Red" 
        BorderThickness="1" 
        CornerRadius="4">
    <TextBlock Text="{Binding SomeProp}" />
</Border>

<DataTemplate x:Key="TemplateA">
    <!-- Static resource - No binding needed -->
    <ContentPresenter Content="{StaticResource Foo}" /> 
</DataTemplate>

<DataTemplate x:Key="TemplateB">
    <!-- Static resource - No binding needed -->
    <ContentPresenter Content="{StaticResource Foo}" />
</DataTemplate>

Внимание! Обязательно используйте атрибут x:Shared в общедоступном контенте, иначе он не будет работать.

WPF'y Way

Выше было сказано, что это не самый удобный способ для WPF делать то, что вам нужно. Это может быть достигнуто с помощью класса DataTemplateSelector, который делает именно это ... выбирает шаблон данных на основе установленных вами критериев.

Например, вы можете легко настроить тот, который ищет ваши известные типы данных и возвращает один и тот же DataTemplate для них обоих, но для всех других типов он обращается к системе для разрешения DataTemplate. Вот что мы на самом деле делаем здесь.

Надеюсь, это поможет! :)

...