依赖属性值优先级和动画

时间:2010-11-05 11:14:55

标签: wpf dependency-properties

我正在使用DoubleAnimation设置一些属性。在触发动画之前,任何本地或Setter更改都会在属性中正确反映。动画完成后,似乎无法更改属性的值。我甚至尝试ClearValueInvalidateProperty设置了调用SetValue,但动画的剩余值仍然存在。如果重复动画,则该属性将继续按预期进行动画处理,因此仅对非动画更改进行锁定。

有没有办法纠正这种行为?我想使用动画来更改属性值,但仍然可以手动或通过Setter更改为其他任何内容。我对Dependency Property Value Precedence了解了一两件事,但我目前遇到的行为有点奇怪。我不想使用“手动动画”。

编辑:添加了示例XAML +代码。

<Window x:Class="WpfApplication7.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300"
        x:Name="_this"
        Background="Red">
    <DockPanel>
        <StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" HorizontalAlignment="Center" >
            <Button Click="ToggleOnClick">Toggle!</Button>
            <Button Click="SetHalfOnClick">Set to 0.5!</Button>
        </StackPanel>
        <TextBox DockPanel.Dock="Bottom" IsReadOnly="True" Text="{Binding ElementName=_viewbox,Path=Opacity}" />
        <Viewbox x:Name="_viewbox">
            <Viewbox.Style>
                <Style TargetType="{x:Type FrameworkElement}">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding Path=IsToggled,ElementName=_this,Mode=OneWay}" Value="True">
                            <DataTrigger.EnterActions>
                                <BeginStoryboard>
                                    <Storyboard>
                                        <DoubleAnimation To="0.2"
                                                 Duration="0:0:0.5"
                                                 Storyboard.TargetProperty="(UIElement.Opacity)" />
                                    </Storyboard>
                                </BeginStoryboard>
                            </DataTrigger.EnterActions>
                            <DataTrigger.ExitActions>
                                <BeginStoryboard>
                                    <Storyboard>
                                        <DoubleAnimation To="1"
                                                 Duration="0:0:0.5"
                                                 Storyboard.TargetProperty="(UIElement.Opacity)" />
                                    </Storyboard>
                                </BeginStoryboard>
                            </DataTrigger.ExitActions>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Viewbox.Style>

            <TextBlock Text="Sample!" />
        </Viewbox>
    </DockPanel>
</Window>

以下是代码:

using System.Windows;

namespace WpfApplication7
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1
    {
        public bool IsToggled
        {
            get { return (bool)GetValue(IsToggledProperty); }
            set { SetValue(IsToggledProperty, value); }
        }

        public static readonly DependencyProperty IsToggledProperty = DependencyProperty.Register("IsToggled", typeof(bool), typeof(Window1), new UIPropertyMetadata(false));

        public Window1()
        {
            InitializeComponent();
        }

        private void ToggleOnClick(object sender, RoutedEventArgs e)
        {
            IsToggled = !IsToggled;
        }

        private void SetHalfOnClick(object sender, RoutedEventArgs e)
        {
            _viewbox.Opacity = 0.5;
        }
    }
}

2 个答案:

答案 0 :(得分:3)

编辑2以回应评论:

在您的示例中,您可以通过以下方式解决问题:

  1. 在动画
  2. 上设置FillBehaviourStop
  3. 在代码中添加处理程序到Completed事件:
  4. <Storyboard Completed="FadeOut_Completed">

    最后,在Completed处理程序中设置所需的'final'值(显式或使用属性的当前值

    private void FadeOut_Completed(object sender, EventArgs e)
    {
       _viewbox.Opacity = _viewbox.Opacity; //this sets the DP value to the animated value
    }
    

    这适用于您的样本;希望它能解决你的问题!


    原始答案

    如果您将Storyboard的{​​{3}}属性设置为Stop(而不是默认值HoldEnd),它将恢复为动画的前动画值动画完成后的属性。 HoldEnd使动画在属性上保持其最终值

    更新以回应评论:

    如评论中所述,当HoldEnd被指定为FillBehaviour时,动画值将覆盖针对属性设置的值。

    这使得将值设置为其他东西有点棘手。

    我不确定是否有更好的方法来实现这一目标,但下面的示例显示了一种解决方法。如果没有来自OP的示例用法,很难判断这是多么适用,但是在这个例子中,我在加载Rectangle的宽度时设置动画,然后在单击按钮时将其重置为另一个值:

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Window.Triggers>
            <EventTrigger RoutedEvent="Window.Loaded">
                <BeginStoryboard>
                    <Storyboard>
                        <DoubleAnimation Storyboard.TargetName="Target" Storyboard.TargetProperty="Width"
                                         From="10" To="100" Duration="0:00:01" FillBehavior="HoldEnd" />
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Window.Triggers>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <Rectangle Height="10" Width="10" Fill="Red"  x:Name="Target"/>
            <Button Grid.Row="1" Content="Resize">
                <Button.Triggers>
                    <EventTrigger RoutedEvent="Button.Click">
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimationUsingKeyFrames Storyboard.TargetName="Target" Storyboard.TargetProperty="Width">
                                    <DiscreteDoubleKeyFrame Value="50" KeyTime="0:00:00" />
                                </DoubleAnimationUsingKeyFrames>
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                </Button.Triggers>
            </Button>
        </Grid>
    </Window>
    

    这是有效的,因为 new 动画会覆盖原始设置中的值。

答案 1 :(得分:3)

您可以将UIElement.BeginAnimation与动画参数设置为 null 一起使用。它将清除您房产附带的所有动画。