为什么绑定不能与动画一起工作?
本文关键字:一起 工作 动画 绑定 不能 为什么 | 更新日期: 2023-09-27 18:08:42
我有一个动画绑定属性的简单问题。下面是一个简单的例子来说明它:
ViewModel:
public class ViewModel
{
private double myProperty;
public double MyProperty
{
get { return myProperty; }
set { myProperty = value; /* Break point here */ }
}
public ViewModel()
{
MyProperty = 20;
}
}
MyControl:
public class MyControl : Button
{
protected override void OnClick()
{
base.OnClick();
Height = ActualHeight + 20;
}
}
MyAnimatedControl:
public class MyAnimatedControl : Button
{
protected override void OnClick()
{
base.OnClick();
DoubleAnimation a = new DoubleAnimation(ActualHeight + 20, new Duration(TimeSpan.FromMilliseconds(500)));
this.BeginAnimation(HeightProperty, a);
}
}
主窗口:
public partial class MainWindow : Window
{
public MainWindow()
{
DataContext = new ViewModel();
InitializeComponent();
}
}
<Grid>
<StackPanel>
<local:MyAnimatedControl Height="{Binding MyProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Content="Animated"/>
<local:MyControl Height="{Binding MyProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Content="Normal 1"/>
<local:MyControl Height="{Binding MyProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Content="Normal 2"/>
</StackPanel>
</Grid>
我有两个继承自Button的控件(MyControl和MyAnimatedControl),它们的Height属性被绑定(mode two way)到ViewModel中的MyProperty属性。
当控件被单击时,它们会增长其Height属性。MyControl给它赋一个新值,MyAnimatedControl使它动画化。
问题:
当我点击其中一个MyControl时,绑定工作正确,所有控件的高度更新,断点在ViewModel中工作。但是当我点击MyAnimatedControl时,绑定似乎不再工作了:它单独生长,绑定不再工作,而两个正常的控件仍然一起生长。它不再与其他控件共享相同的高度。
是否有一种方法可以对动画依赖属性进行操作绑定,从而在动画过程中更新ViewModel ?我读了这篇文章,但它没有回答。
谢谢。
问题是动画具有更高的优先顺序,因此当它应用于任何属性时,该属性的后续更改将不会反映在UI和绑定中。
如本文所述,您可以使用三种方法解决此问题:- 设置动画的FillBehavior为Stop
- 删除整个storyBoard。
- 从单个属性中移除动画。
在你的情况下,我们可以使用第三个选项在动画完成后从高度DP中删除动画。
第二,你应该调用SetCurrentValue方法来设置DP,它将更新绑定,从而更新绑定的ViewModel属性。
在<<p>把所有strong>
Completed
的 DoubleAnimation
: public class MyAnimatedControl : Button
{
protected override void OnClick()
{
base.OnClick();
DoubleAnimation a = new DoubleAnimation(ActualHeight + 20,
new Duration(TimeSpan.FromMilliseconds(500)));
a.Completed += (s, e) =>
{
BeginAnimation(Button.HeightProperty, null); // Remove animation.
SetCurrentValue(Button.HeightProperty, ActualHeight); // Set value.
};
this.BeginAnimation(Button.HeightProperty, a);
}
}
还确保您的ViewModel正在实现INotifyPropertyChanged和属性更改事件是从 MyProperty
setter引发的
问题似乎是动画属性同时也是绑定的源。为了解决这个问题,你可以创建另一个高度属性(例如MyHeight
),当控件的高度发生变化时,它就会被更新,并作为OneWayToSource
绑定的目标。
public class MyAnimatedControl : Button
{
public static readonly DependencyProperty MyHeightProperty =
DependencyProperty.Register(
"MyHeight", typeof(double), typeof(MyAnimatedControl));
public double MyHeight
{
get { return (double)GetValue(MyHeightProperty); }
set { SetValue(MyHeightProperty, value); }
}
protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
base.OnRenderSizeChanged(sizeInfo);
MyHeight = sizeInfo.NewSize.Height;
}
}
绑定:
<local:MyAnimatedControl ...
MyHeight="{Binding MyProperty, Mode=OneWayToSource}"
Height="{Binding MyProperty, Mode=OneWay}"/>
为了更新其他绑定目标,还需要在视图模型中实现
INotifyPropertyChanged
接口:
public class ViewModel : INotifyPropertyChanged
{
private double myProperty = 30;
public double MyProperty
{
get { return myProperty; }
set
{
myProperty = value;
RaisePropertyChanged("MyProperty");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
最后,正如Rohit Vats在他的回答中所写的,你需要在Completed事件处理程序中删除Height属性上的动画:
protected override void OnClick()
{
base.OnClick();
DoubleAnimation a = new DoubleAnimation(ActualHeight + 20,
new Duration(TimeSpan.FromMilliseconds(500)));
a.Completed += (s, e) =>
{
BeginAnimation(Button.HeightProperty, null); // Remove animation.
SetCurrentValue(Button.HeightProperty, ActualHeight); // Set value.
};
this.BeginAnimation(Button.HeightProperty, a);
}
Control.Height
属性是一个DependencyProperty
和DependencyProperty
s可以从各种来源设置,例如:Style Setter
, Animation
,从代码等。由于这个原因,微软必须定义一个优先顺序来决定哪些可能的方法来改变DependencyProperty
的值比其他的更重要。
从逻辑上决定,从Animation
设置DependencyProperty
,就像你在例子中所做的那样,应该"覆盖"从其他来源设置的值,例如。从属性设置器。有关DependencyProperty
值优先级列表的完整信息,请参阅MSDN上的依赖属性值优先级页面。
Button
,看到它的大小在不断增长。因此,如果您不能做到这一点,那么我怀疑您在某个地方有其他代码干扰了这一点。如果这不是你的问题,那么请清楚地解释什么是。
更新>>>
哦,我想我现在明白你想要什么了…您想知道为什么当Animation
动画属性值时不调用属性setter。然而,这将不起作用,因为Animation
不会永久改变属性值。来自动画概述页面的数据绑定和动画动画部分:
大多数动画属性可以是数据绑定或动画;例如,您可以动画
DoubleAnimation
的Duration
属性。然而,由于计时系统的工作方式,数据绑定或动画动画的行为与其他数据绑定或动画对象不同。