我的视图中有一个简单的Border
元素,其中包含一个子TextBlock
,该子绑定到表示应用程序中进程状态的字符串。
我正在尝试对此边框进行动画处理,以便在修改TextBlock
绑定到的字符串时,它可以从屏幕外滑入查看。
这是我到目前为止所拥有的:
<Border>
<Border.Triggers>
<EventTrigger RoutedEvent="Binding.TargetUpdated">
<BeginStoryboard>
<Storyboard>
<ThicknessAnimation Storyboard.TargetProperty="Margin" From="0,-100,0,0" To="0,0,0,0" DecelerationRatio=".9" Duration="0:0:1" />
<ThicknessAnimation Storyboard.TargetProperty="Margin" From="0,0,0,0" To="0,-100,0,0" AccelerationRatio=".9" BeginTime="0:0:5" Duration="0:0:1" />
</Storyboard>
</BeginStoryBoard>
</EventTrigger>
</Border.Triggers>
<TextBlock Text="{Binding StatusText, Mode=OneWay, NotifyOnTargetUpdated=True}"></TextBlock>
</Border>
这按预期工作,但有两个我不知道如何解决的问题:
- 每当文本更改时,动画都会重新开始,我不希望这样。我想要的是等待 5 秒,然后再重新启动。因此,如果文本不断更新,则面板应保持静止,直到自上次更新以来超过 5 秒,然后向上滑动。
- 当应用程序启动时,动画将立即播放。我猜是因为初始绑定算作更新。我怎样才能阻止这种情况发生?
考虑到您的数据在 ViewModel 中,对于问题 1,我建议使用每次更改时都会重新启动StatusText
DispatcherTimer
(您应该为此使用 INotifyPropertyChanged
)。将DispatcherTimer.Interval
设置为 5000 毫秒,当它滴答作响时,开始动画以将边框滑出屏幕。
现在的问题是,由于您使用的是MVVM,因此我知道应用动画的唯一方法非常复杂。
因此,若要手动应用动画(不是从 XAML,而是从 ViewModel),我建议创建一个继承自 Border 的自定义控件类,然后在 XAML 中创建自定义控件类的实例,最后从自定义控件类中触发"滑出屏幕"动画。
若要从 ViewModel 触发动画(位于自定义控件中),可以在自定义控件类中设置一个类型为 bool
的DependencyProperty
,该将在设置为 true 时触发动画(动画启动后立即将依赖项属性的值更改回 false,以便以后可以通过再次将值更改为 true 来再次触发动画)。触发动画的此绑定使用TowWay
模式非常重要,这样在启动动画时 ViewModel 中的属性也会设置回 false。因此,从技术上讲,视图模型中的 bool 属性将用作一个开关,在您翻转它后立即自动关闭(类似于 Minecraft 中的按钮和杠杆)。
对于求解器问题 2,只需保留另一个 bool
变量作为标志,以避免在第一次更改StatusText
时触发动画。
PS:我知道问题 1 的解决方案很复杂,但到目前为止,这是我发现在不破坏 MVVM 的情况下从 ViewModel 触发动画的唯一方法。