WPF PropertyChange不级联 - 动画一个自定义类dependencyproperty更改其他属性 - PropertyChange仅触发第一个

时间:2009-09-21 00:03:52

标签: c# wpf animation binding inotifypropertychanged

非常简化,这是我的问题:(底部的解决方案)

我有一个自定义类,继承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构造函数中完成。谢谢大家!

谢谢!

/维克多

4 个答案:

答案 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); 
    }
}