Подтвердить что ты не робот

Как объединить 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.

Достаточно честный. Итак, застенчивый подход к использованию настраиваемого конвертера значений или добавление количества анимаций в модель представления и привязки к нему, каковы мои параметры?

4b9b3361

Ответ 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>