Как объединить DataTrigger и EventTrigger?
ПРИМЕЧАНИЕ Я задал соответствующий вопрос (с принятым ответом): Как объединить DataTrigger и Trigger?
Я думаю, мне нужно объединить EventTrigger
и DataTrigger
, чтобы добиться того, что мне нужно:
- когда элемент появляется в моем ListBox, он должен мигать в течение нескольких минут.
- если элемент "Критический", он должен оставаться выделенным.
В настоящее время у меня есть DataTemplate, который выглядит так:
<DataTemplate DataType="{x:Type Notifications:NotificationViewModel}">
<Grid HorizontalAlignment="Stretch">
<Border Name="Background" CornerRadius="8" Background="#80c0c0c0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
<Border Name="Highlight" CornerRadius="8" Background="Red" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
<!-- snip actual visual stuff -->
<Grid.Triggers>
<EventTrigger RoutedEvent="Grid.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation x:Name="LoadedAnimation"
Storyboard.TargetName="Highlight"
Storyboard.TargetProperty="Opacity"
From="0" To="1"
RepeatBehavior="5x"
Duration="0:00:0.2"
AutoReverse="True" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Grid.Triggers>
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=IsCritical}" Value="True">
<Setter TargetName="LoadedAnimation" Property="RepeatBehavior" Value="5.5x" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
Идея заключается в том, что EventTrigger анимирует непрозрачность границы Highlight
между 0 и 1 и снова назад, когда элемент загружен первым, привлекая внимание пользователя к нему. DataTrigger
определяет количество раз для анимации. Если модель представления сообщает, что элемент IsCritical
, то анимация происходит в 5,5 раза (например, она заканчивается с непрозрачностью 1), в противном случае она происходит 5 раз (заканчивается на непрозрачность 0).
Однако вышеупомянутый XAML не работает, потому что наборщик DataTrigger терпит неудачу:
Ребенок с именем "LoadedAnimation" не найден в VisualTree.
Достаточно честный. Итак, застенчивый подход к использованию настраиваемого конвертера значений или добавление количества анимаций в модель представления и привязки к нему, каковы мои параметры?
Ответы
Ответ 1
Если у вас есть доступ к SDK Blend (вы должны, если используете VS2012 +), вы должны выполнить это полностью в XAML, с чем-то вроде этого (отказ от ответственности: untested):
<Grid HorizontalAlignment="Stretch">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="NotificationStates">
<VisualState x:Name="Flashing">
<Storyboard>
<DoubleAnimation x:Name="LoadedAnimation"
Storyboard.TargetName="Highlight"
Storyboard.TargetProperty="Opacity"
From="0" To="1"
RepeatBehavior="5x"
Duration="0:00:0.2"
AutoReverse="True" />
</Storyboard>
</VisualState>
<VisualState x:Name="Normal" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border Name="Background" CornerRadius="8" Background="#80c0c0c0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
<Border Name="Highlight" CornerRadius="8" Background="Red" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
<!-- snip actual visual stuff -->
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<ic:GoToStateAction StateName="Flashing"/>
</i:EventTrigger>
<ie:DataTrigger Binding="{Binding Path=IsCritical}" Value="True">
<ic:GoToStateAction StateName="Flashing"/>
</ie:DataTrigger>
</i:Interaction.Triggers>
</Grid>
Извлеките свою раскадровку в VisualState, а затем используйте библиотеку выражений для переключения состояний в XAML. Вам понадобится библиотека Microsoft.Expression.Interactions, см. Также WPF/Silverlight States - активировать из XAML?
Ответ 2
В этом случае я бы использовал поведение вместо триггеров. Вы можете написать поведение, которое привязывает обработчик события к связанному событию загрузки объекта, а затем применяет анимацию. Поведение может выявить некоторые свойства, я бы предоставил свойство AnimationCount (int), которое сообщает о поведении, сколько раз повторять анимацию элемента, с которым он связан. Затем вы можете привязать это свойство к свойству IsCritical в модели представления и использовать конвертер значений для преобразования false в 5 и true в 5.5
Надеюсь, что это поможет
Ответ 3
Я знаю, что вы сказали, что не интересуетесь идеей конвертера, но похоже, что для решений Blend требуется установка библиотеки. Преобразователь не очень много работает и сигнализирует о том, что скорость напрямую зависит от свойства IsCritical
:
public class CriticalAnimationRateConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// Error handling omitted for brevity.
if ((bool)value)
return new System.Windows.Media.Animation.RepeatBehavior(5.5);
else
return new System.Windows.Media.Animation.RepeatBehavior(5.0);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
А затем обновите анимацию:
<DoubleAnimation Storyboard.TargetName="Highlight"
Storyboard.TargetProperty="Opacity"
From="0"
To="1"
RepeatBehavior="{Binding IsCritical, Converter={StaticResource CriticalAnimationRateConverter}}"
Duration="0:00:0.2"
AutoReverse="True" />
Затем DataTrigger
можно удалить.
Ответ 4
Попробуйте что-то вроде этого:
<Style x:Key="EventTriggerStyleKey">
<Style.Triggers>
<EventTrigger RoutedEvent="some event here">
<!-- your animation here -->
</EventTrigger>
<Style.Triggers>
</Style>
<Style x:Key="myStyleKey">
<Style.Triggers>
<DataTrigger Binding="....." Value="......">
<Setter Property="........." Value="......."/>
<Setter Property="Style" Value="{StaticResource EventTriggerStyleKey}"/>
</DataTrigger>
<Style.Triggers>
</Style>