WPF MVVM属性更改动画(WPF MVVM Property Change Animation)

2019-09-02 15:20发布

我要寻找一个干净的方式开始的动画,将有动态值。 基本上我想要做其中元素的变化宽度根据另一个元素的数据的动画。 说我有一个TextBlock这就是Text属性绑定。 当此属性更改我希望有一个视觉元素说一个矩形为我们着想做DoubleAnimation是改变由前值的宽度为新值。

我试图从把代码如果可能的话我看来望而却步。 我看着DataTriggers但他们似乎需要你知道什么价值将如枚举。 在我的情况下,它只是值变更需要触发故事板和动画就需要开始在目前(先前)值并很好地移动到新的价值。

有任何想法吗。 也许我只是错过了一个属性。

Answer 1:

这里是我结束了该解决方案。 要根据我的ViewModel我使用了DataTrigger数据做动画。 下面是我的控制方式。

<Style TargetType="Grid" x:Key="DetailRotation" >
    <Style.Triggers>
        <DataTrigger Binding="{Binding Path=AnimationState}" Value="New">
            <DataTrigger.EnterActions>
                <StopStoryboard BeginStoryboardName="EndAnimation" />
                <BeginStoryboard Name="NewAnimation">
                    <Storyboard>
                        <ThicknessAnimation Storyboard.TargetProperty="Margin" From="0,30,0,0" To="0,0,0,0" Duration="0:0:1" />
                        <DoubleAnimation Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:1" />
                    </Storyboard>
                </BeginStoryboard>
            </DataTrigger.EnterActions>
            <DataTrigger.ExitActions>

            </DataTrigger.ExitActions>

        </DataTrigger>
        <DataTrigger Binding="{Binding Path=AnimationState}" Value="End">
            <DataTrigger.EnterActions>
                <StopStoryboard BeginStoryboardName="NewAnimation" />
                <BeginStoryboard Name="EndAnimation">
                    <Storyboard>
                        <ThicknessAnimation Storyboard.TargetProperty="Margin" From="0,0,0,0" To="0,-20,0,0" Duration="0:0:1"/>
                        <DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:1" />
                    </Storyboard>
                </BeginStoryboard>
            </DataTrigger.EnterActions>
        </DataTrigger>

    </Style.Triggers>
</Style>


Answer 2:

你可以探索利用附加属性挂钩必要的逻辑到情节提要/动画,你的愿望。

这不一定是从编写代码阻止你,但它会保持它从视图中分离出来,并使其能够跨越多个视图重新使用。



Answer 3:

由于通过动画修改属性不能动画“上下文”之外的设置,我想出了一个代码解决方案,因为我不能有效地做同样的XAML。

private void UserControl_IsVisibleChanged(object sender, 
    DependencyPropertyChangedEventArgs e)
{
    if (this.Visibility == Visibility.Visible)
    {
        DoubleAnimation fadeIn = new DoubleAnimation();
        fadeIn.From = 1d;
        fadeIn.To = 1d;
        fadeIn.Duration = new Duration(new TimeSpan(0, 0, 0));

        DoubleAnimation fade = new DoubleAnimation();
        fade.From = 1d;
        fade.To = 0d;
        fade.BeginTime = TimeSpan.FromSeconds(5);
        fade.Duration = new Duration(new TimeSpan(0, 0, 1));

        NameScope.SetNameScope(this, new NameScope());
        this.RegisterName(this.Name, this);

        Storyboard.SetTargetName(fadeIn, this.Name);
        Storyboard.SetTargetProperty(fadeIn, new PropertyPath
            (UIElement.OpacityProperty));

        Storyboard.SetTargetName(fade, this.Name);
        Storyboard.SetTargetProperty(fade, new PropertyPath
            (UIElement.OpacityProperty));

        Storyboard sb = new Storyboard();
        sb.Children.Add(fadeIn);
        sb.Children.Add(fade);

        sb.Completed += new EventHandler(sb_Completed);
        sb.Begin(this);
    }
}

void sb_Completed(object sender, EventArgs e)
{
    this.Visibility = Visibility.Hidden;
}


Answer 4:

其实你要绑定的DoubleAnimation.ToPropertyViewModel属性和动画的实际控制。 问题是,当动画应继续ToProperty改变。 我的解决方案封装所有这一逻辑的MarkupExtenstion它包装一个Binding

public class AnimateBindingExtension : MarkupExtension {
    static DependencyPropertyDescriptor dpd =
        DependencyPropertyDescriptor.FromProperty(DoubleAnimation.ToProperty, 
            typeof(DoubleAnimation));

    public AnimateBindingExtension(PropertyPath path) {
        Path = path;
    }

    public bool ValidatesOnExceptions { get; set; }
    public IValueConverter Converter { get; set; }
    public object ConverterParamter { get; set; }
    public string ElementName { get; set; }
    public RelativeSource RelativeSource { get; set; }
    public object Source { get; set; }
    public bool ValidatesOnDataErrors { get; set; }
    [ConstructorArgument("path")]
    public PropertyPath Path { get; set; }
    public object TargetNullValue { get; set; }

    public override object ProvideValue(IServiceProvider serviceProvider) {
        var valueProvider = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;

        if (valueProvider == null) {
            throw new Exception("could not get IProviderValueTarget service.");
        }

        var bindingTarget = valueProvider.TargetObject as FrameworkElement;
        var bindingProperty = valueProvider.TargetProperty as DependencyProperty;

        if (bindingProperty == null || bindingTarget == null) {
            throw new Exception();
        }

        var binding = new Binding {
            Path = Path,
            Converter = Converter,
            ConverterParameter = ConverterParamter,
            ValidatesOnDataErrors = ValidatesOnDataErrors,
            ValidatesOnExceptions = ValidatesOnExceptions,
            TargetNullValue = TargetNullValue
        };

        if (ElementName != null) binding.ElementName = ElementName;
        else if (RelativeSource != null) binding.RelativeSource = RelativeSource;
        else if (Source != null) binding.Source = Source;

        // you can add a Duration property to this class and use it here
        var anim = new DoubleAnimation {
            Duration = new Duration(TimeSpan.FromSeconds(0.1)),
            AccelerationRatio = 0.2,
            DecelerationRatio = 0.8
        };
        // this can be a new subclass of DoubleAnimation that 
        // overrides ToProperty metadata and add a property 
        // change callback
        dpd.AddValueChanged(anim, (s, e) => bindingTarget.BeginAnimation(bindingProperty, anim));

        BindingOperations.SetBinding(anim, DoubleAnimation.ToProperty, binding);
        // this is because we need to catch the DataContext so add animation object 
        // to the visual tree by adding it to target object's resources.
        bindingTarget.Resources[bindingProperty.Name] = anim;
        // animation will set the value
        return DependencyProperty.UnsetValue;
    }
}

你可以做同样的与其他动画类动画等类型。



文章来源: WPF MVVM Property Change Animation