Adding INotifyPropertyChanged to Model?
Asked Answered
P

5

7

I'm facing some design questions in my wpf MVVM (Prism based) application, would be happy to get your advice. My model is very simple:

public class Customer
{
   public string FirstName {get;set;}
   public string LastName {get;set;}
}

As you can see, I don't have any INotifyPropertyChnaged support for my Model class. I also have ViewModel for the CustomerDetails screen, that support INotifyPropertyChanged.

public class CustomerDetailsViewModel:INotifyPropertyChanged /*Or NotificationObject*/
{
   /*INotifyPropertyChanged event */
   private Customer item;
   public Customer Item
   {
      get{return item;}
      set
      {
         item=value; 
         //Raise PropertyChanged
         //Set IsDirty to true
      }
   }
}

In my view, i'm using binding to the Item.FirstName and my ViewModel being updated. My problem is - since only the FirstName property is being updated via the View, and the Model itself does not support INotifyPropertyChanged, hence the Item setter not being called, and the IsDirty remains equal to false (and therefore does not update the IsDirty notification on the UI).

I know I can support INotifyPropertyChanged in the model, and then register to the Item.PropertyChanged event in the view model, and actually set the IsDirty to true, But - Since I'm also using CodeFirst, and my Model class shared between my ServerSide and my client side (Not using Add Service Reference), I don't want to add the INotifyPreoprtyChanged stuff to my server side.

I'm considaring creating new project, that will use T4 templates to copy one by one all my Entities (as Customer) and adding INotifyPropertyChanged support to each and every model. Is that something that seems reasonable or not? any other suggestions?

Thanks!

Puberulent answered 14/2, 2013 at 7:38 Comment(0)
G
4

Option1.
Separate entities, which being transferred between client and server (DTO), from entities, which are models on the client side. Implement INPC in models. Use mapping between these entities.

Option2.
Bind view to view model properties only. Make view model properties, which wrap corresponding model properties.

Option 3.
Is a mix of first two options. Do not aggregate model in view model. Use mapping between model and view model. Make view model properties, which correspond to model properties.

Garnishee answered 14/2, 2013 at 7:47 Comment(0)
R
1

Well your approach is simply not the best. Much better would be to use a VM like this


public class CustomerDetailsViewModel : INotifyPropertyChanged
{
  public CustomerDetailsViewModel(Customer customer)
  {
    _item = customer;
  }
  private Customer _item;

  public string FirstName
  { 
    get { return _item != null ? _item.FirstName : null; }
    set 
    {
      if (_item == null)
        _item = new Customer(); // just an example, probably it's not the desired behavior
      _item.FirstName = value;
      RaisePropertyChanged(...);
    }
  }
  ...
}

This would stick to the spirit of MVVM.

Rafaello answered 14/2, 2013 at 7:52 Comment(2)
I understand what you're saying, But this will require lots of coding for (almost) no reason. Should I duplicate every property of my model in my view model???Puberulent
@Puberulent You're right. I don't know your project. If it's just a small one, it might be a huge overhead. But in larger projects, when you have additional requirements like testability, decoupling a.s.o. it would be one way to achieve them.Rafaello
I
1

If you want your UI to notice when your model property changed, your model class MUST implement INotifyPropertyChanged and similar MVVM interfaces (IDataErrorInfo, etc...) in order to Notify to the UI that the property changed.

That's because you are not always updating your model from the the viewmodel, where you must implement INotifyProperyChanged and notify for changes.

Wrapping corresponding model properties in the viewmodel used when you cannot implement INotifyPropertyChanged in the model class, which makes the viewmodel to grow VERY fast and creates unnecessary code duplication.

Scenario for example:

public class Customer
{
   public string FirstName {get;set;}
   public string LastName {get;set;}

   // Changes the first name.
   public void ChangeFirstName(string newName)
   {
      FirstName = newName;
      //The UI will never know that the property changed, and it won't update.
   }
}

Solution:

Implement INotifyPropertyChanged in you model class, create backing fields to your properties, and for each property setter, AFTER the set operation, raise OnPropertyChanged invoked method with the property name.

Iormina answered 27/2, 2015 at 15:44 Comment(0)
C
0

If you don't like to clutter your model with INotifyPropertyChanged code you could try using a NUGet package called PropertyChanged.Fody

You can use it like this;

using PropertyChanged;

[ImplementPropertyChanged]
public class Customer
{
   public string FirstName {get;set;}
   public string LastName {get;set;}
}

Any public property in this class will now support INotifyPropertyChanged

Casarez answered 4/11, 2016 at 16:27 Comment(0)
C
-1

I think you are on the right track. In the server side, you do not need INotifyPropertyChanged, thus do not add it to the domain classes in the server side.

You may just add some build symbols such as "WPF" to your client projects; and in the code first definitions implement INotifyPropertyChanged only if there is "WPF" build symbol. Then just add your server side domain classes as links to your presentation application. Something like;

#if WPF
public class MyEntity : INotifyPropertyChanged
#else
public class MyEntity

....
Concupiscence answered 14/2, 2013 at 7:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.