Esempio n. 1
0
        static void SetDataTemplate(IElementNode parentNode, ElementNode node, ILContext parentContext,
                                    IXmlLineInfo xmlLineInfo)
        {
            var parentVar = parentContext.Variables[parentNode];

            //Push the DataTemplate to the stack, for setting the template
            parentContext.IL.Emit(OpCodes.Ldloc, parentVar);

            //Create nested class
            //			.class nested private auto ansi sealed beforefieldinit '<Main>c__AnonStorey0'
            //			extends [mscorlib]System.Object

            var module   = parentContext.Body.Method.Module;
            var anonType = new TypeDefinition(
                null,
                "<" + parentContext.Body.Method.Name + ">_anonXamlCDataTemplate_" + dtcount++,
                TypeAttributes.BeforeFieldInit |
                TypeAttributes.Sealed |
                TypeAttributes.NestedPrivate)
            {
                BaseType = module.TypeSystem.Object
            };

            parentContext.Body.Method.DeclaringType.NestedTypes.Add(anonType);
            var ctor = anonType.AddDefaultConstructor();

            var loadTemplate = new MethodDefinition("LoadDataTemplate",
                                                    MethodAttributes.Assembly | MethodAttributes.HideBySig,
                                                    module.TypeSystem.Object);

            anonType.Methods.Add(loadTemplate);

            var parentValues = new FieldDefinition("parentValues", FieldAttributes.Assembly, module.Import(typeof(object[])));

            anonType.Fields.Add(parentValues);

            TypeReference rootType = null;
            var           vdefRoot = parentContext.Root as VariableDefinition;

            if (vdefRoot != null)
            {
                rootType = vdefRoot.VariableType;
            }
            var fdefRoot = parentContext.Root as FieldDefinition;

            if (fdefRoot != null)
            {
                rootType = fdefRoot.FieldType;
            }

            var root = new FieldDefinition("root", FieldAttributes.Assembly, rootType);

            anonType.Fields.Add(root);

            //Fill the loadTemplate Body
            var templateIl = loadTemplate.Body.GetILProcessor();

            templateIl.Emit(OpCodes.Nop);
            var templateContext = new ILContext(templateIl, loadTemplate.Body, parentValues)
            {
                Root = root
            };

            node.Accept(new CreateObjectVisitor(templateContext), null);
            node.Accept(new SetNamescopesAndRegisterNamesVisitor(templateContext), null);
            node.Accept(new SetFieldVisitor(templateContext), null);
            node.Accept(new SetResourcesVisitor(templateContext), null);
            node.Accept(new SetPropertiesVisitor(templateContext), null);
            templateIl.Emit(OpCodes.Ldloc, templateContext.Variables[node]);
            templateIl.Emit(OpCodes.Ret);

            //Instanciate nested class
            var parentIl = parentContext.IL;

            parentIl.Emit(OpCodes.Newobj, ctor);

            //Copy required local vars
            parentIl.Emit(OpCodes.Dup);             //Duplicate the nestedclass instance
            parentIl.Append(node.PushParentObjectsArray(parentContext));
            parentIl.Emit(OpCodes.Stfld, parentValues);
            parentIl.Emit(OpCodes.Dup);             //Duplicate the nestedclass instance
            if (parentContext.Root is VariableDefinition)
            {
                parentIl.Emit(OpCodes.Ldloc, parentContext.Root as VariableDefinition);
            }
            else if (parentContext.Root is FieldDefinition)
            {
                parentIl.Emit(OpCodes.Ldarg_0);
                parentIl.Emit(OpCodes.Ldfld, parentContext.Root as FieldDefinition);
            }
            else
            {
                throw new InvalidProgramException();
            }
            parentIl.Emit(OpCodes.Stfld, root);

            //SetDataTemplate
            parentIl.Emit(OpCodes.Ldftn, loadTemplate);
            var funcObjRef = module.Import(typeof(Func <object>));
            var funcCtor   =
                funcObjRef
                .Resolve()
                .Methods.First(md => md.IsConstructor && md.Parameters.Count == 2)
                .ResolveGenericParameters(funcObjRef, module);

            parentIl.Emit(OpCodes.Newobj, module.Import(funcCtor));

#pragma warning disable 0612
            var propertySetter =
                module.Import(typeof(IDataTemplate)).Resolve().Properties.First(p => p.Name == "LoadTemplate").SetMethod;
#pragma warning restore 0612
            parentContext.IL.Emit(OpCodes.Callvirt, module.Import(propertySetter));
        }