wpfbindingnotificationscustom-controls

WPF: Why is callback function not called with binding mode OneWay?


I have create a custom control with some properties, all seems to work as excepted.

But after some tests, I found a strange behavior which I don't understand. When I bind the property in OneWay mode, the callback of the property is not called... at least the property is not updated.

My property is defined as follow:

public uint ActiveLeds
{
   get { return (uint)GetValue(ActiveLedsProperty); }
   set { SetValue(ActiveLedsProperty, value); }
}

public static readonly DependencyProperty ActiveLedsProperty =
   DependencyProperty.Register(
       nameof(ActiveLeds),
       typeof(uint),
       typeof(LedControl),
       new FrameworkPropertyMetadata
       {
           DefaultValue = 0u,
           PropertyChangedCallback = new PropertyChangedCallback(ActiveLedsChanged),
           DefaultUpdateSourceTrigger = System.Windows.Data.UpdateSourceTrigger.PropertyChanged,
           BindsTwoWayByDefault = true
       });
private static void ActiveLedsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
   var c = d as LedControl;
   c.ActiveLeds = (uint)e.NewValue;
   c.UpdateLeds();
}

Binding is also really common, and works:

<local:LedControl  ActiveLeds="{Binding LedsOn}" />

But if I change the binding to OneWay, the callback function ActiveLedsChanged in my custom control is not called anymore.

<local:LedControl  ActiveLeds="{Binding LedsOn, Mode=OneWay}" />

Is this normal or did I do something wrong?

Note: LedsOn is a property from a class which implements INotifyPropertyChanged interface.


Solution

  • When you assign a new so-called local value to a dependency property that is currently bound OneWay, the Binding is removed. This does not happen when the Binding is TwoWay.

    You are assigning a new local value in the PropertyChangedCallback:

    private static void ActiveLedsChanged(
        DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var c = d as LedControl;
        c.ActiveLeds = (uint)e.NewValue; // here
        c.UpdateLeds();
    }
    

    The assignment is redundant, because the property does already have the assigned value. Change the callback method like shown below.

    Also note that you should use an explicit cast instead of the as operator. When using as, you must check the result for null. Otherwise you get a NullReferenceException instead of a more appropriate InvalidCastException.

    private static void ActiveLedsChanged(
        DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ((LedControl)d).UpdateLeds();
    }