MultiDataTrigger против DataTrigger с мультипривязкой

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

С MultiDataTrigger:

<MultiDataTrigger>
    <MultiDataTrigger.Conditions>
        <Condition Binding="{Binding Path=SomePath}" Value="SomeValue"/>
        <Condition Binding="{Binding Path=SomeOtherPath, Converter={StaticResource SomeConverter}}" Value="SomeOtherValue"/>
    </MultiDataTrigger.Conditions>
    <MultiDataTrigger.EnterActions>
        <BeginStoryboard Storyboard="{StaticResource MyStoryboard}"/>
    </MultiDataTrigger.EnterActions>
</MultiDataTrigger>

С MultiBinding:

<DataTrigger Value="foo">
    <DataTrigger.Binding>
        <MultiBinding Converter="{StaticResource fooConv}"/>
            <Binding Path=SomePath/>
            <Binding Path=SomeOtherPath/>
        </MultiBinding>
    </DataTrigger.Binding>
    <DataTrigger.EnterActions>
        <BeginStoryboard Storyboard="{StaticResource MyStoryboard}"/>
    </DataTrigger.EnterActions>
</DataTrigger>

person mcwyrm    schedule 08.01.2014    source источник
comment
Использование MultiDataTrigger обычно избавляет вас от конвертера с несколькими значениями. См. этот вопрос, опубликованный сегодня.   -  person Clemens    schedule 08.01.2014
comment
Если бы один подход требовал значительно больше усилий, чем другой, это учитывалось бы в моих расчетах. В этом случае любой подход будет включать использование преобразователя - на самом деле у меня есть соответствующие преобразователи, и мне не нужно их писать, но если бы я этого не сделал, это все равно не сделало бы один подход (в данном случае) более привлекательным, чем Другой.   -  person mcwyrm    schedule 08.01.2014
comment
Для обоих ваших примеров требуется конвертер, поэтому, если вы еще не реализовали их, я бы выбрал решение MultiDataTrigger, поскольку SomeConverter, скорее всего, будет использоваться где-то еще, а fooConv, скорее всего, не будет использоваться в других местах.   -  person Novitchi S    schedule 08.01.2014
comment
Похоже, это формирующийся консенсус. Мультиконвертер, который я использую, просто делает && для своих значений, и я использую его довольно часто, хотя я смутно задаюсь вопросом, не упускаю ли я какой-то более простой подход.   -  person mcwyrm    schedule 08.01.2014


Ответы (2)


Multibinding требуется преобразователь для всех случаев, кроме самых редких (используя StringFormat).

MultiTrigger требуется только конвертер для преобразования результатов привязки в booleans.

person Gusdor    schedule 08.01.2014
comment
Если оставить в стороне усилия, которые могут быть потрачены на написание конвертера, есть ли какая-то особая причина избегать его использования? - person mcwyrm; 08.01.2014
comment
Только усилие. Я нахожу это мощным мотиватором :D - person Gusdor; 08.01.2014

Я хотел бы уточнить немного больше.

Для меня MultiBinding и MultiDataTrigger принципиально разные, и хотя в некоторых ситуациях вы можете использовать оба для достижения одной и той же функциональности, это похоже на хак, чтобы заставить оба работать одинаково.

MultiDataTriggers следует использовать, когда вам нужно выполнить более одного условия отдельно, чтобы вы могли выполнить действие (установить значение свойства, начать анимацию и т. д.). Например, вам нужно, чтобы A было истинным, а B — ложным. Оба эти условия сами по себе могут интерпретироваться по отдельности. Это случай этого вопроса.

MultiBindings, с другой стороны, следует использовать, когда вам нужно более одного параметра для расчета одного выхода по вашему выбору. Этот вывод должен иметь некоторое значение для установки свойства. Например, вы измените значение свойства, только если A равно B. Это имеет смысл, когда вы используете один и тот же стиль для нескольких элементов управления, и A является свойством элемента управления (скажем, свойство Text TextBlock), а B является одним свойством из модели представления с именем SelectedText. Таким образом, проблема, которую мы можем попытаться решить, заключается в следующем: среди всех TextBlocks в моем представлении установите передний план одного с тем же текстом, что и свойство SelectedText из моей модели представления, чтобы мигать (анимация изменения цвета).

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

Я оставлю XAML для примера, где я буду использовать DataTrigger с MultiBinding, о которых я упоминал выше: (я предполагаю, что вы используете шаблон MVVM)

<Style TargetType="{x:Type TextBlock}" x:Key="SelectedTextStyle">
    <Setter Property="FontFamily" Value="Segoe UI Light"/>
    <Setter Property="FontSize" Value="24"/>
    <Setter Property="HorizontalAlignment" Value="Left"/>
    <Style.Triggers>
        <DataTrigger Value="True">
            <DataTrigger.Binding>
               <MultiBinding Converter="{StaticResource StringsToBooleanConverter}">
                    <Binding Path="SelectedText"/> <!--This is a property of the View Model-->
                    <Binding RelativeSource="{RelativeSource Self}" Path="Text"/> <!--This is the Dependency Property 'Text' of the TextBlock control-->
                </MultiBinding>
            </DataTrigger.Binding>
            <DataTrigger.EnterActions>
                <BeginStoryboard>
                    <Storyboard>
                        <ColorAnimation Storyboard.TargetProperty="Foreground.Color" Duration="0:0:2" From="Black" To="DarkOrange" AutoReverse="True" FillBehavior="HoldEnd" RepeatBehavior="Forever"/>
                    </Storyboard>
                </BeginStoryboard>
            </DataTrigger.EnterActions>
            <DataTrigger.ExitActions>
                <BeginStoryboard>
                    <Storyboard>
                        <ColorAnimation Storyboard.TargetProperty="Foreground.Color" Duration="0:0:0" From="DarkOrange" To="Black" FillBehavior="HoldEnd"/>
                    </Storyboard>
                </BeginStoryboard>
            </DataTrigger.ExitActions>
        </DataTrigger>
    </Style.Triggers>
</Style>
person Daniel Marques    schedule 13.03.2019
comment
Я вообще этого не понимаю. Если мне нужно, чтобы A было истинным, а B - ложным - сценарий, для которого вы указали MultiDataTrigger, был бы наиболее подходящим - тогда есть значение (выход), которое можно рассчитать, только зная A и B, что является сценарием в котором вы сказали, что MultiBinding будет более подходящим. - person mcwyrm; 22.03.2019
comment
За исключением этого простого случая (A == True && B == False), вам не нужен преобразователь для вычисления выходных данных. Вы можете оценить оба из них по отдельности. Итак, вы можете использовать MultiDataTrigger. С другой стороны, если ваш тестовый пример представляет собой что-то вроде A › B, вам понадобится преобразователь и вам нужно будет оценить оба значения одновременно. Для этого вам понадобится MultiBinding. - person Daniel Marques; 22.03.2019
comment
Основано ли это на чем-либо, кроме личных предпочтений? - person mcwyrm; 22.03.2019
comment
Нет. Как и большинство вещей в программировании. - person Daniel Marques; 22.03.2019