MVVM INotifyPropertyChanged与基类PropertyChange冲突

本文关键字:PropertyChange 冲突 基类 INotifyPropertyChanged MVVM | 更新日期: 2023-09-27 18:21:39

我对MVVM还比较陌生,我正在努力了解INotifyPropertyChanged接口是如何工作的,以及如何在我的模型中实现它。我决定采用的方法是在我的每个业务对象类中实现它
该方法的问题在于,当我将视图绑定到基类中的属性时,该基类中的PropertyChanged事件永远不会初始化(为null),因此当我的Model更改时,视图不会刷新该元素的数据。我能够用下面的例子重现这个问题。

我有一个基本类:

 public class Person : INotifyPropertyChanged
    {
        #region INotifyProperty
        public event PropertyChangedEventHandler PropertyChanged;
        public void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion
        public String Name
        {
            get
            {
                return _name;
            }
            set
            {
                _name = value;
                RaisePropertyChanged("Name");
            }
        }
        private String _name;
    }

我有一个Employee类继承自我的Person基类:

 public class Employee : Person,INotifyPropertyChanged
    {
        #region INotifyProperty
        public event PropertyChangedEventHandler PropertyChanged;
        public void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion

        public String EmployeeID
        {
            get
            {
                return _employeeId;
            }
            set
            {
                _employeeId = value;
                RaisePropertyChanged("EmployeeID");
            }
        }
        private String _employeeId;
    }

这里我的看法模型:

 public class ViewModel : ViewModelBase<ViewModel>
    {
        private Employee _employee;
        public ViewModel()
        {
            ChangeModelCommand = new RelayCommand(param=>this.ChangeModel() , param=>this.CanChangeModel);
            Employee = new Employee()
                         {
                             Name = "BOB",EmployeeID = "1234"
                         };
        }
        public ICommand ChangeModelCommand { get; set; }

        public Employee Employee
        {
            get
            {
                return _employee;
            }
            set
            {
                this._employee = value;
                NotifyPropertyChanged(m=>m.Employee);
            }
        }
        public void ChangeModel()
        {
            MessageBox.Show("CHANGING MODEL");
            this.Employee.Name = "MIKE";
            this.Employee.EmployeeID = "5678";
        }
        public bool CanChangeModel
        {
            get{ return true;}
        }
    }

最后我的观点:

<Window.Resources>
    <MVVM_NotificationTest:ViewModel x:Key="Model"></MVVM_NotificationTest:ViewModel>
</Window.Resources>
<Grid DataContext="{StaticResource Model}">
<StackPanel>
    <Label Content="Employee Name"/>
    <TextBox Text="{Binding     Path=Employee.Name,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
    <Label Content="Employee ID"/>
    <TextBox Text="{Binding Path=Employee.EmployeeID,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
    <Button Content="Change Model" Height="30" Width="100" Margin="5" Command="{Binding Path=ChangeModelCommand}"/>
</StackPanel>
</Grid>

在这个例子中,我在VM构造函数中初始化我的Employee VM属性,然后我有一个命令来修改EmployeeID(来自Employees类)和Name(来自Person类)。但是,View中唯一更新的UI元素是EmployeeID,而不是Name(我希望Bob更新为Mike)

调试时,我发现PropertyChanged事件在基类(Person)中始终为null。我还注意到,当我从Employee类中删除整个#INotifyProperty区域时,一切都很好,因为它使用的是Base-Type事件和方法

我遇到的问题是,我当前的所有模型类都显式地实现了INotifyPropertyChanged。它们都定义了PropertyChanged事件并实现了RaisePropertyChanged方法,这显然会影响我在MVVM应用程序中的绑定

最后,我想澄清一下,我不想在ViewModel中包装我的Model属性,也不想依赖VM INPC机制。我想使用我的模型INPC实现,而不必根据我是否从基类型继承来有条件地删除INPC实现。

总之,我想知道在我的深层结构模型中实现INPC的最佳方式是什么,这样继承就不会像我们在本例中看到的那样破坏PropertyEvent传播,并且我的独立类也可以是自给自足的。任何想法或建议都将不胜感激:)

MVVM INotifyPropertyChanged与基类PropertyChange冲突

只需使RaisePropertyChanged受到保护并将其移动到基类中。目前,您将有很多不必要的重复。

类似这样的东西:

protected virtual void RaisePropertyChanged(string propertyName);

许多MVVM框架都为您提供了这一点。例如,PRISM有一个NotificationObject ViewModel基类。

您应该只实现INPC一次,您可以在子类中使用相同的提升方法。

我还将更改raise属性更改方法,以使用反射,而不是传入硬编码字符串。我看到你在视图模型中做了这件事,但在你的模型中没有(大多数错误往往发生在那里)。