非常简化,这是我的问题:(底部的解决方案)
我有一个自定义类,继承Animatable和INotifyPropertyChange,包含一个DependencyProperty(我的动画,比如从1到10)和一个额外的属性(我想从带有绑定的XAML中使用):
MyClass : Animatable, INotifyPropertyChanged {
public static DependencyProperty AnimateValueProperty = DependencyProperty.Register(
"AnimateValue",
typeof(double),
typeof(MyClass)
);
public double AnimateValue {
get { return (double)GetValue(AnimateValueProperty); }
set {
SetValue(AnimateValueProperty, value);
OnPropertyChanged(new PropertyChangedEventArgs("AnimateValue"));
OnPropertyChanged(new PropertyChangedEventArgs("GuiValue")); //Added in edit
}
}
}
public double GuiValue {
get {
return AnimateValue + 10;
//More fancy stuff happening in the real class...
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) {
if (PropertyChanged != null) {
PropertyChanged(this, e);
}
}
protected override Freezable CreateInstanceCore() {
return new MyClass();
}
}
当我将GUI元素绑定到属性时,我实际上是动画(AnimateValue),一切都按预期工作 - 当我将GUI元素绑定到相关属性(GuiValue)时,没有任何反应。我想改变的事件没有达到那个属性,但我真的不知道如何解决这个问题。有什么指针吗?
非常感谢任何帮助!
编辑:感谢Adam Sills和Kai Wang的两个回复,愚蠢的我没有留下第二个OnPropertyChange电话,但是我之前尝试过,但它没有用。为了调试,我在AnimateValue.set函数中放了一个写字符,看哪 - 它根本没有执行!
我也试过改变吸气剂总是返回20 - 没有变化! :-o似乎动画完全跳过属性get和set并动画并读取底层依赖属性...或者我误解了?我使用的动画代码是:
DoubleAnimation da = new DoubleAnimation (1, 10, new Duration(TimeSpan.FromSeconds(3)));
myClassInstance.BeginAnimation(MyClass.AnimateValueProperty, da);
嗯...在这里编写代码之后,似乎非常合理的是没有使用setter(虽然我真的很喜欢它!) - 但是,基本问题仍然存在,我仍然不明白为什么吸气剂是没用过!
Edit2: 解决方案!
如下所示,我无法将INotifyPropertyChange用于连接到DependencyProperty的属性 - 动画和XAML在内部使用DepencencyProperty,根本不使用getter和setter。
因此 - PropertyChangedCallback在更改时通知其他人,CoerceValueCallback“修复”数据。也可以验证数据,所有这些都在DependencyProperty构造函数中完成。谢谢大家!
谢谢!
/维克多
答案 0 :(得分:2)
通过设置AnimateValue的值,您告诉WPF它已更改。但是你永远不会告诉WPF GuiValue已经改变了。当你不告诉它时,WPF数据绑定框架如何知道GuiValue已经改变了?
当您更新AnimateValue并提出更改通知时(由于它是依赖属性,它本身不是必需的),您还需要提出有关GuiValue的通知,因为它依赖于AnimateValue但是在内部手动计算属性。
基本上只需添加
OnPropertyChanged(new PropertyChangedEventArgs("GuiValue"));
到AnimateValue设置块。
<强>更新强>
根据您的新编辑,如果通过XAML进行属性设置,则永远不会调用依赖项属性的getter / setter,而是直接通过GetValue / SetValue完成。
如果您需要在本地响应更改,请覆盖OnPropertyChanged或在DependencyProperty.Register中提供更改回调
答案 1 :(得分:2)
这是一个属性更改的通知模式,用于依赖属性
public Boolean PasswordBoxVisible {
get { return (Boolean)GetValue(PasswordBoxVisibleProperty); }
set { SetValue(PasswordBoxVisibleProperty, value); }
}
public static readonly DependencyProperty PasswordBoxVisibleProperty =
DependencyProperty.Register("PasswordBoxVisible", typeof(Boolean), typeof(UserControl), new UIPropertyMetadata(false, new PropertyChangedCallback(PropChanged)));
//this method is called when the dp is changed
static void PropChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) {
UserControl userControl = o as UserControl;
//now you can use this to call some methods, raise other value changed etc, in this case OtherProperty.
userControl.NotifyPropertyChanged("OtherProperty");
}
我有一种感觉,但我不完全确定,你可能需要做的是强迫其他价值观。 have a look at the coerce value callback section in this article
答案 2 :(得分:1)
我不确定我是否明白你的意思。但看看这是否有帮助。
public double AnimateValue {
get { return (double)GetValue(AnimateValueProperty); }
set {
SetValue(AnimateValueProperty, value);
OnPropertyChanged(new PropertyChangedEventArgs("AnimateValue"));
OnPropertyChanged(new PropertyChangedEventArgs("GuiValue "));
}
}
}
答案 3 :(得分:1)
如果您的对象是从Dependency Object派生的,那么您不能使用INotifyPropertyChanged,因为Binding架构只会使用依赖属性Resgistration才能使用绑定。
为此你需要只读依赖属性,我已经解释如下。
public static DependencyProperty AnimateValueProperty =
DependencyProperty.Register(
"AnimateValue",
typeof(double),
typeof(MyClass)
);
// This is for the Readonly GuiValueKey property
public static DependencyPropertyKey GuiValueKey =
DependencyProperty.RegisterReadOnly (
"GuiValue",
typeof(double),
typeof(MyClass),
new UIPropertyMetadata(0.0)
);
public double AnimateValue {
get { return (double)GetValue(AnimateValueProperty); }
set {
SetValue(AnimateValueProperty, value);
// Following statement update GuiValue wherever it
// is binded
this.SetValue(GuiValueKey,value + 10);
}
}
}
// you dont even need following line...
// but its good to have it..
public double GuiValue {
get {
return (double)this.GetValue(GuiValueKey);
}
}