0

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

我有一个自定义类,继承 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 动画似乎完全跳过了属性获取和设置,动画并读取了底层的依赖属性......还是我误解了?我使用的动画代码是:

DoubleAnimation da = new DoubleAnimation (1, 10, new Duration(TimeSpan.FromSeconds(3)));
myClassInstance.BeginAnimation(MyClass.AnimateValueProperty, da);

嗯……在这里写完代码之后,不使用 setter 似乎很合理(尽管我真的很希望这样!) - 但是,基本问题仍然存在,我仍然不明白为什么不使用 getter!

编辑2:解决方案!

正如下面所建议的,我不能将 INotifyPropertyChange 用于连接到 DependencyProperty 的属性 - 动画和 XAML 在内部使用 DependencyProperty 并且根本不使用 getter 和 setter。

因此 - PropertyChangedCallback 通知其他人发生变化, CoerceValueCallback 来“修复”数据。也可以验证数据,所有这些都在 DependencyProperty 构造函数中完成。谢谢大家!

谢谢!

/胜利者

4

4 回答 4

2

通过设置 AnimateValue 的值,您是在告诉 WPF 它已更改。但是您永远不会告诉 WPF GuiValue 已更改。当您不告诉它时,WPF 数据绑定框架应该如何知道 GuiValue 已更改?

当您更新 AnimateValue 并发出更改通知(这本身不是必需的,因为它是一个依赖属性)时,您还需要发出有关 GuiValue 的通知,因为它依赖于 AnimateValue 但在属性内手动计算。

基本上只是添加

OnPropertyChanged(new PropertyChangedEventArgs("GuiValue"));

到 AnimateValue 设置块。

更新:

根据您的新编辑,如果通过 XAML 进行属性设置,则永远不会调用依赖属性的 getter/setter,这一切都是直接通过 GetValue/SetValue 完成的。

如果您需要在本地响应更改,请覆盖 OnPropertyChanged 或在 DependencyProperty.Register 中提供更改回调

于 2009-09-21T00:12:10.130 回答
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");
  }

我有一种感觉,但不完全确定,你可能需要做的是强制其他价值观。看看本文中的强制值回调部分

于 2009-09-21T05:49:09.033 回答
1

我不确定我是否明白你的意思。但看看这是否有帮助。

    public double AnimateValue {
    get { return (double)GetValue(AnimateValueProperty); }
    set {
            SetValue(AnimateValueProperty, value);
            OnPropertyChanged(new PropertyChangedEventArgs("AnimateValue"));
            OnPropertyChanged(new PropertyChangedEventArgs("GuiValue "));
        }
    }
}
于 2009-09-21T00:11:43.937 回答
1

如果您的对象是从 Dependency Object 派生的,那么您不能使用 INotifyPropertyChanged,因为 Binding 体系结构只会使用 Dependency Property 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); 
    }
}
于 2009-09-21T06:36:35.080 回答