Silverlight/WPF cross-compile gotcha

September 22, 2010

Here’s an interesting gotcha if you are trying to cross-compile between Silverlight and WPF. The default content alignment of a ContentControl’s content in Silverlight is left/top while in WPF it’s stretch/stretch! The Silverlight ContentControl respects the VerticalContentAlignment/HorizontalContentAlignment properties (which default to left/top) while the WPF one does not. Check out the default templates of ContentControl in Silverlight and WPF for some other “cute” differences.

Advertisements

Binding to Anonymous types in Silverlight

May 30, 2010

If you’ve ever tried to bind to anonymous type in Silverlight (or a WPF non full-trust XBAP) you will have wound up running into a pretty nasty gotcha. It seems like a natural enough thing to do, for example:

public partial class MainPage : UserControl
    {
        IList types;

        public MainPage()
        {
            InitializeComponent();

            types = (from type in
                            Assembly
                            .GetExecutingAssembly()
                            .GetTypes()
                        select new
                        {
                            Name = type.Name,
                            BaseTypeName = type.BaseType.Name
                        }).ToList();

            DataContext = types;
        }
    }

It seems like this should work, right? If you try it, though, you will see a whole lot of nothing and a bunch of MethodAccessExceptions in your output log.

Why does this happen?

This happens because the way Anonymous types are implemented is that, at compile time, the compiler will determine what type needs to be generated in the assembly based on the property names and inferred types and will do the necessary generation. The problem is, though, that this type is marked internal!

This would not be so bad except for the fact that the Silverlight and WPF binding system need to reflect against the type in order to set up a binding, which would be fine if you were doing that from inside you own assembly, but it is the binding system that is going to be doing the reflection, from System.Windows.

The immediate answer then, that should occur to you, is that you can make your assemblies internals visible to System.Windows.

[assembly: InternalsVisibleTo("System.Windows,
PublicKey=00240000048000009400000006020000002400
005253413100040000010001008D56C76F9E8649383049
F383C44BE0EC204181822A6C31CF5EB7EF486944D0321
88EA1D3920763712CCB12D75FB77E9811149E6148E5D
32FBAAB37611C1878DDC19E20EF135D0CB2CFF2BFEC
3D115810C3D9069638FE4BE215DBF795861920E5AB6F
7DB2E2CEEF136AC23D5DD2BF031700AEC232F6C6B1
C785B4305C123B37AB", AllInternalsVisible=false)]

And indeed this will work (line breaks in the public key above added for clarity). This was gleaned from reflectoring some of the system Silverlight assemblies that need to make their internals visible to System.Windows (where the binding engine sits).

Ok, so this is all well and good, if you want to display read only information from a linq query, as Anonymous types are immutable! But what if we want to harness the easy definition of these anonymous types as a template for mutable types, and what if we want these types to be public so we don’t need to bother with exposing our internals? Well, I was curious as to how hard it would be to adapt the code I wrote recently for generating dynamic types to implement INotifyPropertyChanged to generate types that had the same properties as an anonymous type except read-write and public.

Well, luckily enough for you, if you are interested in this stuff, I did it! I won’t go into a lot of detaills for how this is done as it follows the general pattern of my previous post on type generation where I explained in more detail, but the general gist is that it will reflect against the anonymous type (which it can do since it is in the same assembly, if you put this code in a different assembly you will need to InternalsVisibleTo it) and for each property there found, make a writable version on the type it is generating. This writable property will also be augmented to raise a PropertyChanged event for INotifyPropertyChanged (bonus!!), allowing for some pretty interesting scenarios.

Here’s how the usage would look:

    public partial class MainPage : UserControl
    {
        IList types;

        public MainPage()
        {
            InitializeComponent();

            types = (from type in
                            Assembly
                            .GetExecutingAssembly().GetTypes()
                        select new
                        {
                            Name = type.Name,
                            BaseTypeName = type.BaseType.Name
                        }.MakePublicAndMutable()).ToList();

            DataContext = types;
        }
    }

And here’s the code that does the dynamic type generation:

    public static class Extensions
    {
        public static object MakePublicAndMutable(this object obj)
        {
            return TypeGenerator.MakePublicAndMutable(obj);
        }
    }

    public class TypeGenerator
    {
        //note, not threadsafe currently 😉
        private static AssemblyBuilder _ab;
        private static ModuleBuilder _mb;
        private static Dictionary<Type, Type> types =
            new Dictionary<Type, Type>();

        private static IEnumerable<PropertyInfo> GetProperties(
            Type type)
        {
            return from p in
                       type.GetProperties(
                           BindingFlags.Public |
                           BindingFlags.Instance |
                           BindingFlags.FlattenHierarchy)
                   select p;
        }

        public static object MakePublicAndMutable(object item)
        {
            List<object> parms = new List<object>();

            foreach (PropertyInfo prop in GetProperties(item.GetType()))
            {
                parms.Add(prop.GetValue(item, null));
            }

            Type type = GetAnonTypeProxyType(item.GetType());
            ConstructorInfo mi = type.GetConstructor(
                (from parm in parms select parm.GetType()).ToArray());

            return Activator.CreateInstance(type, parms.ToArray());
        }

        protected static Type GetAnonTypeProxyType(Type type)
        {
            Type ret;
            if (types.TryGetValue(type, out ret))
            {
                return ret;
            }

            if (_ab == null)
            {
                AssemblyName assmName = new AssemblyName("DynamicAssembly");
                _ab = AppDomain.CurrentDomain.DefineDynamicAssembly(
                    assmName, AssemblyBuilderAccess.Run);
                _mb = _ab.DefineDynamicModule(assmName.Name);
            }

            TypeBuilder typeBuilder = _mb.DefineType(
            Guid.NewGuid().ToString() + "__proxy", TypeAttributes.Public);
            typeBuilder.AddInterfaceImplementation(
                typeof(INotifyPropertyChanged));

            FieldBuilder eventField =
                CreatePropertyChangedEvent(typeBuilder);

            MethodBuilder raisePropertyChanged =
                CreateRaisePropertyChanged(typeBuilder, eventField);

            var props = GetProperties(type);
            Dictionary<string, FieldBuilder> fields =
                new Dictionary<string, FieldBuilder>();

            CreateProperties(props, typeBuilder, fields,
                raisePropertyChanged);
            CreateDefaultConstructor(typeBuilder);
            CreateConstructor(props, typeBuilder, fields);

            ret = typeBuilder.CreateType();
            types.Add(type, ret);
            return ret;
        }

        private static MethodBuilder CreateRaisePropertyChanged(
            TypeBuilder typeBuilder, FieldBuilder eventField)
        {
            MethodBuilder raisePropertyChangedBuilder =
                typeBuilder.DefineMethod(
                "RaisePropertyChanged",
                MethodAttributes.Family | MethodAttributes.Virtual,
                null, new Type[] { typeof(string) });

            ILGenerator raisePropertyChangedIl =
            raisePropertyChangedBuilder.GetILGenerator();
            Label labelExit = raisePropertyChangedIl.DefineLabel();

            // if (PropertyChanged == null)
            // {
            //      return;
            // }
            raisePropertyChangedIl.Emit(OpCodes.Ldarg_0);
            raisePropertyChangedIl.Emit(OpCodes.Ldfld, eventField);
            raisePropertyChangedIl.Emit(OpCodes.Ldnull);
            raisePropertyChangedIl.Emit(OpCodes.Ceq);
            raisePropertyChangedIl.Emit(OpCodes.Brtrue, labelExit);

            // this.PropertyChanged(this,
            // new PropertyChangedEventArgs(propertyName));
            raisePropertyChangedIl.Emit(OpCodes.Ldarg_0);
            raisePropertyChangedIl.Emit(OpCodes.Ldfld, eventField);
            raisePropertyChangedIl.Emit(OpCodes.Ldarg_0);
            raisePropertyChangedIl.Emit(OpCodes.Ldarg_1);
            raisePropertyChangedIl.Emit(OpCodes.Newobj,
                typeof(PropertyChangedEventArgs)
                .GetConstructor(new[] { typeof(string) }));
            raisePropertyChangedIl.EmitCall(OpCodes.Callvirt,
                typeof(PropertyChangedEventHandler)
                .GetMethod("Invoke"), null);

            // return;
            raisePropertyChangedIl.MarkLabel(labelExit);
            raisePropertyChangedIl.Emit(OpCodes.Ret);

            return raisePropertyChangedBuilder;
        }

        private static FieldBuilder CreatePropertyChangedEvent(
            TypeBuilder typeBuilder)
        {
            // public event PropertyChangedEventHandler PropertyChanged;
            FieldBuilder eventField =
                typeBuilder.DefineField("PropertyChanged",
                typeof(PropertyChangedEventHandler),
                FieldAttributes.Private);
            EventBuilder eventBuilder =
                typeBuilder.DefineEvent(
                "PropertyChanged",
                EventAttributes.None,
                typeof(PropertyChangedEventHandler));

            eventBuilder.SetAddOnMethod(
            CreateAddRemoveMethod(typeBuilder, eventField, true));
            eventBuilder.SetRemoveOnMethod(
            CreateAddRemoveMethod(typeBuilder, eventField, false));

            return eventField;
        }

        private static MethodBuilder CreateAddRemoveMethod(
            TypeBuilder typeBuilder,
            FieldBuilder eventField, bool isAdd)
        {
            string prefix = "remove_";
            string delegateAction = "Remove";
            if (isAdd)
            {
                prefix = "add_";
                delegateAction = "Combine";
            }
            MethodBuilder addremoveMethod =
            typeBuilder.DefineMethod(prefix + "PropertyChanged",
               MethodAttributes.Public |
               MethodAttributes.SpecialName |
               MethodAttributes.NewSlot |
               MethodAttributes.HideBySig |
               MethodAttributes.Virtual |
               MethodAttributes.Final,
               null,
               new[] { typeof(PropertyChangedEventHandler) });
            MethodImplAttributes eventMethodFlags =
                MethodImplAttributes.Managed |
                MethodImplAttributes.Synchronized;
            addremoveMethod.SetImplementationFlags(
                eventMethodFlags);

            ILGenerator ilGen = addremoveMethod.GetILGenerator();

            // PropertyChanged += value; // PropertyChanged -= value;
            ilGen.Emit(OpCodes.Ldarg_0);
            ilGen.Emit(OpCodes.Ldarg_0);
            ilGen.Emit(OpCodes.Ldfld, eventField);
            ilGen.Emit(OpCodes.Ldarg_1);
            ilGen.EmitCall(OpCodes.Call,
                typeof(Delegate).GetMethod(
                delegateAction,
                new[] { typeof(Delegate), typeof(Delegate) }),
                null);
            ilGen.Emit(OpCodes.Castclass, typeof(
            PropertyChangedEventHandler));
            ilGen.Emit(OpCodes.Stfld, eventField);
            ilGen.Emit(OpCodes.Ret);

            MethodInfo intAddRemoveMethod =
            typeof(INotifyPropertyChanged).GetMethod(
            prefix + "PropertyChanged");
            typeBuilder.DefineMethodOverride(
            addremoveMethod, intAddRemoveMethod);

            return addremoveMethod;
        }

        private static void CreateDefaultConstructor(
           TypeBuilder typeBuilder)
        {
            ConstructorBuilder cons = typeBuilder.DefineConstructor(
                MethodAttributes.Public,
                CallingConventions.Standard,
                null);
            ILGenerator ilGen = cons.GetILGenerator();
            ilGen.Emit(OpCodes.Ldarg_0);
            ilGen.Emit(OpCodes.Call,
                typeof(object).GetConstructor(new Type[0]));
            ilGen.Emit(OpCodes.Ret);
        }

        private static void CreateConstructor(
            IEnumerable<PropertyInfo> props,
            TypeBuilder typeBuilder,
            Dictionary<string, FieldBuilder> fields)
        {
            var paramTypes = from p in props select p.PropertyType;
            ConstructorBuilder cons = typeBuilder.DefineConstructor(
                MethodAttributes.Public,
                CallingConventions.Standard,
                paramTypes.ToArray());
            ILGenerator ilGen = cons.GetILGenerator();
            ilGen.Emit(OpCodes.Ldarg_0);
            ilGen.Emit(OpCodes.Call,
                typeof(object).GetConstructor(new Type[0]));

            int count = 1;
            foreach (PropertyInfo info in props)
            {
                ilGen.Emit(OpCodes.Ldarg_0);
                ilGen.Emit(OpCodes.Ldarg, count);
                ilGen.Emit(OpCodes.Stfld, fields[info.Name]);
                count++;
            }

            ilGen.Emit(OpCodes.Ret);
        }

        private static void CreateProperties(
            IEnumerable<PropertyInfo> props,
            TypeBuilder typeBuilder,
            Dictionary<string, FieldBuilder> fields,
            MethodBuilder raisePropertyChanged)
        {
            foreach (PropertyInfo info in props)
            {
                PropertyBuilder pb = typeBuilder.DefineProperty(
                    info.Name, PropertyAttributes.None,
                    info.PropertyType,
                    (from p in info.GetIndexParameters()
                     select p.ParameterType).ToArray());

                FieldBuilder backingField = typeBuilder.DefineField(
                    "_" + info.Name,
                    info.PropertyType,
                    FieldAttributes.Private);
                fields.Add(info.Name, backingField);

                MethodInfo getMethod = info.GetGetMethod();
                if (getMethod != null)
                {
                    pb.SetGetMethod(
                        CreateGetMethod(info, getMethod,
                        backingField, typeBuilder));

                    pb.SetSetMethod(
                        CreateSetMethod(info, getMethod, backingField,
                        typeBuilder, raisePropertyChanged));
                }
            }
        }

        private static MethodBuilder CreateGetMethod(
            PropertyInfo info,
            MethodInfo toWrap,
            FieldBuilder backingField,
            TypeBuilder typeBuilder)
        {
            MethodInfo orig = toWrap;
            var paramTypes = (from p in orig.GetParameters()
                              select p.ParameterType).ToArray();
            MethodBuilder mb = typeBuilder.DefineMethod(
                orig.Name,
                MethodAttributes.Public |
                MethodAttributes.HideBySig,
                orig.ReturnType, paramTypes);

            ILGenerator ilGen = mb.GetILGenerator();
            ilGen.Emit(OpCodes.Ldarg_0);
            ilGen.Emit(OpCodes.Ldfld, backingField);
            ilGen.Emit(OpCodes.Ret);

            return mb;
        }

        private static MethodBuilder CreateSetMethod(
            PropertyInfo info,
            MethodInfo toWrap,
            FieldBuilder backingField,
            TypeBuilder typeBuilder,
            MethodBuilder raisePropertyChanged)
        {
            MethodInfo orig = toWrap;
            var origParamTypes = (from p in orig.GetParameters()
                                  select p.ParameterType).ToArray();
            List<Type> paramTypes = new List<Type>();
            if (orig.ReturnType != typeof(void))
            {
                paramTypes.Add(orig.ReturnType);
            }
            paramTypes.AddRange(origParamTypes);

            MethodBuilder mb = typeBuilder.DefineMethod(
                "set_" + info.Name,
                MethodAttributes.Public |
                MethodAttributes.HideBySig,
                null, paramTypes.ToArray());

            ILGenerator ilGen = mb.GetILGenerator();
            ilGen.Emit(OpCodes.Ldarg_0);
            ilGen.Emit(OpCodes.Ldarg_1);
            ilGen.Emit(OpCodes.Stfld, backingField);

            // RaisePropertyChanged("[PropertyName]");
            ilGen.Emit(OpCodes.Ldarg_0);
            ilGen.Emit(OpCodes.Ldstr, info.Name);
            ilGen.EmitCall(
            OpCodes.Call, raisePropertyChanged, null);

            ilGen.Emit(OpCodes.Ret);

            return mb;
        }
    }

Again see my previous post for some Reflection.Emit details if you don’t understand the above. And feel free to shoot me some questions!


Working with collection-typed Dependency Properties, part 2

April 27, 2010

In my last post on this subject, I was trying to track down a good way to avoid setting the default for a collection typed Dependency Property in the constructor. See my the other post as to why this makes the property harder to style. I’ve come up with some interesting ideas, but there are still some interesting quirks with how the Xaml design surfaces treat these collections and the associated styles.

The root problem I was trying to address is that when you have xaml such as this:

<local:Palette x:Name="thePalette">
    <local:Palette.Colors>
        <Color>Blue</Color>
        <Color>Orange</Color>
    </local:Palette.Colors>
</local:Palette>

And you have a Color dependency property that is not initialized in the default value or the constructor but is initialized in the style:

<Setter Property="Colors">
    <Setter.Value>
        <local:ColorCollection>
            <Color>Red</Color>
            <Color>Blue</Color>
        </local:ColorCollection>
    </Setter.Value>
</Setter>

Then, oddly, things will appear to work correctly in the designer. Meanwhile, at runtime, as expected, when the Xaml parser goes to add the colors to the Colors property it will find that the Colors property is null.

Silverlight 4 actually gives a good way to avoid this behavior in the form of the ISupportInitialize event. When we have our control implement this class ISupportInitialize.BeginInit will be called when the Xaml parser starts parsing the element, and ISupportInitialize.EndInit will get called when the Xaml parser finishes parsing the element, before the style is applied. Thus, if we want to ensure that there is an empty local collection for the parser to fill, but not leave the collection as a local value if the parse doesn’t find any local values (so that the style precedence properties can apply), we can do something like this:

        private ColorCollection _initialColors =
            new ColorCollection();

        public void BeginInit()
        {
            if (ReadLocalValue(ColorsProperty) ==
                DependencyProperty.UnsetValue)
            {
                _initialColors.Clear();
                Colors = _initialColors;
            }
        }

        public void EndInit()
        {
            if (GetValue(ColorsProperty) == _initialColors &&
                _initialColors.Count == 0)
            {
                ClearValue(ColorsProperty);
            }
            UpdateColors();
        }

Which will basically set a local value as the Xaml parser begins to parse the element, but if no items are added to the collection, clear the value when done parsing, so that the style values can take precedence.

This seems to work for fixing the runtime problem. However, there seem to be other problems with creating style-able collection properties when it comes to the designer. If you, for example start typing out the Palette as above, the designer will apply its style before you even get to the Colors property, so, when you are adding the items to the Colors property collection, you will be modifying the collection from the default style of the Palette, so the Colors properties all Palette instances will be affected. Fun, huh? So I’m left wondering if its a good idea currently to try and create style-able collection-typed Dependency Properties with the current tool support, given their current behavior.

It would nice if we could somehow indicate to Blend/VS that this is the only correct way to specify the Colors collection in Xaml:

<local:Palette x:Name="thePalette">
    <local:Palette.Colors>
        <local:ColorCollection>
            <Color>Blue</Color>
            <Color>Orange</Color>
        </local:ColorCollection>
    </local:Palette.Colors>
</local:Palette>

But I haven’t come across a way to do this yet….


Proper pattern for defining collection type Dependency Properties?

April 23, 2010

I’ll relate a query that I recently posted on the Silverlight forums here, in case someone reading this has a good answer:

So, we all know that when creating a Dependency Property that has a collection type that setting a new collection instance as the default value in the metadata does not have the desired effect as that instance will be shared between all instances of the class as the default value of that property. So the correct solution is to initialize the collection instance in the constructor, see http://msdn.microsoft.com/en-us/library/cc903961(VS.95).aspx

But what if you want to set a value for this collection via a style? Or set its default value in the default style? For an example, see the Palette property on the Silverlight Toolkit chart. If we provide a value locally in the constructor, this will take precedence over the value provided in the style correct? Or if we avoid initializing the collection in the constructor, as in the Palette example, then this will not work:

<CustomControl.CollectionProperty>
   <CollectionItem />
   <CollectionItem />
</CustomControl.CollectionProperty>

only this will:

<CustomControl.CollectionProperty>
   <CollectionItemCollection>
       <CollectionItem />
       <CollectionItem />
   </CollectionItemCollection>
</CustomControl.CollectionProperty>

So, if you need a collection property to be stylable you can avoid setting it in the constructor and document that when used in xaml it needs a new collection instance to be instantiated. But what happens when tools like blend blithely create the former xml snippet when you use their collection editor?

Does anyone know a good pattern that allows for all these behaviors?


Dynamically generating types to implement INotifyPropertyChanged

April 13, 2010

As I mentioned in my last post, so much in Silverlight/WPF (especially when using MVVM) requires INotifyPropertyChanged for smooth operation that it would really be nice if there were first-class language support for augmenting classes in this way. INotifyPropertyChanged is pretty easily classified as a cross-cutting concern, I believe, and hence is a natural fit for aspect oriented programming techniques. For example, if its in your toolbelt, you could use Postsharp to do it pretty neatly, or other similar tools.

But, what I’m interested in, is if you want some simple code to implement this that stands alone and doesn’t have any external dependencies on 3rd party libraries, what would that look like? And how complicated is that? I was hoping to be able to use the new support for LambdaExpression.CompileToMethod in .NET 4 to make my life easier and avoid having to directly emit IL code, but it seems this API has some limitations (its only usable to generate static methods) at the moment that would prevent it being used in this manner. So, unfortunately, a degree in IL authoring is required to understand the code I’ll relate below.

The basic concept is that we will dynamically generate a type that inherits from the type for which we want to implement INotifyPropertyChanged. It will override the setters of any public or protected virtual properties, and raise the PropertyChanged event with the property name after the base setter has been called. This derived type implements the INotifyPropertyChanged event and is the actual type that you will create an instance for.

Things to note with this approach:

  1. This does not attempt to “wrap” a live instance of the class you trying to augment with the interface. It instead creates a derived type that you should instantiate rather than the actual type. This approach could be modified to wrap a live instance without too much additional effort.
  2. The implementation is not yet thread-safe.
  3. This approach relies on the public properties being marked as virtual so that they are overridable in the dynamically generated type.
  4. As I’m not actually using this code (its mostly an experiment, currently), it is a bit rough, so use at your own risk, and you may need to do some polishing, but this could act as a jumping off point if you are interested in this kind of approach, or or trying to learn more about runtime IL generation.
  5. This was written against the Silverlight subset of the Framework, so should work fine against Silverlight or WPF.

Let’s start with how you can use the code. If we have a class, Test:

public class Test
{
    public virtual double TestDouble { get; set; }
    public virtual string TestString { get; set; }
}

We can create an instance of it and use it in this way:

Test testObj = ProxyProvider.Instance.NewProxy<Test>();
(testObj as INotifyPropertyChanged).PropertyChanged +=
    (o, e) => System.Diagnostics.Debug.WriteLine(
    "property changed: " + e.PropertyName);
testObj.TestDouble = 5;
testObj.TestString = "testtest";

And when we run the application, the debug statements confirm that the property changed events are firing. So, how is this accomplished?

Let’s start with the rather boring singleton that furnishes the augmented types:

public class ProxyProvider
    {
        private static volatile ProxyProvider _instance = null;
        public static ProxyProvider Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new ProxyProvider();
                }
                return _instance;
            }
        }

        private ProxyProvider()
        {
        }

        private Dictionary<Type, Type> _proxyTypes = new Dictionary<Type, Type>();

        public T NewProxy<T>()
        {
            return (T)ProxyHelper(typeof(T));
        }

        private object ProxyHelper(Type type)
        {
            Type proxyType;
            if (_proxyTypes.TryGetValue(type, out proxyType))
            {
                return Activator.CreateInstance(proxyType);
            }
            else
            {
                proxyType =
                INotifyPropertyChangedProxyTypeGenerator
                .GenerateProxy(type);
                _proxyTypes.Add(type, proxyType);
                return Activator.CreateInstance(proxyType);
            }
        }

        public object NewProxy(Type type)
        {
            return ProxyHelper(type);
        }
    }

This basically just maintains a dictionary of generated types so they don’t need to be generated anew each time. The real work of the dynamic type generation is occurring in the INotifyPropertyChangedProxyTypeGenerator:

public class INotifyPropertyChangedProxyTypeGenerator
    {
        private static AssemblyBuilder _ab;
        private static ModuleBuilder _mb;

INotifyPropertyChangedProxyTypeGenerator needs some Reflection.Emit objects that aid in the construction of dynamic types. The AssemblyBuilder manages the dynamic assembly we are creating in memory, and the ModuleBuilder manages the module that will contain our types.

        public static Type GenerateProxy(Type type)
        {
            if (_ab == null)
            {
                var assmName = new AssemblyName("DynamicAssembly");
                _ab = AppDomain.CurrentDomain.DefineDynamicAssembly(
                             assmName,
                             AssemblyBuilderAccess.Run);
                _mb = _ab.DefineDynamicModule(assmName.Name);
            }

            // public class [TypeName]__proxy
            //    : [TypeName], INotifyPropertyChanged
            TypeBuilder typeBuilder = _mb.DefineType(
                type.Name + "__proxy", TypeAttributes.Public, type);
            typeBuilder.AddInterfaceImplementation(
            typeof(INotifyPropertyChanged));

            FieldBuilder eventField =
            CreatePropertyChangedEvent(typeBuilder);

            MethodBuilder raisePropertyChanged =
            CreateRaisePropertyChanged(typeBuilder, eventField);

            // get all the public or protected
            // virtual property setters.
            var props = from p in
                            type.GetProperties(
                                BindingFlags.Public |
                                BindingFlags.NonPublic |
                                BindingFlags.Instance |
                                BindingFlags.FlattenHierarchy)
                        where p.GetSetMethod().IsVirtual &&
                        (p.GetSetMethod().IsPublic ||
                        p.GetSetMethod().IsFamily)
                        select p;
            props.ToList().ForEach(
            (item) => WrapMethod(
            item, raisePropertyChanged, typeBuilder));

            Type ret = typeBuilder.CreateType();
            return ret;
        }

This is the top level script of actions that are required to generate the dynamic type:

  1. Assert that our AssemblyBuilder and ModuleBuilder are created.
  2. Create the dynamic type based off the original type’s name.
  3. Cause the new type to implement the interface INotifyPropertyChanged.
  4. Create the PropertyChanged event on the new type to implement the interface.
  5. Create a method on the new type called RaisePropertyChanged, which will be called from the property setters.
  6. For each public or protected virtual property, override the setter method, having each new setter call RaisePropertyChanged.
  7. Return the created type.

Now, let’s drill down further into how these steps are accomplished. First, let’s see how we create the PropertyChanged event:

        private static FieldBuilder CreatePropertyChangedEvent(
        TypeBuilder typeBuilder)
        {
            // public event PropertyChangedEventHandler PropertyChanged;

            FieldBuilder eventField =
                typeBuilder.DefineField("PropertyChanged",
                typeof(PropertyChangedEventHandler),
                FieldAttributes.Private);
            EventBuilder eventBuilder =
                typeBuilder.DefineEvent(
                "PropertyChanged",
                EventAttributes.None,
                typeof(PropertyChangedEventHandler));

            eventBuilder.SetAddOnMethod(
            CreateAddRemoveMethod(typeBuilder, eventField, true));
            eventBuilder.SetRemoveOnMethod(
            CreateAddRemoveMethod(typeBuilder, eventField, false));

            return eventField;
        }

The event consists of the actual event definition which has an Add method and a Remove method that indicate what occurs when users += or –= the event, and the delegate that will store the delegate chain associated with the event. This method will create the event and backing delegate definitions on the type, and then create the add and remove methods for the event by calling this method:

 private static MethodBuilder CreateAddRemoveMethod(
            TypeBuilder typeBuilder, FieldBuilder eventField, bool isAdd)
        {
            string prefix = "remove_";
            string delegateAction = "Remove";
            if (isAdd)
            {
                prefix = "add_";
                delegateAction = "Combine";
            }
            MethodBuilder addremoveMethod =
            typeBuilder.DefineMethod(prefix + "PropertyChanged",
               MethodAttributes.Public |
               MethodAttributes.SpecialName |
               MethodAttributes.NewSlot |
               MethodAttributes.HideBySig |
               MethodAttributes.Virtual |
               MethodAttributes.Final,
               null,
               new[] { typeof(PropertyChangedEventHandler) });
            MethodImplAttributes eventMethodFlags =
                MethodImplAttributes.Managed |
                MethodImplAttributes.Synchronized;
            addremoveMethod.SetImplementationFlags(eventMethodFlags);

            ILGenerator ilGen = addremoveMethod.GetILGenerator();

            // PropertyChanged += value; // PropertyChanged -= value;
            ilGen.Emit(OpCodes.Ldarg_0);
            ilGen.Emit(OpCodes.Ldarg_0);
            ilGen.Emit(OpCodes.Ldfld, eventField);
            ilGen.Emit(OpCodes.Ldarg_1);
            ilGen.EmitCall(OpCodes.Call,
                typeof(Delegate).GetMethod(
                delegateAction,
                new[] { typeof(Delegate), typeof(Delegate) }),
                null);
            ilGen.Emit(OpCodes.Castclass, typeof(
            PropertyChangedEventHandler));
            ilGen.Emit(OpCodes.Stfld, eventField);
            ilGen.Emit(OpCodes.Ret);

            MethodInfo intAddRemoveMethod =
            typeof(INotifyPropertyChanged).GetMethod(
            prefix + "PropertyChanged");
            typeBuilder.DefineMethodOverride(
            addremoveMethod, intAddRemoveMethod);

            return addremoveMethod;
        }

The add or remove method are constructed using the following steps:

  1. Create the method named add_PropertyChanged or remove_PropertyChanged. A good trick for determining method attributes or implementation flags (or method body for that matter) if you are unsure is to write what you are trying to emulate in c# and compile it, and then use Reflector to examine the IL code that was generated.
  2. Emit code that adds or removes the provided delegate to the backing delegate chain for the event.
  3. Specify that the method is overriding the expected method on the INotifyPropertyChanged interface.
  4. Return the resulting method.

The RaisePropertyChanged method we create will simply call the delegate chain backing the PropertyChanged event if it is non-null:

private static MethodBuilder CreateRaisePropertyChanged(
TypeBuilder typeBuilder, FieldBuilder eventField)
        {
            MethodBuilder raisePropertyChangedBuilder =
                typeBuilder.DefineMethod(
                "RaisePropertyChanged",
                MethodAttributes.Family | MethodAttributes.Virtual,
                null, new Type[] { typeof(string) });

            ILGenerator raisePropertyChangedIl =
            raisePropertyChangedBuilder.GetILGenerator();
            Label labelExit = raisePropertyChangedIl.DefineLabel();

            // if (PropertyChanged == null)
            // {
            //      return;
            // }
            raisePropertyChangedIl.Emit(OpCodes.Ldarg_0);
            raisePropertyChangedIl.Emit(OpCodes.Ldfld, eventField);
            raisePropertyChangedIl.Emit(OpCodes.Ldnull);
            raisePropertyChangedIl.Emit(OpCodes.Ceq);
            raisePropertyChangedIl.Emit(OpCodes.Brtrue, labelExit);

            // this.PropertyChanged(this,
            // new PropertyChangedEventArgs(propertyName));
            raisePropertyChangedIl.Emit(OpCodes.Ldarg_0);
            raisePropertyChangedIl.Emit(OpCodes.Ldfld, eventField);
            raisePropertyChangedIl.Emit(OpCodes.Ldarg_0);
            raisePropertyChangedIl.Emit(OpCodes.Ldarg_1);
            raisePropertyChangedIl.Emit(OpCodes.Newobj,
                typeof(PropertyChangedEventArgs)
                .GetConstructor(new[] { typeof(string) }));
            raisePropertyChangedIl.EmitCall(OpCodes.Callvirt,
                typeof(PropertyChangedEventHandler)
                .GetMethod("Invoke"), null);

            // return;
            raisePropertyChangedIl.MarkLabel(labelExit);
            raisePropertyChangedIl.Emit(OpCodes.Ret);

            return raisePropertyChangedBuilder;
        }

If you are new to IL generation and mostly use C#, the way that the if statement unrolls into, basically, a goto may be new to you. Although much more advanced, IL code is in many ways very similar to Assembly language due to the need to translate IL code into native code very efficiently. The IL code emitted here will check to see if the delegate chain associated with PropertyChanged is null in which case it will branch to the exit label and skip the invocation of the delegate chain.

Last but not least, here is how we will override each setter, call its base implementation and then call RaisePropertyChanged:

        private static void WrapMethod(PropertyInfo item,
        MethodBuilder raisePropertyChanged, TypeBuilder typeBuilder)
        {
            MethodInfo setMethod = item.GetSetMethod();

            //get an array of the parameter types.
            var types = from t in setMethod.GetParameters()
                        select t.ParameterType;

            MethodBuilder setMethodBuilder = typeBuilder.DefineMethod(
                setMethod.Name, setMethod.Attributes,
                setMethod.ReturnType, types.ToArray());
            typeBuilder.DefineMethodOverride(
            setMethodBuilder, setMethod);
            ILGenerator setMethodWrapperIl =
                setMethodBuilder.GetILGenerator();

            // base.[PropertyName] = value;
            setMethodWrapperIl.Emit(OpCodes.Ldarg_0);
            setMethodWrapperIl.Emit(OpCodes.Ldarg_1);
            setMethodWrapperIl.EmitCall(
            OpCodes.Call, setMethod, null);

            // RaisePropertyChanged("[PropertyName]");
            setMethodWrapperIl.Emit(OpCodes.Ldarg_0);
            setMethodWrapperIl.Emit(OpCodes.Ldstr, item.Name);
            setMethodWrapperIl.EmitCall(
            OpCodes.Call, raisePropertyChanged, null);

            // return;
            setMethodWrapperIl.Emit(OpCodes.Ret);
        }

The steps involved are:

  1. Create the method using the same settings of the Set method we are overriding.
  2. Emit IL that calls the base setter method.
  3. Emit IL that calls the RaisePropertyChanged method passing in the name of the current property.

And that’s basically it! We’ve created a dynamic assembly, a dynamic module and a dynamic type that inherits from the target type, but also implements INotifyPropertyChanged, and overrides any overridable setters and has them raise the PropertyChanged event! Pretty neat huh?

So what’s next? I’m somewhat satisfied with this because it employed a self contained and small amount of code to massively reduce the amount of boilerplate needed if you have a lot of types that need to implement this interface. But, really, it can be a bit too onerous or ill-advisable to absolutely require that properties be overridable to take advantage of this (not to mention error-prone!). So I think I’ll investigate what methods I might use to rewrite IL in an assembly as a post-compile step to improve on all this. The obvious and easiest choice is to use PostSharp to do this kind of IL rewriting, but as I and others are not always in a position to leverage 3rd party tools, I’m interested in how complex a stand-alone solution would be.

Well, until next time 😉


Windows Phone + Silverlight/XNA = Awesome

March 5, 2010

http://blogs.msdn.com/ckindel/archive/2010/03/04/different-means-better-with-the-new-windows-phone-developer-experience.aspx

Awesome 🙂