Question

I have a project in WPF with the MVVM-Pattern.

The view has a listview of Persons(FirstName, LastName, Town) and next to the list are the details of the person(FirstName,LastName,ZIP) with a button(Save). If you click to a person on the left side, the person details on the right side will load automatically.

In the ViewModel I have an ObservableCollection of Person-Models. (Person list)

The Person Model includes some propertys like FirstName, LastName, Town, Zip. (Details).

When I change the ZIP, the Town will updated automatically(in the setter switch-case) e.g. ZIP '11111' Town 'Town1' / ZIP '22222' Town 'Town2'.

The Person Model includes also an ICommand "SavePerson" to Save Changes.

Now when i click to an item in the listview the details will load automatically. When I change the FirstName or LastName and click "Save" the listview will change the First and the LastName of the selected item, that's ok. Now when I change the ZIP from '12345' into '11111' the town in the listview is still the old one and not 'Town1'.

Have you an idea to fix this problem, without to implement the INotifyPropertyChanged-Interface in the Model?

Some code: Model:

public class Person
{
    private string _firstName = string.Empty;
    private string _lastName = string.Empty;
    private string _zip = string.Empty;
    private string _town = string.Empty;

    public string FirstName
    {
        get { return _firstName; }
        set { _firstName = value; }
    }

    public string LastName
    {
        get { return _lastName; }
        set { _lastName= value; }
    }

    public string ZIP
    {
        get { return _zip; }
        set
        {
            switch (value)
            {
                case "11111":
                    this.Town = "Town1";
                    break;
                case "22222":
                    this.Ort = "Town2";
                    break;
                default:
                    break;
            }
            _zip = value;
        }
    }

    public string Town
    {
        get { return _town; }
        set { _town= value; }
    }
            public ICommand SaveNameCommand
    {
        get
        {
            return new DelegateCommand((param) => this.SaveName(param));
        }
    }

    private void SaveName(object parameter)
    {
        string[] param = ((string)parameter).Split(new char[] { ':' });
        FirstName = param[0];
        LastName = param[1];
        PLZ = param[2];
    }
}

ViewModel:

public class PersonList
{
    private readonly ObservableCollection<Person> _persons = new ObservableCollection<Person>();
    private Person _currentSelectedPerson = new Person();

    public PersonList()
    {
        this._persons.Add(new Person() { FirstName = "First1", LastName = "Last1", Ort = "Ort1", PLZ = "112" });
        this._persons.Add(new Person() { FirstName = "First2", LastName = "Last2", Ort = "Ort2", PLZ = "122" });
        this._persons.Add(new Person() { FirstName = "First3", LastName = "Last3", Ort = "Ort3", PLZ = "1132" });
    }

    public IEnumerable<Person> Persons
    {
        get { return this._persons; }
    }
}
Was it helpful?

Solution

Since your Model should be loosely-coupled from your ViewModel, it makes sense that you might not want to implement INotifyPropertyChanged in your Model since it's most commonly associated with WPF; however, it's a C# interface and can be used in any type of application, so there's no harm implementing it. In fact, I'd suggest it's probably the best way. However, if you really don't want to implement it in your model classes, consider an event-subscriber model, where the Model raises an event when changed, and the ViewModel subscribes to it.

model.ValuesChanged += model_ValuesChanged;

private void model_ValuesChanged(object sender, EventArgs e)
{
     RaisePropertyChanged("MyProperty");
}

OTHER TIPS

I have absolutely no idea why you would want to not implement the INotifyPropertyChanged interface on your model class(es). Really, your only other option would be to implement it in your view model and expose all of your model properties there:

public string FirstName
{
    get { return _currentSelectedPerson .FirstName; }
    set { _currentSelectedPerson .FirstName = value; NotifyPropertyChanged("FirstName"); }
}

public string LastName
{
    get { return _currentSelectedPerson .LastName; }
    set { _currentSelectedPerson .LastName= value; NotifyPropertyChanged("LastName"); }
}
...

WPF and the INotifyPropertyChanged interface go hand in hand... at some stage, you're going to have to implement it.

The model Should implement INotifyPropertyChanged chack INotifyPropertyChanged WPF
any other search of INotifyPropertyChanged will do as well

You need notification your View about changed in ViewModel. For this use INotifyPropertyChanged. Any class that implements this interface, notifies any listeners when a property has changed.

So you need to modify our Person class a little bit more:

public class Person : INotifyPropertyChanged
{
    private string _firstName = string.Empty;
    private string _lastName = string.Empty;
    private string _zip = string.Empty;
    private string _town = string.Empty;

    public string FirstName
    {
        get { return _firstName; }
        set 
        {
            _firstName = value; 
            RaisePropertyChanged("FirstName");
        }
    }

    public string LastName
    {
        get { return _lastName; }
        set 
        {
            _lastName= value; 
            RaisePropertyChanged("LastName");
        }
    }

    public string ZIP
    {
        get { return _zip; }
        set
        {
            switch (value)
            {
                case "11111":
                    this.Town = "Town1";
                    break;
                case "22222":
                    this.Town = "Town2";
                    break;
                default:
                    break;
            }
            _zip = value;
            RaisePropertyChanged("LastName");
            RaisePropertyChanged("Town");
        }
    }

    public string Town
    {
        get { return _town; }
        set 
        {
            _town= value; 
            RaisePropertyChanged("Town");
        }
    }
            public ICommand SaveNameCommand
    {
        get
        {
            return new DelegateCommand((param) => this.SaveName(param));
        }
    }

    private void SaveName(object parameter)
    {
        string[] param = ((string)parameter).Split(new char[] { ':' });
        FirstName = param[0];
        LastName = param[1];
        PLZ = param[2];
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top