Tuesday, January 5, 2010

MultiuseModel-View (MMV) Object modeling pattern with WPF and WCF: The Foundation



Download sample ObservableObject project



In my previous article I went over how to break up a multiuse object into logical parts. In this article I will talk about an ObservableObject: an object that notifies WPF of changes.



The ObservableObject Class


There are two type of members that you can bind in a WPF app: properties and methods. Requirements for binding properties is fairly straight forward: one must implement INotifyPropertyChanged. To bind a method, on the other hand, we must actually have a property of type ICommand for each method we want to bind to.


Implementing INotifyPropertyChanged simply consists of raising the PropertyChanged event every time a property changes. The problem lies in making a child class of ObservableObject to raise the event without having the developer of the child class call it himself/herself. The best solution for this problem is to use Reflection.Emit to construct a child class of the templated class and override the properties' set method to raise the event after executing the template's set method logic.


foreach (PropertyInfo property in parentType.GetProperties())
                {
                    method = parentType.GetMethod("set_" + property.Name);
                    methodBuilder = typeBuilder.DefineMethod(method.Name, method.Attributes, method.ReturnType, method.GetParameters().Select(pi => pi.ParameterType).ToArray());
                    il = methodBuilder.GetILGenerator();
                    locAi = il.DeclareLocal(typeof(ArgIterator));

                    il.Emit(OpCodes.Nop);
                    il.Emit(OpCodes.Ldarg_0);
                    il.Emit(OpCodes.Ldarg_1);
                    il.EmitCall(OpCodes.Call, method, null);
                    il.Emit(OpCodes.Nop);
                    il.Emit(OpCodes.Ldarg_0);
                    il.Emit(OpCodes.Ldstr, property.Name);
                    il.EmitCall(OpCodes.Call, parentType.GetMethod("OnPropertyChange", BindingFlags.NonPublic | BindingFlags.Instance), null);
                    il.Emit(OpCodes.Nop);
                    il.Emit(OpCodes.Ret);
                    typeBuilder.DefineMethodOverride(methodBuilder, method);
                }

With this in mind, adding ICommands for methods becomes just as easy: we can use the same TypeBuilder to add new properties of type ICommand for each public method.



foreach (MethodInfo mi in parentType.GetMethods(BindingFlags.Instance | BindingFlags.Public).Where(methodInfo => !methodInfo.Name.StartsWith("get_") && !methodInfo.Name.StartsWith("set_") && !methodInfo.Name.StartsWith("add_") && !methodInfo.Name.StartsWith("remove_")))
                {
                    FieldBuilder commandField = typeBuilder.DefineField("_" + mi.Name + cExtendedTypesCommandPostfix, typeof(DelegateCommand), FieldAttributes.Private);

                    MethodBuilder commandGetMethod = typeBuilder.DefineMethod("get_" + mi.Name + cExtendedTypesCommandPostfix, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeof(ICommand), Type.EmptyTypes);
                    ILGenerator commandGetMethodIL = commandGetMethod.GetILGenerator();

                    var commandNullLabel = commandGetMethodIL.DefineLabel();
                    var defaultLabel = commandGetMethodIL.DefineLabel();

                    commandGetMethodIL.Emit(OpCodes.Nop);
                    commandGetMethodIL.Emit(OpCodes.Ldarg_0);
                    commandGetMethodIL.Emit(OpCodes.Ldfld, commandField);
                    commandGetMethodIL.Emit(OpCodes.Ldnull);
                    commandGetMethodIL.Emit(OpCodes.Ceq);
                    commandGetMethodIL.Emit(OpCodes.Brfalse, commandNullLabel);
                    commandGetMethodIL.Emit(OpCodes.Ldarg_0);
                    commandGetMethodIL.Emit(OpCodes.Ldarg_0);
                    commandGetMethodIL.Emit(OpCodes.Ldftn, mi);
                    commandGetMethodIL.Emit(OpCodes.Newobj, typeof(Action).GetConstructor(new Type[] { typeof(object), typeof(IntPtr) }));
                    commandGetMethodIL.Emit(OpCodes.Newobj, typeof(DelegateCommand).GetConstructor(new Type[] { typeof(Action) }));
                    commandGetMethodIL.Emit(OpCodes.Stfld, commandField);
                    commandGetMethodIL.MarkLabel(commandNullLabel);
                    commandGetMethodIL.Emit(OpCodes.Ldarg_0);
                    commandGetMethodIL.Emit(OpCodes.Ldfld, commandField);
                    commandGetMethodIL.Emit(OpCodes.Ret);

                    PropertyBuilder commandProperty = typeBuilder.DefineProperty(mi.Name + cExtendedTypesCommandPostfix, PropertyAttributes.HasDefault, typeof(ICommand), null);
                    commandProperty.SetGetMethod(commandGetMethod);
                }

Now for all of this to work we need to make sure two things happen: first the consumer of the template object should actually get an instance of the derived type. And second, since the consumer is actually using a child class of the type he/she declared, we must ensure that reflection and typing compatibility is achieved. To do this, we must first of all provide a means of instantiating a new object (with a New() static method) and we must also override the GetType() of the child type we have created to return an instance of the template's Type class.


MethodInfo method = typeof(object).GetMethod("GetType", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { }, null);
                MethodBuilder methodBuilder = typeBuilder.DefineMethod(method.Name, method.Attributes, typeof(Type), method.GetParameters().Select(pi => pi.ParameterType).ToArray());
                ILGenerator il = methodBuilder.GetILGenerator();
                LocalBuilder locAi = il.DeclareLocal(typeof(ArgIterator));

                il.Emit(OpCodes.Ldtoken, parentType);
                il.EmitCall(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", BindingFlags.Public | BindingFlags.Static), null);
                il.Emit(OpCodes.Stloc_0);
                il.Emit(OpCodes.Ldloc_0);
                il.Emit(OpCodes.Ret);

public static T New()
        {
            return ((T)Activator.CreateInstance(CreateOverridenType(typeof(T))));
        }

In my next article, I'll demonstrate how to create an enterprise level DatabaseObject and DatabaseCollection classes.




Monday, January 4, 2010

MultiuseModel-View (MMV) Object modeling pattern with WPF and WCF: Genesis



In my previous article I gave a basic introduction to the Multiuse-Model View pattern. In this short article I will explain in detail the concepts behind a MMV library.



The Multiuse-Object Theory


A well organized framework is highly dependent on inheritance and encapsulation to avoid messy code and unnecessary overhead. Let's take the WPF framework itself for instance: when you are dealing with controls... say... a Button, you are dealing with a class that inherits from DispatcherObject, DependencyObject, Visual, UIElement, FrameworkElement, Control, ContentControl and ButtonBase. Each of these parent classes provide a different piece of functionality to their children such that by the time we get to deal with the Button class, we only have to worry about a few methods and properties to make the button show up on the screen and display text (or other stuff) inside and handle user events.
Likewise, with our Multiuse-Model approach, we want a set of classes that provide basic functionality to our business objects in order to encapsulate operations related to databases, client-server communications and even property notification changes.
In my previous article I wrote about lumping all this functionality in one single class, the MultiuseObject class, however, for large scale applications this would be cumbersome since the amount of functionality in a realistic framework is excessive for a single class. For this reason it is better to slice and dice each set of functionality into their own classes. At a minimum you should have the following classes as parents of your business objects:


  • ObservableObject: provides implementation of INotifyPropertyChanged for properties and ICommands for methods.
  • DatabaseObject: provides functionality to retrieve and store information on a database (there are many good data-layer libraries already, this object would wrap their functionality).
  • CommunicationObject: provides client-server communications.
  • MultiuseObject: wraps all functionality in a nice and neat package.

These classes are listed in order of inheritance, since, it is likely that sometimes you might not need to deal with the entire functionality. For example, sometimes you will have UI-only objects that would inherit straight from ObservableObject opposed to MultiuseObject.

In my next article, I'll demonstrate how to create an enterprise level ObservableObject class.