INotifyPropertyChanged没有做任何事情

时间:2016-10-11 14:46:31

标签: c# wpf mvvm data-binding

我现在拥有的是扩展WPF工具包拾色器。当我在颜色选择器中选择颜色时,边框的颜色会更改为所选颜色。现在可以使用,请参阅以下gif:

enter image description here

有一些问题。当我删除INotifyPropertyChanged界面和OnPropertyChanged()方法时,一切仍然正常(为什么?!它不应该,对吧?)

此外,当我在MyStyle类的BackgroundColor属性的setter中添加断点时,该属性不会更新。它应该更新,因为我将它绑定到以下行:b.Path = new PropertyPath(nameof(BackgroundColor));

我的问题是:

  1. 当我删除所有INotifyPropertyChanged内容时,为什么这一切仍然有用
  2. 当我更改颜色时,为什么我的对象的BackgroundColor属性不会更新(为什么它不会触及setter断点)
  3. 我有以下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));
            }
        }
    }
    

    适用于以下型号:

    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);
        }
    }
    

    然后MyStyle是一个带有一堆属性的抽象类,比如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; }
    
      .....
    }
    

    修改

    它会更新BoxViewModel.BackgroundColor属性,并在更改颜色时调用这些setter和getter。 MyStyle.BackgroundColor没有任何改变也没有改变。它与数据上下文或绑定属性有什么关系吗?来自mystyle类的BackgroundColor字符串和BackgroundColors都应该更改。

2 个答案:

答案 0 :(得分:2)

查看this

  

很抱歉花了这么长时间回复,实际上你遇到了WPF的另一个隐藏方面,就是它WPF的数据绑定引擎将数据绑定到PropertyDescriptor实例,如果源对象是普通CLR,它将包装source属性对象并没有实现INotifyPropertyChanged 接口。数据绑定引擎将尝试通过PropertyDescriptor.AddValueChanged()方法订阅属性更改事件。当目标数据绑定元素更改属性值时,数据绑定引擎将调用PropertyDescriptor.SetValue()方法将更改后的值传回源属性,并且它将同时引发ValueChanged事件以通知其他订阅者(在本例中,其他订阅者将是ListBox中的TextBlock。

     

如果您正在实施INotifyPropertyChanged,那么您完全有责任在需要绑定到UI的数据的每个属性集中实现更改通知。否则,更改将不会像您期望的那样同步。

     

希望这会让事情稍微清楚一点。

所以基本上你可以做到这一点,只要它是一个普通的CLR对象。

答案 1 :(得分:2)

这似乎是WPF绑定引擎的一个功能。它检测到您有多个绑定到数据源(VM)的同一实例的控件,并且这些绑定中的至少一个处于TwoWay模式。当绑定更新源属性时,绑定引擎会自动更新其他绑定控件,而无需任何通知。

对于不通过绑定发起的更改(代码中执行的更改),将需要INotityPropertyChanged。

我用一个简单的WPF应用程序对此进行了测试,该应用程序有两个文本框绑定(双向)到没有INPC实现的POCO视图模型。更新任一文本框都会更改另一个文本框的内容,而没有明显的通知机制。