How can one register a dependency property whose value is calculated using the value of another dependency property?
Because the .NET property wrappers are bypassed by WPF at run-time, one should not include logic in the getters and setters. The solution to that is typically to use PropertyChangedCallback
s. But those are declared static.
For example, what is the proper way to accomplish this contrived task:
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));
As long as the dependency is not circular, is there a proper means to accomplish this?
Hmmm... I think you'd better look at dependency properties value coercion. Here is an example with coercion:
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));
}
}
You're actually correct, you should use PropertyChangedCallback. Here's how:
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));