WPF:DoubleAnimation“至”属性绑定时间

时间:2018-11-26 07:58:28

标签: c# wpf animation binding

我正在尝试制作一个Button,该面板使用该面板的Height属性上的动画来打开/关闭某些面板。

方法是将动画的“ To”值绑定到viewmodel属性,该属性在按钮的命令中进行了更改。

我想它应该像这样工作:

  1. Button被点击
  2. viewmodel检查其“ IsOpened”属性
  3. 如果它是True,则vm将其设置为False,并将TargetHeight设置为0;如果为False,则vm将其设置为True,将TargetHeight设置为128
  4. 动画触发并将高度更改为所需值

但是实际上它是这样工作的:

  1. Button被点击
  2. 动画触发并将Height更改为先前设置的值
  3. viewmodel检查其“ IsOpened”属性并更改其值

因此,viewmodel不会为当前单击按钮设置目标高度,而是为将来的下一次设置目标高度。

我应该做些什么才能使其正确? 不幸的是,已经尝试设置BeginTime属性来延迟动画播放,但这没有帮助。

代码如下:

XAML

<Button Command="{Binding SwitchBottomPanel}">
        <Button.Triggers>
            <EventTrigger RoutedEvent="Button.Click">
                <BeginStoryboard>
                    <Storyboard>
                        <DoubleAnimation Storyboard.TargetName="BottomPanel"
                                         Storyboard.TargetProperty="Height"
                                         To="{Binding TargetHeight}"
                                         Duration="0:0:0.3"
                                         BeginTime="0:0:0.3"/>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Button.Triggers>
    </Button>

Viewmodel类:

    class MainViewModel : ViewModelBase
{
    private double _targetHeight;
    private bool _isBottomOpened;
    private double _bottomHeightBig = 128;

    public double TargetHeight
    {
        get { return _targetHeight; }
        set
        {
            _targetHeight = value;
            RaisePropertyChanged(nameof(TargetHeight));
        }
    }

    public bool IsBottomOpened
    {
        get { return _isBottomOpened; }
        set
        {
            _isBottomOpened = value;

            if (value == true) TargetHeight = _bottomHeightBig;
            else TargetHeight = 0;

            RaisePropertyChanged(nameof(IsBottomOpened));
        }
    }

    public ICommand SwitchBottomPanel { get; set; }

    public MainViewModel()
    {
        SwitchBottomPanel = new DelegateCommand(() => IsBottomOpened = !IsBottomOpened);
        RaisePropertyChanged(nameof(SwitchBottomPanel));

        IsBottomOpened = false;
    }
}

1 个答案:

答案 0 :(得分:1)

您可以处理视图模型的PropertyChanged事件,并在视图中以编程方式启动动画:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new MainViewModel();
        Loaded += OnLoaded;
        Unloaded += OnUnloaded;
    }

    private MainViewModel ViewModel => DataContext as MainViewModel;

    private void OnLoaded(object sender, RoutedEventArgs e) =>
        ViewModel.PropertyChanged += ViewModel_PropertyChanged;

    private void OnUnloaded(object sender, RoutedEventArgs e) =>
        ViewModel.PropertyChanged += ViewModel_PropertyChanged;

    private void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) =>
        BottomPanel.BeginAnimation(HeightProperty, new DoubleAnimation()
        {
            To = ViewModel.TargetHeight,
            Duration = TimeSpan.FromSeconds(0.3)
        });
}

仅仅因为您可以在纯XAML中实现诸如动画之类的功能,但这并不意味着您总是应该如此。在这个示例中,使用诸如C#这样的表达性编程语言而不是使用诸如XAML这样的标记语言来实现视图逻辑是非常有意义的。

您可能还需要考虑在视图中指定实际高度,并绑定到IsBottomOpened属性:

<Grid x:Name="BottomPanel" Background="Yellow" Height="0" Width="200">
    <Grid.Style>
        <Style TargetType="Grid">
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsBottomOpened}">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Storyboard.TargetProperty="Height"
                                         To="128"
                                         Duration="0:0:0.3" />
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Grid.Style>
</Grid>

如果这样做,也可以将Button元素替换为ToggleButton并绑定到其IsChecked属性,而不是使用IsBottomOpened源属性。在视图模型中是否真正需要这些属性取决于您的要求。