Взаимодействие DataTriggers с начальными значениями не работает - PullRequest
0 голосов
/ 05 сентября 2018

Я пытаюсь создать шаблон данных WPF (4.6.2), который будет выполнять анимацию, когда для определенного свойства ViewModel установлено значение true, а затем будет устанавливать для свойства значение false после завершения анимации (а не только когда это запущено).

Это была одна попытка:

<DataTemplate DataType="...">
    <Border x:Name="Bd" ...>
        <Border.Resources>
            <Storyboard x:Key="Animate" FillBehavior="Stop">
                <DoubleAnimation Storyboard.TargetName="Bd"
                                 Storyboard.TargetProperty="Opacity"
                                 From="0" To="1" Duration="0:0:3" />
            </Storyboard>
        </Border.Resources>
        ...
        <i:Interaction.Triggers>
            <ei:DataTrigger Binding="{Binding ShouldAnimate}" Value="true">
                <ei:ControlStoryboardAction Storyboard="{StaticResource Animate}"
                                            ControlStoryboardOption="Play" />
            </ei:DataTrigger>
            <ei:StoryboardCompletedTrigger Storyboard="{StaticResource Animate}">
                <ei:ChangePropertyAction TargetObject="{Binding}"
                                         PropertyName="ShouldAnimate"
                                         Value="false" />
            </ei:StoryboardCompletedTrigger>
        </i:Interaction.Triggers>
    </Border>
</DataTemplate>

Это работает ... при условии, что я установил для свойства значение true после того, как уже создало пользовательский интерфейс. Если свойство уже имеет значение true, то ничего не происходит (раскадровка не запускается и свойство не сбрасывается).

(Я также не совсем доволен объявлением раскадровки как локального ресурса, чтобы TargetName работал, но, похоже, это необходимо.)

Другой попыткой было использование ванильного DataTrigger:

    <DataTemplate.Triggers>
        <DataTrigger Binding="{Binding ShouldAnimate}" Value="true">
            <DataTrigger.EnterActions>
                <BeginStoryboard Storyboard="{StaticResource Animate}" />
            </DataTrigger.EnterActions>
        </DataTrigger>
    </DataTemplate.Triggers>

Это успешно оживляет, даже если свойство было установлено заранее (хотя, как ни странно, Storyboard.TargetName должно быть указано , а не , а сама раскадровка должна быть объявлена ​​либо полностью вне DataTemplate или встроен в BeginStoryboard вместо использования ресурса). Но я не могу найти хороший способ сбросить свойство после завершения анимации.

Storyboard.Completed сначала показалось многообещающим, но, похоже, он не содержит никакой контекстной информации о том, к какому экземпляру он был вызван и, следовательно, какой ViewModel необходимо обновить. (Похоже, StoryboardCompletedTrigger использует это внутренне, но полагается на наличие локальных экземпляров раскадровки, а не глобальных ресурсов. Я еще не тестировал это с несколькими экземплярами шаблона, но будет важно, чтобы раскадровка, завершающая один, не влияла на другой. )


Я попытался объединить оба из них (запуск раскадровки в ванильном DataTrigger и ожидание завершения в триггере взаимодействия), но это вынуждает StoryboardCompletedTrigger.Storyboard выдавать ошибку синтаксического анализа "При раскадровке для IsFrozen должно быть установлено значение false, чтобы изменить" при попытке присоединить к обработчику события Completed; предположительно потому что ванильные триггеры применяются как стиль.

...