【问题标题】:WPF mouse click returns storyboard to previous stateWPF 鼠标单击将情节提要返回到以前的状态
【发布时间】:2017-08-19 21:10:01
【问题描述】:

如果单击此代码,则此代码将动画椭圆的运动。如何通过再次单击其新位置来返回(以动画方式 - 就像情节提要一样)椭圆在初始位置。那可能吗? (最好只在 XAML 中)

<Ellipse x:Name="circle_button" HorizontalAlignment="Left" Height="100" Margin="30,40,0,0" VerticalAlignment="Top" Width="100" Fill="#FF33D3A7" >
        <Ellipse.Triggers>
            <EventTrigger RoutedEvent="Ellipse.MouseDown" >
                <BeginStoryboard>
                    <Storyboard>
                        <ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
                            <SplineThicknessKeyFrame KeyTime="00:00:00" Value="30,40,0,0" />
                            <SplineThicknessKeyFrame KeyTime="00:00:00.4" Value="95,120,0,0" />
                        </ThicknessAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Ellipse.Triggers>

【问题讨论】:

  • 你可以停止storyboard(默认动画是holding value你可以使用"HoldBehavior=Stop"在情节提要结束时将其释放到初始状态)。
  • @Sinatr 没有 HoldBehavior 属性。只有 FillBehavior,它不起作用。
  • 如果我添加 FillBehavior="Stop" 它会自动返回先前位置的椭圆。我不是想实现这一点。我想再次点击它的新位置,然后将其发送回初始位置
  • 抱歉打错字,FillBehavior=Stop 确实如此。我并不是说它是一种解决方案,而是一种查看动画是 hold 值的方法。如果您想避免代码隐藏,您必须使用 2 个省略号,因为纯粹在 xaml 处理状态切换逻辑中是不可能的(您可以编写行为来这样做)。否则使用 2 VisualState 并在代码隐藏中切换它们(类似于@macieqqq 答案)应该更合适

标签: c# wpf xaml storyboard wpf-animation


【解决方案1】:

我认为一种可能的方法是定义故事板并使用一些代码来触发动画。

这是一个例子:

Xaml:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <Storyboard x:Key="ElipseStoryboard">
            <ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
                <SplineThicknessKeyFrame KeyTime="00:00:00" Value="30,40,0,0" />
                <SplineThicknessKeyFrame KeyTime="00:00:00.4" Value="95,120,0,0" />
            </ThicknessAnimationUsingKeyFrames>
        </Storyboard>
        <Storyboard x:Key="ElipseStoryboardReversed">
            <ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
                <SplineThicknessKeyFrame KeyTime="00:00:00" Value="95,120,0,0" />
                <SplineThicknessKeyFrame KeyTime="00:00:00.4" Value="30,40,0,0" />
            </ThicknessAnimationUsingKeyFrames>
        </Storyboard>
    </Window.Resources>
    <Grid x:Name="CP">
        <Ellipse x:Name="circle_button" MouseDown="Circle_button_OnMouseDown" HorizontalAlignment="Left" Height="100" Margin="30,40,0,0" VerticalAlignment="Top" Width="100" Fill="#FF33D3A7" >
        </Ellipse>
    </Grid>
</Window>

后面的代码:

namespace WpfApplication1
{    
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private bool flag = false;
        private void Circle_button_OnMouseDown(object sender, MouseButtonEventArgs e)
        {
            if (flag)
            {
                var storyboard = this.Resources["ElipseStoryboard"] as Storyboard;
                if (storyboard != null)
                    storyboard.Begin(circle_button);
            }
            else
            {
                var storyboard = this.Resources["ElipseStoryboardReversed"] as Storyboard;
                if (storyboard != null)
                    storyboard.Begin(circle_button);
            }
            flag = !flag;
        }
    }
}

请试一试。

仅替代 Xaml 解决方案:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">

    <Grid x:Name="CP">
        <Ellipse x:Name="circle_button" HorizontalAlignment="Left" Height="100" Margin="30,40,0,0" VerticalAlignment="Top" Width="100" Fill="#FF33D3A7" >
            <Ellipse.Triggers>
                <EventTrigger RoutedEvent="Ellipse.MouseDown" >
                    <BeginStoryboard>
                        <Storyboard>
                            <ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
                                <SplineThicknessKeyFrame KeyTime="00:00:00" Value="30,40,0,0" />
                                <SplineThicknessKeyFrame KeyTime="00:00:00.4" Value="95,120,0,0" />
                            </ThicknessAnimationUsingKeyFrames>
                            <DoubleAnimation Storyboard.TargetProperty="Opacity" Storyboard.TargetName="circle_button"
                        From="1.0" To="0.0" Duration="0:0:0" BeginTime="00:00:00.4"></DoubleAnimation>
                            <DoubleAnimation Storyboard.TargetProperty="Opacity" Storyboard.TargetName="circle_button2"
                        From="0.0" To="1.0" Duration="0:0:0" BeginTime="00:00:00.4"></DoubleAnimation>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </Ellipse.Triggers>
            </Ellipse>

        <Ellipse x:Name="circle_button2" Opacity="0" HorizontalAlignment="Left" Height="100" Margin="95,120,0,0" VerticalAlignment="Top" Width="100" Fill="#FF33D3A7" >
            <Ellipse.Triggers>
                <EventTrigger RoutedEvent="Ellipse.MouseDown" >
                    <BeginStoryboard>
                        <Storyboard>
                            <ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="Margin" BeginTime="00:00:00" Storyboard.TargetName="circle_button">
                                <SplineThicknessKeyFrame KeyTime="00:00:00" Value="95,120,0,0" />
                                <SplineThicknessKeyFrame KeyTime="00:00:00.4" Value="30,40,0,0" />
                            </ThicknessAnimationUsingKeyFrames>
                            <DoubleAnimation Storyboard.TargetProperty="Opacity" Storyboard.TargetName="circle_button2"
                        From="1.0" To="0.0" Duration="0:0:0" ></DoubleAnimation>
                            <DoubleAnimation Storyboard.TargetProperty="Opacity" Storyboard.TargetName="circle_button"
                        From="0.0" To="1.0" Duration="0:0:0"></DoubleAnimation>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </Ellipse.Triggers>
        </Ellipse>
    </Grid>

</Window>

【讨论】:

  • 非常感谢您的回答。除了与代码结合使用的可能方法之外,您认为是否可以仅在 XAML 中完成?
  • 我认为这是可能的。但这并不容易。例如,您可以创建两个省略号,将触发器与适当的情节提要放在每一个上,并在情节提要的末尾操纵省略号的可见性。我想当我有时间准备的时候,我可以给你举个例子。
  • 这是我已经想到的。但我认为创建两个不同的椭圆来表示单个按钮并没有多大意义。如果没有其他办法,我更愿意坚持你的解决方案。谢谢。
  • 我刚刚准备了示例 - 它已添加到此帖子中。如何实现它取决于您。我更喜欢在后面的代码中实现。 Xaml 在应用程序增长过程中可能会变得越来越复杂。
【解决方案2】:

另一种方法是使用可视状态并在代码隐藏中简单地在它们之间切换。与将动画作为资源保存相比,这可能是更更清晰的方法。

xaml:

<Ellipse x:Name="circle_button"
         HorizontalAlignment="Left"
         Height="100"
         Margin="30,40,0,0"
         VerticalAlignment="Top"
         Width="100"
         Fill="#FF33D3A7"
         MouseDown="circle_button_MouseDown">
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup>
            <VisualState x:Name="A">
                <Storyboard>
                    <ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="Margin">
                        <SplineThicknessKeyFrame KeyTime="0:0:0.4" Value="95,120,0,0" />
                    </ThicknessAnimationUsingKeyFrames>
                </Storyboard>
            </VisualState>
            <VisualState x:Name="B">
                <Storyboard>
                    <ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="Margin">
                        <SplineThicknessKeyFrame KeyTime="0:0:0.4" Value="30,40,0,0" />
                    </ThicknessAnimationUsingKeyFrames>
                </Storyboard>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
</Ellipse>

cs:

bool _isStateB;

void circle_button_MouseDown(object sender, MouseButtonEventArgs e)
{
    _isStateB = !_isStateB;
    VisualStateManager.GoToElementState(circle_button, _isStateB ? "B" : "A", true);
}

演示:

可以使用Button 代替Ellipse(使用包含此类椭圆的样式),然后您将拥有Click 事件以及使用键盘聚焦和单击元素的能力。

PS:写完答案后我突然有一个想法。ToggleButton 有 2 个状态,实际上您可以使用 IsChecked 在 2 个位置之间切换(并运行不同的动画)。 .. 在添加第三个之前,最好使用具有视觉状态的解决方案。

【讨论】:

  • ToggleButton 的想法很有趣,但您能提供一些示例或类似内容的链接吗?我在 WPF 和 XAML 方面没有丰富的经验。非常感谢您的回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-11-30
  • 2011-12-29
  • 2012-11-09
  • 1970-01-01
  • 2012-12-31
  • 1970-01-01
  • 2017-11-27
相关资源
最近更新 更多