Should INotifyPropertyChanged also be implemented on model level?

时间:2018-06-18 11:42:00

标签: c# wpf mvvm inotifypropertychanged

Let's say I have a view model called MyViewModel which is implemented like this:

public class MyViewModel : BindableBase
{
    // BindableBase implements INotifyPropertyChanged
    // through the method SetProperty() which works fine.       
    private string _viewModelProperty
    public string ViewModelProperty 
    {
        get { return _viewModelProperty; }
        set { SetProperty(ref _viewModelProperty, value); } 
    }

    private NestedObjectModel _nestedObject;
    public NestedObjectModel NestedObject
    {
        get { return _nestedObject; }
        set { SetProperty(ref _nestedObject, value); }
    }
}

As you can see it contains two properties. One string, and one object (without getting into semantics about whether a string is also an object). The object (or model) has some properties as well, but these are not directly implemented with INotifyPropertyChanged as the view model. It could look like this:

public class NestedObjectModel
{
    public string Text { get; set; }
    public double Number { get; set; }
}

What I would like to do, is to use the INotifyPropertyChanged in the view model, to notify when the model changes (i.e. if either Text or Number is changed by a method in the view model). It could look something like this:

// This method is located in the view model
public void ChangeTextInNestedObject(string newText)
{
    NestedObject.Text = newText;
    OnPropertyChanged(nameof(NestedObject));
}

Problem is, that I cannot get this to work. The value is changed, but the XAML doesn't reach to the changes. I have also tried to add a property specific notice:

OnPropertyChanged(nameof(NestedObject.Text));

Is it not possible to do it this way? Do I really have to implement INotifyPropertyChanged on model level as well?

1 个答案:

答案 0 :(得分:0)

它应该工作。 WPF始终对PropertyChanged事件做出反应。但是,您的MVVM框架可能会比较OnPropertyChanged方法中的旧值和新值,并且如果它们相同则不会引发事件。也许有一些参数会强制举起活动,如果没有,你可以自己举起PropertyChanged活动。

请参阅viewmodel的以下代码:

using System.ComponentModel;
using WpfApp1.Model;

namespace WpfApp1.Model
{
    public class NestedObjectModel
    {
        public string Text { get; set; }
        public double Number { get; set; }
    }
}

namespace WpfApp1.ViewModels
{
    class MyViewModel: INotifyPropertyChanged
    {
        private string _viewModelProperty;
        private NestedObjectModel _nestedObject;
        public event PropertyChangedEventHandler PropertyChanged;

        public string ViewModelProperty
        {
            get { return _viewModelProperty; }
            set {
                _viewModelProperty = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("ViewModelProperty"));
                ChangeTextInNestedObject(value);
            }
    }

    public NestedObjectModel NestedObject
    {
        get { return _nestedObject; }
        set {
            _nestedObject = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("NestedObject"));
        }
    }

    public MyViewModel()
    {
        _nestedObject = new NestedObjectModel() { Text = "TExt", Number = 321.1 };
    }

    public void ChangeTextInNestedObject(string newText)
    {
        _nestedObject.Text = newText;
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("NestedObject"));
    }
    }
}

MainWindow.xaml:

<Window x:Class="WpfApp1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:vm="clr-namespace:WpfApp1.ViewModels"
    xmlns:local="clr-namespace:WpfApp1"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
    <vm:MyViewModel />
</Window.DataContext>

<StackPanel Orientation="Vertical">
    <TextBox Text="{Binding ViewModelProperty, UpdateSourceTrigger=PropertyChanged}" />

    <Label Content="{Binding NestedObject.Text}" />
    <Label Content="{Binding NestedObject.Number}" />
</StackPanel>        

当您更改TextBox中的文字时,第一个标签的内容也会发生变化。

HTH,汤姆