MVVM : Injecting INotifyPropertyChanged Into an Existing Class

10 בדצמבר 2010

תגיות: , , , ,
2 תגובות

Download the source code for this post here.


Using MVVM in Silverlight and WPF I often encounter the following problem.


I have a business class that needs to be exposed through the ViewModel. For this, it needs to implement INotifyPropertyChanged or expose Dependency properties.


I take the side of those who prefer to keep WPF dependencies out of the ViewModel, so I usually take the path of writing a proxy that delegates properties to the business object and implementing INotifyPropertyChanged.


I am not comfortable with this duplication, and I usually pay a price for it when I refactor the business class, but I still do it because the separation of View and Model is so important and justifies the extra work.


However, it would be nice, if INotifyPropertyChanged would be generated automatically.


The Unity framework from the Patterns and Practices group can do this for you.


It's a little tricky, and the sample provided by the group is not entirely generic.


I implemented a factory class that uses Unity to generate an INotifyPropertyChanged implementation for any interface implementation pair at run time. I demonstrate configuration in code or using a configuration file.


The solution includes the following Test project that injects INotifyPropertyChanged to a BusinessObject class called BusinessObjects.Customer that implements BusinessObjects.ICustomer.



using System.ComponentModel;


using BusinessObjects;


using Microsoft.VisualStudio.TestTools.UnitTesting;


using NotifyPropertyChangedInjectionFactory;


namespace TestProject


{


    [TestClass]


    public class UnitTests


    {


        [TestMethod]


        public void TestInjectionWithCode()


        {


            Factory factory = new Factory();


            ClassDescriptor classDescriptor = new ClassDescriptor


            {


                TypeFrom = typeof(ICustomer),


                TypeTo = typeof(Customer),


                ConstructorArguments = new object[] { "Bill", 34 }


            };


            factory.RegisterWithCode(classDescriptor);


            VerifyImplementation(factory);


        }


        [TestMethod]


        public void TestInjectionFromConfigFile()


        {


            Factory factory = new Factory();


            factory.RegisterFromConfigFile();


            VerifyImplementation(factory);


        }


        private static void VerifyImplementation(Factory factory)


        {


            ICustomer customer = factory.Create<ICustomer>();


            Assert.IsInstanceOfType(customer, typeof(INotifyPropertyChanged));


            INotifyPropertyChanged propChanged = customer as INotifyPropertyChanged;


            int notificationCount = 0;


            string newName = "Fred";


            int newAge = 25;


            Assert.IsFalse(customer.Name == newName);


            Assert.IsFalse(customer.Age == newAge);


            propChanged.PropertyChanged += (s, e) =>


            {


                notificationCount++;


                if (e.PropertyName == "Name")


                    Assert.IsTrue(customer.Name == newName);


                if (e.PropertyName == "Age")


                    Assert.IsTrue(customer.Age == newAge);


            };


            customer.Name = newName;


            customer.Age = newAge;


            Assert.IsTrue(customer.Name == newName);


            Assert.IsTrue(customer.Age == newAge);


            Assert.IsTrue(notificationCount == 2);


        }


    }


}


The limitation here is that the object returned by the factories Create method is not a Customer. In this implementation I used the InterfaceInterception mechanism, but TransparentProxyInterception has the same drawback.


For more information I recommend reading this section of the Unity Framework documentation.

הוסף תגובה
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *

2 תגובות

  1. Yazid14 בדצמבר 2010 ב 14:14

    Very good article, I downloaded the solution and the tests work very well. However when I tried to test it using a WPF project I cannot get it to work. Do you have an exmaple usinga WPF project?

    TIA
    Yaz

    הגב
  2. miami6 בספטמבר 2012 ב 5:15

    Topic good, it helped me a lot. Thank you for share.

    הגב