Анимация WPF Windows Presentation Foundation с использованием мультитриггера

#wpf #xaml #animation #multitrigger

#wpf #xaml #Анимация #мультитриггер

Вопрос:

Я пытаюсь освоиться с тем, как создавать анимации с использованием WPF XAML. Я изо всех сил пытаюсь заставить свою анимацию запускаться на основе правильных условий, и теперь мне нужна помощь.

Просто для смеха я хочу создать страницу с кнопкой, которая будет уклоняться от любой попытки нажатия, перемещаясь в другое место на холсте. Вот иллюстрация моих желаемых анимаций: введите описание изображения здесь

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

Это то, что у меня есть на данный момент:

  <Page x:Class="myApp.SecondPage"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
  mc:Ignorable="d" 
  xmlns:c="clr-namespace:myApp"
  d:DesignHeight="300" d:DesignWidth="500"
Title="SecondPage" Height="300" Width="500">
<Page.Resources>        
    <PathGeometry x:Key="AnimationPath" Figures="M 0,0 C -130,-100 -130,-60 -130,-0"/>
    <Style x:Key="secondButton" TargetType="Button">
        <Setter Property="Content" Value="Button"></Setter>
        <Style.Triggers>
            <MultiTrigger >
                <MultiTrigger.Conditions>
                    <Condition  Property="IsMouseOver" Value="True"></Condition>
 <!--Doesn't work --><Condition Property="TranslateTransform.X" Value="0"></Condition>
                </MultiTrigger.Conditions>
                <MultiTrigger.EnterActions>
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimationUsingPath x:Name="XAnim"
                                   FillBehavior="HoldEnd"
                                   Storyboard.TargetProperty="RenderTransform.X"
                                   PathGeometry="{StaticResource AnimationPath}"
                                   Source="X" 
                                   Duration="0:0:.2"  
                                   />
                            <DoubleAnimationUsingPath x:Name="YAnim"
                                   FillBehavior="HoldEnd"
                                   Storyboard.TargetProperty="RenderTransform.Y"                                       
                                   PathGeometry="{StaticResource AnimationPath}"
                                   Source="Y" 
                                   Duration="0:0:.2"  
                                  />                             
                        </Storyboard>

                    </BeginStoryboard>

                </MultiTrigger.EnterActions>
            </MultiTrigger>
        </Style.Triggers>
    </Style>
</Page.Resources>

    <Grid>
    <Canvas HorizontalAlignment="Stretch" Name="MyCanvas" VerticalAlignment="Stretch" IsManipulationEnabled="True">
      <Button  Style="{StaticResource secondButton}" Canvas.Left="150" Canvas.Top="240" Height="48" x:Name="theButton" Width="115" FontSize="18" ForceCursor="False">
            <Button.RenderTransform>
                <TranslateTransform x:Name="AnimatedTranslateTransform"/>
            </Button.RenderTransform>
        </Button>
    </Canvas>
</Grid>
  

В моем втором состоянии мультитриггера я пытаюсь проверить, где находится кнопка (чтобы запустить правильную раскадровку). Кажется, я просто не могу понять, какое свойство и значение использовать в условии, чтобы оценить, находится ли кнопка с левой или правой стороны. TranslateTransform.X Свойство не работает. Есть предложения?

Ответ №1:

Вам нужно поработать с MultiDataTrigger здесь, чтобы выполнить преобразование:

 <Style x:Key="secondButton" TargetType="Button">
    <Style.Triggers>
        <!-- ... -->
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}"
                        Value="True" />
                <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=RenderTransform.X}"
                        Value="0"/>
            </MultiDataTrigger.Conditions>
            <!-- ... -->
        </MultiDataTrigger>
    </Style.Triggers>
</Style>
  

(В обычном мультитриггере вы можете получить доступ только к непосредственным свойствам, Property="TranslateTransform.X" это не только неправильно, поскольку так и должно быть Property="RenderTransform.X" , но в дальнейшем оно будет оцениваться как присоединенное свойство, которого не существует)

Поскольку вы назвали преобразование, вы могли бы также использовать привязку с помощью ElementName вместо RelativeSource во втором условии.

 <Condition Binding="{Binding ElementName=AnimatedTranslateTransform, Path=X}"
           Value="0"/>
  

Комментарии:

1. 1 Спасибо! Это выглядит как хороший ответ. К сожалению, у меня нет возможности проверить (и принять) это до понедельника. Я кратко рассмотрел MultiDataTrigger, но подумал, что это в первую очередь для работы с данными (из чтения документации).

2. Тогда просто считайте состояние преобразования данными :), я не думаю, что вам нужно так сильно беспокоиться об этом.

3. Я все еще довольно неопытен в WPF и XAML, и концепция, с помощью которой что-то может определять привязку RelativeSource={RelativeSource Self} , была для меня новой. Прямо сейчас это выглядит как недостающий фрагмент в моей головоломке.

4. Тогда вы, возможно, захотите прочитать эту статью здесь . (И / или некоторые другие статьи о WPF , которые все довольно хороши)