c# - WPF:DoubleAnimation "To"属性绑定(bind)计时

标签 c# wpf animation binding

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

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

我想它应该像这样工作:

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

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

  1. 按钮被点击
  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>

View 模型类:

    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;
    }
}

最佳答案

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

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 等标记语言来实现 View 逻辑非常有意义。

您可能还想考虑在 View 中指定实际高度,并绑定(bind)到 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 并绑定(bind)到其 IsChecked 属性,而不是使用 IsBottomOpened 源属性。您是否真的需要 View 模型中的这些属性取决于您的要求。

关于c# - WPF:DoubleAnimation "To"属性绑定(bind)计时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53476802/

相关文章:

javascript - 流畅的动画开始

jquery 简单的幻灯片

c# - 使用 C# 设置和 LocalFileSettingsProvider 时公司名称中的下划线

c# - 如何获取 DataGridViewRowSelectedRowCollection 中的列

c# - 如何将 xml 节点加载到 html 文本框中

angularjs - 从 Angular 2 和 Silverlight 应用程序使用相同的 WCF 服务

具有自动删除项目的 WPF 列表框

c# - Model.Is___ - 它应该是属性还是方法?

wpf - Wpf ScrollViewer滚动量

android - Jetpack Compose RC01 中缺少 AnimatedImageVector