Эффективность (нескольких) MultiDataTrigger против Конвертера
В настоящее время я анализирую некоторые XAML, которые используют стиль, который широко использует MultiDataTriggers (8-10 триггеров с несколькими данными на стиль, с 4-6 условиями на триггер). Глядя на это, я размышляю, будет ли эффективнее использовать конвертер (или конвертер нескольких значений), тем более что MultiDataTriggers не могут быть отлажены.
Кто-нибудь может авторитетно заявить, как MultiDataTriggers компилируются? Я понимаю, что Условия объединены, составлено ли это таким образом, чтобы было предусмотрено сокращение?
А как насчет нескольких MultiDataTriggers? Замкнуты ли они так, что первый полностью удовлетворенный вызывает остановку оценки? Или все они оцениваются с последним выигрышем, если несколько удовлетворены?
2 ответа
Triggers are evaluated from top to bottom
, Это справедливо для всех видов триггеров (Trigger, DataTrigger, MultiTrigger и MutliDataTrigger).
А как насчет нескольких MultiDataTriggers? Замкнуты ли они так, что первый полностью удовлетворенный вызывает остановку оценки? Или все они оцениваются с последним выигрышем, если несколько удовлетворены?
Как указано триггеры оцениваются сверху вниз. Таким образом, если сначала выполнить все условия, это не означает, что дальнейшие триггеры не будут оцениваться. Все триггеры, примененные к измененному свойству, оцениваются, и если любые два из них устанавливают одно и то же свойство внутри триггера, тогда last trigger always won
а также overrides the property set by first trigger
,
<TextBlock>
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding IsEnable}" Value="True">
<Setter Property="Text" Value="Test1"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsEnable}" Value="True">
<Setter Property="Text" Value="Test2"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
Текст всегда будет Test2
когда IsEnable
оценивает, чтобы быть правдой.
Кто-нибудь может авторитетно заявить, как MultiDataTriggers компилируются? Я понимаю, что Условия объединены, составлено ли это таким образом, чтобы было предусмотрено сокращение?
Да, в MultiDataTrigger предусмотрена короткая резка, т.е. если first condition evaluate to be false, second condition won't be checked
, Этот пример подтверждает это -
<TextBlock>
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsEnable,
Converter={StaticResource SingleValueConverter}}"
Value="True"/>
<Condition Binding="{Binding IsEnable,
Converter={StaticResource SingleValueConverter}}"
Value="True"/>
</MultiDataTrigger.Conditions>
<Setter Property="Text" Value="Test"/>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
В обоих случаях применяется преобразователь, но в случае IsEnabled
является false
, converter gets hit only once
потому что первое условие оценивается как ложное. Но в случае IsEnabled
является true
, converter gets hit twice
первое условие успешно выполнено.
Конвертеры позволяют отладку и более сложную логику, но они также должны проверить все свои Bindings
и вызывать внешнюю функцию каждый раз, когда один из их Bindings
менять. Таким образом, они медленнее, чем триггеры почти во всех случаях. Триггеры останавливаются при первом невыполненном условии.
Так что мой ответ - использовать MutiDataTrigger настолько, насколько это возможно, когда вам нужно больше логики, в зависимости от того, возможно ли, что некоторые условия повторяются в другом месте или нет, вы можете реализовать дополнительную DependencyProperty
(который изменяется при изменении некоторых других свойств) или использовать конвертер.
Например, у меня есть 5 свойств, которые я хочу связать с:
IsChecked = A && B && (C || D || !E)
IsReadonly = !A && !B && (C || D || !E)
поэтому я бы создал новое свойство F, равное C || D || !E
и когда одно из этих трех изменений, обновите F
, теперь я могу использовать F
в качестве третьего пути привязки триггера.