tags:

views:

484

answers:

4

In my UI code I have a lot classes with the same basic skeleton:

  • derives from INotifyPropertyChanged
  • contains the following code:

    void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }
    
    
    public event PropertyChangedEventHandler PropertyChanged;
    

It seems like a perfect chance to factor into a class and to derive from that instead of INotifyPropertyChanged, but sadly C# doesn't support multiple inheritance so it's not really going to work. Any ideas on how to refactor this kind of code?

+1  A: 

Maybe you can use something like this:

class A1 : INotifyPropertyChanged
{
    private string _myProperty;
    private static Expression<Func<A1, string>> myProperty = _ => _.MyProperty;

    public string MyProperty
    {
        get { return _myProperty; }
        set
        {
            _myProperty = value;
            InvokePropertyChanged(myProperty);
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void InvokePropertyChanged<T>(Expression<Func<A1, T>> property)
    {
        PropertyChangedEventHandler Handler = PropertyChanged;
        if (Handler != null)
        {
            MemberExpression expression = (MemberExpression)property.Body;
            Handler(this, new PropertyChangedEventArgs(expression.Member.Name));
        }
    }
}

This significally reduce future code changes;)

Or you can use Postsharp plug-in that automatically implements INotifyPropertyChanged.

Sergey Teplyakov
Could you add some more explanation?
Anders Rune Jensen
Sergey, this is one of many good solutions to the problem where you rely on magic strings. I'm not sure that's what the OP was asking, though
Rob Fonseca-Ensor
@Anders: I mean, that maybe instead of deriving from some class you could easily do it by hand? If not, there are some additional ways: 1. code generation 2. reflection 3.PostSharp
Sergey Teplyakov
PropFu doesn't seem to solve the problem, it still has the event + method duplication. It does help a little though.
Anders Rune Jensen
@Anders: Yep! Actually this code facilitates only futher refactorings. And what you think about PostSharp?
Sergey Teplyakov
PostSharp looks nifty but there is only so much that AOP can do ;-)
Anders Rune Jensen
+1  A: 

Can't you just put this code into your superclass's superclass?

  • Object
    • Your concrete NotifyPropertyChanged class <-- Insert here
      • Whatever your viewmodel inherited from (and stopped you using multiple inheritance
        • Your concrete viewmodel
        • Another concrete viewmodel

Most MVVM Frameworks provide such a class for you.

Because of the access rules around events, you can't factor this out into an extension method without reflection, unfortunately.

Rob Fonseca-Ensor
Yeah I guess I have to do something like this. Thanks for the MVVM reference, it's nice to know that people are aware of this. I'm just baffled that books about WPF (Programming WPF) doesn't mention anything like this. Or that WPF doesn't have some notifypropertychanged class since it must have come up quite quickly that it leads to ugly duplicated code.
Anders Rune Jensen
But as I wrote to Natrium it's really a pretty ugly solution since the classes in the middle are greased into something that they really shouldn't care about. I guess this is the best one can do with OOP ;-)
Anders Rune Jensen
Hmm. What do you mean the classes in the middle are greased into something they shouldn't care about? What are these middle classes responsible for in your project?
Rob Fonseca-Ensor
Well the helper class in the middle might just have some common functionality. Something that isn't really UI related and now it has to know about INotify stuff and that makes it less general.
Anders Rune Jensen
Maybe it's the helper class in the middle that can be pushed into a separate static class, a set of extension methods, or a helper object that is provided to your UI class as a dependency? http://haacked.com/archive/2007/12/11/favor-composition-over-inheritance-and-other-pithy-catch-phrases.aspx
Rob Fonseca-Ensor
A: 

It is 4 lines of code that will never change. Create a snippet!

adrianm
Although you might need to add thread safety: void NotifyPropertyChanged(String info) { var handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(info)); } }
Rob Fonseca-Ensor
A: 

A common practice is to have a base class implementing INotifyPropertyChanged, like this:

public abstract class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;

        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Then your classes will derive from this one, and you can call OnPropertyChanged when you wish to notify changes on the value of a property :

public class PersonViewModel : ViewModelBase
{

    public PersonViewModel(Person person)
    {
        this.person = person;
    }

    public string Name
    {
        get
        {
            return this.person.Name;
        }
        set
        {
            this.person.Name = value;
            OnPropertyChanged("Name");
        }
    }
}
Natxo