依赖属性取决于另一个属性。

26

如何注册一个依赖属性,其值是使用另一个依赖属性的值计算出来的?

因为在运行时,WPF会绕过.NET属性包装器,所以不应在getter和setter中包含逻辑。解决方案通常是使用PropertyChangedCallback。但这些是静态声明的。

例如,如何正确完成这个假想任务:

public bool TestBool
{
  get { return (bool)GetValue(TestBoolProperty); }
  set 
  { 
    SetValue(TestBoolProperty, value);
    TestDouble = ((value)?(100.0):(200.0)); // HERE IS THE DEPENDENCY
  }
}
public static readonly DependencyProperty TestBoolProperty =
  DependencyProperty.Register("TestBool", typeof(bool), typeof(ViewModel));

public double TestDouble
{
  get { return ((double)GetValue(TestDoubleProperty)); }
  set { SetValue(TestDoubleProperty, value); }
}
public static readonly DependencyProperty TestDoubleProperty =
  DependencyProperty.Register("TestDouble", typeof(double), typeof(ViewModel));
只要依赖关系不是循环的,是否有适当的方法来实现这一点?
2个回答

26

哦,我认为你最好看一下依赖属性的值协同。这里有一个带有协同的例子:

public class ViewModel : DependencyObject
{
  public bool TestBool
  {
    get { return (bool)GetValue(TestBoolProperty); }
    set { SetValue(TestBoolProperty, value); }
  }
  public static readonly DependencyProperty TestBoolProperty =
    DependencyProperty.Register("TestBool", typeof(bool), typeof(ViewModel), new PropertyMetadata(false, OnTestBoolPropertyChanged));

  private static void OnTestBoolPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  {
    var vm = (ViewModel)d;
    vm.CoerceValue(TestDoubleProperty);
  }

  public double TestDouble
  {
    get { return ((double)GetValue(TestDoubleProperty)); }
    set { SetValue(TestDoubleProperty, value); }
  }
  public static readonly DependencyProperty TestDoubleProperty =
    DependencyProperty.Register("TestDouble", typeof(double), typeof(ViewModel), new PropertyMetadata(0.0, null, OnCoerceTestDouble));

  private static object OnCoerceTestDouble(DependencyObject d, object baseValue)
  {
    var vm = (ViewModel) d;
    var testBool = vm.TestBool;
    return ((testBool) ? (100.0) : (200.0));
  }
}

使用CoerceValueCallback的优点是什么,与opedog直接在另一个依赖属性的PropertyChangedCallback中更改依赖属性相比有何不同?从您链接的文档中我了解到,您的方法更为正确,但我很想知道实际上的区别。 - Gregyski
1
好的,举几个例子:它不会破坏此属性的绑定(即,如果此属性是绑定表达式的目标,则在强制转换后它将继续工作,但在显式设置后将丢失);它在依赖属性值解析中具有较高的优先级(即,如果您说PropA="Something"并不意味着PropA=="Something",因为强制转换可能会忽略该赋值);它会记住属性的旧值(即,下次调用CoerceValue()时,您将获得TestDouble的原始值,而不是本地设置的值)。 - Anvaka

1

你说得对,你应该使用PropertyChangedCallback。以下是方法:

public bool TestBool
{
  get { return (bool)GetValue(TestBoolProperty); }
  set 
  { 
    SetValue(TestBoolProperty, value);
  }
}
public static readonly DependencyProperty TestBoolProperty =
  DependencyProperty.Register("TestBool", typeof(bool), typeof(ViewModel),
  new PropertyMetadata(false, new PropertyChangedCallback(OnTestBoolChanged)));

private static void OnTestBoolChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
  ViewModel vm = d as ViewModel;
  vm.TestDouble = value ? 100.0 : 200.0;
}

public double TestDouble
{
  get { return ((double)GetValue(TestDoubleProperty)); }
  set { SetValue(TestDoubleProperty, value); }
}
public static readonly DependencyProperty TestDoubleProperty =
  DependencyProperty.Register("TestDouble", typeof(double), typeof(ViewModel));

谢谢opedog。在我的调查中,我愚蠢地没有检查PropertyChangedCallback传递了什么。我调整了我的测试项目以使用此方法,并且它正在工作。接下来我将尝试Anvaka的解决方案。 - Gregyski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接