riciloma
riciloma

Reputation: 1836

A nicer way to handle Properties Changes in C#

I'm building a MVVM application in which a ToBeListened class has a couple of properties, PropertyA and PropertyB, and I want to listen to them.

public class ToBeListened : INotifyPropertyChanged
{

    private double _propertyA;
    private string _propertyB;
    /*Here I'm omitting the update part where NotifyPropertyChanged gets called*/
    public double PropertyA{get; set; }
    public double PropertyB{get; set; }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Those two properties are listened by a Listener class, so I've implemented an EventHandler in it, that listens to a ToBeListened object.

public class Listener
{

     private ToBeListened toBeListenedObject; 

     public Listener()
     {  
        toBeListenedObject = new ToBeListened();
        toBeListenedObject.PropertyChanged += newPropertyChangedEventHandler(PropertyListener_PropertyChanged);
     }

     private void PropertyListener_PropertyChanged(object sender, PropertyChangedEventArgs e)
     {
        switch(e.PropertyName)
        {
          case "PropertyA":
          {
            /*...DO SOMETHING...*/
          }
          case "PropertyB":
          {
            /*...Do something else...*/
          }
    }

The thing is, I don't really like this solution I've found. A switch-case isn't polymorphism-friendly, so

  1. is there a better way to do this? Maybe something that uses overloading? (Like private void PropertyListener_PropertyChanged(double sender, PropertyChangedEventArgs e)
  2. most of all, is it right to code a ViewModel like this?

Upvotes: 4

Views: 1426

Answers (3)

Baldrick
Baldrick

Reputation: 11840

In the past I've used a little class derived from Dictionary<string, Action> for this purpose. It was something like this:

public class PropertyChangedHandler : Dictionary<string, Action>
{
    public PropertyChangedHandler(INotifyPropertyChanged source)
    {
        source.PropertyChanged += Source_PropertyChanged;
    }

    private void Source_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        Action toDo;
        if (TryGetValue(e.PropertyName, out toDo))
        {
            toDo();
        }
    }
}

Then your listener looks like this:

public class Listener
{
    private ToBeListened toBeListenedObject = new ToBeListened();

    PropertyChangedHandler handler;

    public Listener()
    {
        handler = new PropertyChangedHandler(toBeListenedObject)
                    {
                        { "PropertyA", DoA },
                        { "PropertyB", DoB }
                    };
    }

    private void DoB()
    {            
    }

    private void DoA()
    {            
    }
}

This is just an example to give you an idea - it can be expanded for more complex purposes, of course.

Upvotes: 1

Alex
Alex

Reputation: 3889

i think MVVM Light framework (or library?) has what you need. Take a look at their ObservableObject class http://www.mvvmlight.net/help/SL5/html/d457231f-6af7-601d-fa1f-1fe7c9f60c57.htm

Basically what it does, is making your object observable.

Upvotes: 0

rmc00
rmc00

Reputation: 887

I like Josh Smith's PropertyObserver, which you can get at http://mvvmfoundation.codeplex.com/ (some documentation from Josh at https://joshsmithonwpf.wordpress.com/2009/07/11/one-way-to-avoid-messy-propertychanged-event-handling/). It's a nice class that encapsulates the plumbing logic you're talking about, so you can focus on just handling changes to certain properties. So in your case, you could write code like:

var observer = new PropertyObserver<ToBeListened>(toBeListenedObject)
                  .RegisterHandler(tbl => tbl.PropertyA, tbl => HandlePropertyA(tbl))
                  .RegisterHandler(tbl => tbl.PropertyB, tbl => HandlePropertyB(tbl));

You can start using it by installing the MVVM Foundation nuget package into your solution. The ID is MvvmFoundation.Wpf.

Upvotes: 4

Related Questions