我似乎在这里达到了某种 MVVM 突破点。
当底层视图模型对象的“状态”属性发生变化时,我希望控件的不透明度动画半秒(DoubleAnimation 从 0.5 到 1.0)。我最初使用 DataTrigger 实现了这一点,但由于我还没有找到一种方法来对任何更改做出反应,只是一个给定的值,我必须始终将 VM 对象的“状态”属性翻转为特殊的“待定”值,然后再设置它达到其预期值。(有没有办法对任何变化做出反应?)
这很 hacky,所以我开始摆弄 EventTriggers ......
这是我迄今为止尝试过的:
- 使用普通
EventTrigger
这似乎需要一个 RoutedEvent,但这反过来又要求我的底层视图模型对象继承自 DependencyObject。
- 使用
i:Interaction.Triggers
这样我就可以收听正常的 .NET 事件并对其做出反应,但我还没有找到一种方法来开始StoryBoard
使用这种方法。
- 使用
i:Interaction.Triggers
和编写Behavior
这个实验没有发现我没有办法将我的自定义行为附加到它的相关控件上。
这就是 XAML 的样子:
<cc:MyControl>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Updated">
<i:Interaction.Behaviors>
<cv:OpacityBehavior Duration="0:0:0:5" />
</i:Interaction.Behaviors>
</i:EventTrigger>
</i:Interaction.Triggers>
这是自定义行为:
class OpacityBehavior : Behavior<MyControl>
{
public Duration Duration { get; set; }
protected override void OnAttached()
{
base.OnAttached();
var animation = new DoubleAnimation(0.5, 1, Duration, FillBehavior.HoldEnd);
var associatedObject = lookupVisualParent(this);
associatedObject.BeginAnimation(UIElement.OpacityProperty, animation);
}
}
这不起作用,因为 XAML 解析器要求它直接附加到“MyControl”,但我需要将它附加到事件触发器。然后我尝试了这种方法:
class OpacityBehavior : Behavior<DependencyObject>
{
public Duration Duration { get; set; }
protected override void OnAttached()
{
base.OnAttached();
var animation = new DoubleAnimation(0.5, 1, Duration, FillBehavior.HoldEnd);
var associatedObject = lookupVisualParent(this);
associatedObject.BeginAnimation(UIElement.OpacityProperty, animation);
}
private UIElement lookupVisualParent(DependencyObject dObj)
{
if (dObj is UIElement)
return (UIElement) dObj;
if (dObj == null)
return null;
return lookupVisualParent(LogicalTreeHelper.GetParent(dObj));
}
}
这失败了,因为它lookupVisualParent
不起作用。行为的逻辑父级总是null
.
我觉得这应该是一个相当普遍的任务?这个问题有好的解决方案吗?我觉得很奇怪我将编写我的视图模型类,以便它们派生DependencyObject
以便在事件触发时启动动画。
干杯