ControlTemplate с DataTrigger Vs. DataTemplate с DataTemplateSelector

У меня есть общий элемент управления, который отображает редактор на основе свойства типа внутри ViewModel. В настоящее время это реализовано с использованием Control, ControlTemplate и DataTrigger вот так:

<Control
   x:Name="MainControl"
   Grid.Column="1"
   TargetUpdated="OnTargetUpdated">
        <Control.Style>
            <Style>
                <Style.Triggers>
                    <DataTrigger
                        Binding="{Binding Path=EditorType}"
                        Value="{x:Static view:EditorType.Bool}">
                        <Setter
                            Property="Control.Template"
                            Value="{StaticResource boolTemplate}" />
                    </DataTrigger>
                    <DataTrigger
                        Binding="{Binding Path=EditorType}"
                        Value="{x:Static view:EditorType.Text}">
                        <Setter
                            Property="Control.Template"
                            Value="{StaticResource textTemplate}" />
                    </DataTrigger>
                    <DataTrigger
                        Binding="{Binding Path=EditorType}"
                        Value="{x:Static view:EditorType.Integer}">
                        <Setter
                            Property="Control.Template"
                            Value="{StaticResource integerTemplate}" />
                    </DataTrigger>
                    ...
                    ....
                </Style.Triggers>
            </Style>
     </Control.Style>
</Control>

Теперь того же можно добиться, используя ContentPresenter, DataTemplate и DataTemplateSelector вот так:

<local:EditorTemplateSelector
    BoolEditorTemplate="{StaticResource boolTemplate}"
    TextEditorTemplate="{StaticResource textTemplate}"
    IntegerEditorTemplate="{StaticResource integerTemplate}"
    ...
    ....
    x:Key="EditorTemplateSelector">
</local:EditorTemplateSelector>

<ContentPresenter
    ContentTemplateSelector="{Binding Source={StaticResource EditorTemplateSelector}}"
    Content="{Binding}"
    TargetUpdated="OnTargetUpdated">
</ContentPresenter>

// Template selector returning appropriate template based on type

Я чувствую, что второй подход лучше использовать DataTemplateSelector, но хотел бы узнать от вас -

  • Какой из них лучше и почему?

  • Будет ли разница в производительности между двумя?


person akjoshi    schedule 19.01.2012    source источник
comment
Из того, что я понимаю, второй способ считается лучшей практикой. Кроме того, он гораздо более удобочитаем, поскольку не поддерживает логику выбора (которая всегда должна быть определена в C#). Однако меня также интересует производительность.   -  person Louis Kottmann    schedule 19.01.2012


Ответы (4)


Я слышал, что DataTemplateSelectors не обновляют шаблон, если значение, на котором они основаны, меняется, и из-за этого я обычно ими не пользуюсь.

Мой предпочтительный метод — использовать DataTemplates.

<MyControl.Resources>
    <DataTemplate TargetType="{x:Type local:BooleanModel}">
        <local:BooleanView />
    </DataTemplate>
    <DataTemplate TargetType="{x:Type local:IntegerModel}">
        <local:IntegerView />
    </DataTemplate>
    ...
</MyControl.Resources>

Во-вторых, если я хочу изменить шаблон на основе свойства, а не типа объекта, я обычно использую DataTriggers. Это связано с тем, что если это свойство когда-либо будет изменено, уведомление PropertyChange автоматически сообщит пользовательскому интерфейсу, что оно было изменено, и обновит шаблон. Я не верю, что DataTemplateSelectors делает это автоматически. Я также предпочитаю видеть логику выбора шаблона в моем XAML, а не скрывать ее в файле TemplateSelector, но это просто личное предпочтение.

И мой последний выбор — использовать DataTemplateSelector. Я почти никогда не использую его в приложении WPF, хотя часто делаю это в Silverlight, поскольку он не поддерживает мой предпочтительный метод использования неявного DataTemplates (пока)

Я не знаю о каких-либо существенных различиях в производительности между ними, хотя мне было бы интересно, если бы кто-нибудь сказал мне иначе.

person Rachel    schedule 19.01.2012
comment
Интересно, я почти уверен, что вопрос был о WPF, просто из любопытства - исправили ли они неявные шаблоны в SL4/5, поскольку я знаю, что они не были доступны в предыдущих версиях. - person ; 19.01.2012
comment
@Dmitry Я полагаю, что последний проект Silverlight, который я делал, был в 4.0, и тогда неявные шаблоны данных не работали. Я слышал, что они работают в 5.0, но пока нет. - person Rachel; 19.01.2012
comment
+1 за «DataTemplateSelectors не обновляют шаблон, если значение, которое они основаны на chan». Я проверил это, и шаблон не обновляется при изменении значения. Благодарю. - person akjoshi; 20.01.2012
comment
Это не всегда так. Если у вас есть ContentPresenter с Content={Binding Path=SomeProp}, тогда, если SomeProp изменится, ContentPresenter снова запросит у TemplateSelector шаблон. Однако, если SomeProp НЕ изменится, но изменится свойство этого объекта, вы больше не получите вызов селектора шаблонов. - person MikeKulls; 06.07.2012
comment
Вот пример селектора шаблонов данных от @Rachel change-data-template-dynamically - person huoxudong125; 15.10.2014

У вас тут два вопроса :)

  1. Где принять решение в XAML(DataTriggers) или в коде TemplateSelector
  2. Что вы переопределяете весь Style или только DataTemplate. В вашем первом примере вы переопределяете Style, во втором - DataTemplate.

Вот мои 2с:

Я бы остановился на триггерах, так как с ними вы получите непревзойденный уровень гибкости — новый редактор по цене нового ресурса и триггер на XAML — что может быть лучше? Есть одно потенциальное предостережение, связанное с использованием DataTrigger — это может привести к утечке данных.

Говоря о выборе Style против DataTemplate, я снова остановился на Style. Это может быть немного тяжелее визуального дерева, но это даст вам полный контроль над внешним видом ваших редакторов.

В частности, некоторые свойства могут быть определены только на уровне Style с использованием Style Setters. Определение тогда уровня @DataTemplate просто не будет работать, так как ваш контент DataTemplate не является непосредственным дочерним элементом вашего контейнера управления (есть дополнительный уровень - Actula Control). Если у вас нет таких свойств, ControlTemplates тоже хороши и, вероятно, быстрее (?).

person Community    schedule 19.01.2012
comment
Спасибо, Дмитрий. Не могли бы вы предоставить более подробную информацию о «DataTrigger, вызывающем утечку данных»? - person akjoshi; 20.01.2012
comment
@akjoshi - Извините, я не смогу придумать точное воспроизведение, это скорее наблюдение, я видел несколько проектов, которые значительно выигрывают после уменьшения количества триггеров. - person ; 20.01.2012

Я также не являюсь поклонником DataTemplateSelector, но я думаю, вы могли бы использовать их, если оценка вашего селектора состоит из не только проверки типов, например. if x>5 && dayOfWeek==Tue && isFullMoon(today) затем шаблон1.

person EricG    schedule 09.01.2019
comment
Да, если требуется сложная логика, полезен DataTemplateSelector; хотя некоторые случаи все еще могут быть достигнуты с помощью MultiDataTrigger. - person akjoshi; 11.01.2019

Я бы предложил ответить на один из вопросов, считаете ли вы, что control необходим. Вы получаете целую кучу функций с control, которые на самом деле недоступны с DataTemplate. Вы можете добавить DependencyProperties, events, functions и т. д. и т. д. Но вам это нужно? Если вы этого не сделаете, то контроль может быть излишним.

person MikeKulls    schedule 06.07.2012