holland
holland

Reputation: 2182

INotifyPropertyChanged not doing anything

What I'm having right now is a Extended WPF Toolkit Color Picker. When I select a color in the color picker, the color of the border gets changed to the chosen color. This works right now, see the following gif:

enter image description here

There are a few things wrong. When I remove the INotifyPropertyChanged interface and the OnPropertyChanged() method, everything still works fine (why?! It shouldn't, right?)

Also, when I add a breakpoint at the setter of the BackgroundColor property in my MyStyle class, the property doesn't get updated. It should update because I bind it with the following line: b.Path = new PropertyPath(nameof(BackgroundColor));

My questions are:

  1. Why does this all still work when I delete all the INotifyPropertyChanged stuff
  2. Why doesn't the BackgroundColor property of my object update when I change the color (why doesn't it hit the setter breakpoint)

I have the following ViewModel:

public class BoxViewModel : INotifyPropertyChanged
{
    private string _backgroundcolor;

    public string Description { get; set; }
    public string BackgroundColor
    {
        get
        {
            return _backgroundcolor;
        }
        set
        {
            _backgroundcolor = value;
            OnPropertyChanged();
        }
    }

    /// <summary>
    /// Occurs when [property changed].
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Which works with the following model:

public class Box : MyStyle
{
    Canvas _label;
    Border _border;
    string _description;
    BoxViewModel vm;

    public override void Draw(Canvas label)
    {
        _label = label;
        _border = new Border();

        _border.BorderBrush = BorderColorBrush;
        _border.Background = BackgroundColorBrush;

        _border.Width = Width;
        _border.Height = Height;

        //

        _border.DataContext = vm;

        Binding b = new Binding();
        b.Source = vm;
        b.Path = new PropertyPath(nameof(BackgroundColor));
        b.Mode = BindingMode.TwoWay;
        b.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;

        BindingOperations.SetBinding(_border, Border.BackgroundProperty, b);

        label.Children.Add(_border);

    }

    internal override void AddInputs(ItemsControl inputPanel)
    {
        vm = new BoxViewModel()
        {
            Description = _description,
            BackgroundColor = BackgroundColor                
        };

        inputPanel.Items.Add(vm);
    }
}

And then MyStyle is an abstract class with a bunch of properties, like the BackgroundColor one:

public abstract class MyStyle
{
    string _BackgroundBrush;
    string _BackgroundColor;
  .....
    public string BorderColor
    {
        get { return _BorderColor; }
        set
        {
            _BorderColor = value;
            BorderColorBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString(value != null ? BorderColor : "#FFFFFFFF"));
        }
    }
    public SolidColorBrush BorderColorBrush { get; set; }


    public string BackgroundColor { 
        get { return _BackgroundColor; }
        set {
            _BackgroundColor = value;
            BackgroundColorBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString(value != null ? BackgroundColor : "#FFFFFFFF"));
        }
    }
    public SolidColorBrush BackgroundColorBrush { get; set; }

  .....
}

Edit

It does update the BoxViewModel.BackgroundColor property and those setters and getters are being called when the color is changed. Still nothing happens with the MyStyle.BackgroundColor isn't being changed. Does it have something to do witht he data context or the binding property or something? Both the BackgroundColor string and BackgroundColors from the mystyle class should change.

Upvotes: 2

Views: 861

Answers (2)

Chris Shain
Chris Shain

Reputation: 51369

This appears to be a feature of the WPF binding engine. It detects that you have multiple controls bound to the same instance of a data source (VM), and at least one of those bindings is in TwoWay mode. When the binding updates the source property, the binding engine automatically updates the other bound controls without any need for notification.

INotityPropertyChanged would be needed for changes that do not originate via a binding (changes performed in code).

I've tested this with a simple WPF application that has two text boxes bound (two-way) to a POCO view model with no INPC implementation. Updating either textbox changes the content of the other, with no apparent notification mechanism.

Upvotes: 2

R.Rusev
R.Rusev

Reputation: 1141

Have a look at this.

Sorry to take so long to reply, actually you are encountering a another hidden aspect of WPF, that's it WPF's data binding engine will data bind to PropertyDescriptor instance which wraps the source property if the source object is a plain CLR object and doesn't implement INotifyPropertyChanged interface. And the data binding engine will try to subscribe to the property changed event through PropertyDescriptor.AddValueChanged() method. And when the target data bound element change the property values, data binding engine will call PropertyDescriptor.SetValue() method to transfer the changed value back to the source property, and it will simultaneously raise ValueChanged event to notify other subscribers (in this instance, the other subscribers will be the TextBlocks within the ListBox.

And if you are implementing INotifyPropertyChanged, you are fully responsible to implement the change notification in every setter of the properties which needs to be data bound to the UI. Otherwise, the change will be not synchronized as you'd expect.

Hope this clears things up a little bit.

So basically you can do this, as long as its a plain CLR object.

Upvotes: 2

Related Questions