I'm currently struggling with DependencyProperties in WPF. Full code can be found here: https://github.com/JYPDWhite/WPFValueCorrectionTest
In this code I have 2 problems that I can't figure out how to fix.
The code contains a OwnControl which is derived from UserControl, it contains a DependencyPropertyNumber aka NumberProperty.
There is a coerceValueCallback registered that coerce the given number to 0 when the given value is >5.
public static readonly DependencyProperty NumberProperty = DependencyProperty.Register(
nameof(Number),
typeof(int),
typeof(OwnControl),
new FrameworkPropertyMetadata(
defaultValue: 2,
flags: FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
propertyChangedCallback: PropertyChangedCallback,
coerceValueCallback: CoerceNumberValue));
private static object CoerceNumberValue(DependencyObject d, object baseValue)
{
OwnControl depObject = (OwnControl)d;
var newValue = (int)baseValue;
var correctedNumber = depObject.CheckNumber(newValue);
return correctedNumber;
}
public int Number
{
get { return (int)GetValue(dp: NumberProperty); }
set { SetValue(dp: NumberProperty, value); }
}
private int CheckNumber(int newValue)
{
if (newValue < 5)
{
return newValue;
}
return 0;
}
The coerced value is correctly saved in the OwnControl, to propagate the correction back to the View Model I use this propertyChangedCallback where the Binding is updated using BindingOperations.
private static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (!Equals(e.OldValue, e.NewValue))
{
d.SetCurrentValue(dp: NumberProperty, e.NewValue);
d.Dispatcher.BeginInvoke(new Action(() =>
{
var be = BindingOperations.GetBindingExpression((OwnControl)d, dp: NumberProperty);
if (be == null)
{
Debug.WriteLine("Istnull");
}
be?.UpdateSource();
}), DispatcherPriority.ContextIdle);
}
}
This seems to work just fine. If I enter 2 as input the ViewModel and the OwnControl get the correct value. Then I enter 5 the value is getting coerced and the change is reflected in OwnControl and in the ViewModel.
But when I now enter for example 6 (replacing the the 0 in the input field) I see that the coercing is executed and the OwnControl get the correct value 0.
But the debugger is not running through the PropertyChangedCallback and so also in the ViewModel 6 is still the stored value.
Question 1: Why is the updating of the coerced value failing when I enter a "wrong" number repeatedly?
Question 2: In the DependencyProperty.Register the defaultValue is set to 2 but upon startup I can see in the debuger when hitting Breakpoint in PropertyChangedCallback that initally the value is set to 2 but the first hit of the debugger in den PropertyChangedCallback oldValue is 2 and newValue is 0. From where is the 0 comming?