ActivityBuilderXamlWriter.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx40 / System.Activities / System / Activities / XamlIntegration / ActivityBuilderXamlWriter.cs / 1305376 / ActivityBuilderXamlWriter.cs

                            //---------------------------------------------------------------- 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//---------------------------------------------------------------

namespace System.Activities.XamlIntegration 
{
    using System.Collections.Generic; 
    using System.Globalization; 
    using System.IO;
    using System.Linq; 
    using System.Runtime;
    using System.Windows.Markup;
    using System.Xaml;
    using System.Xaml.Schema; 
    using System.Xml;
 
    // This class rewrites an  case (or null if not an ActivityBuilder),
        // so we need to compute this value dynamically
        XamlType activityBuilderXamlType; 
        XamlType activityXamlType;
 
        XamlType activityPropertyXamlType; 
        XamlType xamlTypeXamlType;
        XamlType typeXamlType; 
        XamlType activityPropertyReferenceXamlType;

        XamlMember activityPropertyType;
        XamlMember activityPropertyName; 
        XamlMember activityPropertyValue;
        XamlMember activityBuilderName; 
        XamlMember activityBuilderAttributes; 
        XamlMember activityBuilderProperties;
        XamlMember activityBuilderPropertyReference; 

        bool notRewriting;
        int currentDepth;
 
        // we need to accrue namespace so that we can resolve DynamicActivityProperty.Type
        // and correctly strip superfluous wrapper nodes around default values 
        NamespaceTable namespaceTable; 
        BuilderXamlNode currentState;
        Stack pendingStates; 

        public ActivityBuilderXamlWriter(XamlWriter innerWriter)
            : base()
        { 
            this.innerWriter = innerWriter;
            this.currentState = new RootNode(this); 
            this.namespaceTable = new NamespaceTable(); 
        }
 
        public override XamlSchemaContext SchemaContext
        {
            get
            { 
                return this.innerWriter.SchemaContext;
            } 
        } 

        void SetActivityType(XamlType activityXamlType, XamlType activityBuilderXamlType) 
        {
            if (activityXamlType == null)
            {
                this.notRewriting = true; 
            }
            else 
            { 
                this.activityXamlType = activityXamlType;
                this.activityBuilderXamlType = activityBuilderXamlType; 
                this.xamlTypeXamlType = this.SchemaContext.GetXamlType(typeof(XamlType));
                this.typeXamlType = this.SchemaContext.GetXamlType(typeof(Type));

                this.activityPropertyXamlType = this.SchemaContext.GetXamlType(typeof(DynamicActivityProperty)); 
                this.activityPropertyType = this.activityPropertyXamlType.GetMember("Type");
                this.activityPropertyName = this.activityPropertyXamlType.GetMember("Name"); 
                this.activityPropertyValue = this.activityPropertyXamlType.GetMember("Value"); 

                this.activityBuilderName = this.activityBuilderXamlType.GetMember("Name"); 
                this.activityBuilderAttributes = this.activityBuilderXamlType.GetMember("Attributes");
                this.activityBuilderProperties = this.activityBuilderXamlType.GetMember("Properties");
                this.activityBuilderPropertyReference = this.SchemaContext.GetXamlType(typeof(ActivityBuilder)).GetAttachableMember("PropertyReference");
                this.activityPropertyReferenceXamlType = this.SchemaContext.GetXamlType(typeof(ActivityPropertyReference)); 
            }
        } 
 
        public override void WriteNamespace(NamespaceDeclaration namespaceDeclaration)
        { 
            if (this.notRewriting)
            {
                this.innerWriter.WriteNamespace(namespaceDeclaration);
                return; 
            }
 
            if (this.namespaceTable != null) 
            {
                this.namespaceTable.AddNamespace(namespaceDeclaration); 
            }
            this.currentState.WriteNamespace(namespaceDeclaration);
        }
 
        public override void WriteValue(object value)
        { 
            if (this.notRewriting) 
            {
                this.innerWriter.WriteValue(value); 
                return;
            }

            this.currentState.WriteValue(value); 
        }
 
        public override void WriteStartObject(XamlType xamlType) 
        {
            if (this.notRewriting) 
            {
                this.innerWriter.WriteStartObject(xamlType);
                return;
            } 

            EnterDepth(); 
            this.currentState.WriteStartObject(xamlType); 
        }
 
        public override void WriteGetObject()
        {
            if (this.notRewriting)
            { 
                this.innerWriter.WriteGetObject();
                return; 
            } 

            EnterDepth(); 
            this.currentState.WriteGetObject();
        }

        public override void WriteEndObject() 
        {
            if (this.notRewriting) 
            { 
                this.innerWriter.WriteEndObject();
                return; 
            }

            this.currentState.WriteEndObject();
            ExitDepth(); 
        }
 
        public override void WriteStartMember(XamlMember xamlMember) 
        {
            if (this.notRewriting) 
            {
                this.innerWriter.WriteStartMember(xamlMember);
                return;
            } 

            EnterDepth(); 
            this.currentState.WriteStartMember(xamlMember); 
        }
 
        public override void WriteEndMember()
        {
            if (this.notRewriting)
            { 
                this.innerWriter.WriteEndMember();
                return; 
            } 

            this.currentState.WriteEndMember(); 
            ExitDepth();
        }

        void PushState(BuilderXamlNode state) 
        {
            if (this.pendingStates == null) 
            { 
                this.pendingStates = new Stack();
            } 
            this.pendingStates.Push(this.currentState);
            this.currentState = state;
        }
 
        void EnterDepth()
        { 
            Fx.Assert(!this.notRewriting, "we only use depth calculation if we're rewriting"); 
            this.currentDepth++;
            if (this.namespaceTable != null) 
            {
                this.namespaceTable.EnterScope();
            }
        } 

        void ExitDepth() 
        { 
            Fx.Assert(!this.notRewriting, "we only use depth calculation if we're rewriting");
            if (this.currentState.Depth == this.currentDepth) 
            {
                // complete the current state
                this.currentState.Complete();
 
                // and pop off the next state to look for
                if (this.pendingStates.Count > 0) 
                { 
                    this.currentState = this.pendingStates.Pop();
                } 
            }
            this.currentDepth--;
            if (this.namespaceTable != null)
            { 
                this.namespaceTable.ExitScope();
            } 
        } 

        protected override void Dispose(bool disposing) 
        {
            base.Dispose(disposing);
            if (disposing)
            { 
                ((IDisposable)this.innerWriter).Dispose();
            } 
        } 

        abstract class BuilderXamlNode 
        {
            protected BuilderXamlNode(ActivityBuilderXamlWriter writer)
            {
                this.Depth = writer.currentDepth; 
                this.Writer = writer;
                this.CurrentWriter = writer.innerWriter; 
            } 

            public int Depth 
            {
                get;
                private set;
            } 

            // a lot of nodes just redirect output, this 
            // allows them to avoid overriding everything just for that 
            public XamlWriter CurrentWriter
            { 
                get;
                protected set;
            }
 
            protected ActivityBuilderXamlWriter Writer
            { 
                get; 
                private set;
            } 

            protected internal virtual void Complete()
            {
            } 

            protected internal virtual void WriteNamespace(NamespaceDeclaration namespaceDeclaration) 
            { 
                CurrentWriter.WriteNamespace(namespaceDeclaration);
            } 

            protected internal virtual void WriteStartObject(XamlType xamlType)
            {
                CurrentWriter.WriteStartObject(xamlType); 
            }
 
            protected internal virtual void WriteGetObject() 
            {
                CurrentWriter.WriteGetObject(); 
            }

            protected internal virtual void WriteEndObject()
            { 
                CurrentWriter.WriteEndObject();
            } 
 
            protected internal virtual void WriteStartMember(XamlMember xamlMember)
            { 
                CurrentWriter.WriteStartMember(xamlMember);
            }

            protected internal virtual void WriteEndMember() 
            {
                CurrentWriter.WriteEndMember(); 
            } 

            protected internal virtual void WriteValue(object value) 
            {
                CurrentWriter.WriteValue(value);
            }
        } 

        // RootNode needs to buffer nodes until we finish processing Name + Properties 
        // because we need to insert our namespace _before_ the first StartObject. 
        // this is the starting value for ActivityBuilderXamlWriter.currentNode
        class RootNode : BuilderXamlNode 
        {
            const string PreferredXamlNamespaceAlias = "x";
            const string PreferredClassAlias = "this";
 
            bool wroteXamlNamespace;
            HashSet rootLevelPrefixes; 
 
            XamlNodeQueue pendingNodes;
 
            public RootNode(ActivityBuilderXamlWriter writer)
                : base(writer)
            {
                this.pendingNodes = new XamlNodeQueue(writer.SchemaContext); 
                base.CurrentWriter = this.pendingNodes.Writer;
            } 
 
            protected internal override void WriteNamespace(NamespaceDeclaration namespaceDeclaration)
            { 
                if (Writer.currentDepth == 0 && !this.wroteXamlNamespace)
                {
                    if (namespaceDeclaration.Namespace == XamlLanguage.Xaml2006Namespace)
                    { 
                        this.wroteXamlNamespace = true;
                    } 
                    else 
                    {
                        if (this.rootLevelPrefixes == null) 
                        {
                            this.rootLevelPrefixes = new HashSet();
                        }
                        this.rootLevelPrefixes.Add(namespaceDeclaration.Prefix); 
                    }
                } 
                base.WriteNamespace(namespaceDeclaration); 
            }
 
            protected internal override void WriteStartObject(XamlType xamlType)
            {
                if (Writer.currentDepth == 1)
                { 
                    XamlType activityXamlType = null;
 
                    // root object: see if we're serializing an ActivityBuilder 
                    if (xamlType.UnderlyingType == typeof(ActivityBuilder))
                    { 
                        activityXamlType = Writer.SchemaContext.GetXamlType(typeof(Activity));
                    }
                    // or an ActivityBuilder
                    else if (xamlType.IsGeneric && xamlType.UnderlyingType != null 
                        && xamlType.UnderlyingType.GetGenericTypeDefinition() == typeof(ActivityBuilder<>))
                    { 
                        Type activityType = xamlType.TypeArguments[0].UnderlyingType; 
                        activityXamlType = Writer.SchemaContext.GetXamlType(typeof(Activity<>).MakeGenericType(activityType));
                    } 

                    Writer.SetActivityType(activityXamlType, xamlType);

                    if (activityXamlType != null) 
                    {
                        Writer.PushState(new BuilderClassNode(this, Writer)); 
                        return; 
                    }
                    else 
                    {
                        // we should be a pass through. Flush any buffered nodes and get out of the way
                        FlushPendingNodes(null);
                    } 
                }
                base.WriteStartObject(xamlType); 
            } 

            public void FlushPendingNodes(string classNamespace) 
            {
                base.CurrentWriter = this.Writer.innerWriter;
                if (!Writer.notRewriting)
                { 
                    // make sure we have any required namespaces
                    if (!this.wroteXamlNamespace) 
                    { 
                        string xamlNamespaceAlias = GenerateNamespacePrefix(PreferredXamlNamespaceAlias);
                        this.WriteNamespace(new NamespaceDeclaration(XamlLanguage.Xaml2006Namespace, xamlNamespaceAlias)); 
                    }

                    // If there's an x:Class="Foo.Bar", add a namespace declaration for Foo in the local assembly so we can
                    // say stuff like this:Bar.MyProperty later on. DON'T add the namespace declaration if somebody has already 
                    // declared the namespace in the nodestream though (duplicates are an error).
                    if (classNamespace != null) 
                    { 
                        bool sawClassNamespace = false;
 
                        XamlReader reader = this.pendingNodes.Reader;
                        XamlWriter writer = this.Writer.innerWriter;
                        while (reader.Read() && reader.NodeType == XamlNodeType.NamespaceDeclaration)
                        { 
                            if (classNamespace.Equals(reader.Namespace.Namespace))
                            { 
                                sawClassNamespace = true; 
                            }
                            writer.WriteNode(reader); 
                        }

                        if (!sawClassNamespace)
                        { 
                            string classNamespaceAlias = GenerateNamespacePrefix(PreferredClassAlias);
                            writer.WriteNamespace(new NamespaceDeclaration(classNamespace, classNamespaceAlias)); 
                        } 

                        // We may have consumed the first non-namespace node off the reader in order 
                        // to check it for being a NamespaceDeclaration. Make sure it still gets written.
                        if(!reader.IsEof)
                        {
                            writer.WriteNode(reader); 
                        }
                    } 
 
                    this.rootLevelPrefixes = null; // not needed anymore
                } 

                XamlServices.Transform(this.pendingNodes.Reader, this.Writer.innerWriter, false);
                this.pendingNodes = null;
            } 

            string GenerateNamespacePrefix(string desiredPrefix) 
            { 
                string aliasPostfix = string.Empty;
                // try postfixing 1-1000 first 
                for (int i = 1; i <= 1000; i++)
                {
                    string alias = desiredPrefix + aliasPostfix;
                    if (!this.rootLevelPrefixes.Contains(alias)) 
                    {
                        return alias; 
                    } 
                    aliasPostfix = i.ToString(CultureInfo.InvariantCulture);
                } 

                // fall back to GUID
                return desiredPrefix + Guid.NewGuid().ToString();
            } 
        }
 
        // ... 
        class BuilderClassNode : BuilderXamlNode
        { 
            RootNode rootNode;

            string xClassNamespace;
            XamlType xClassXamlType; 
            XamlNodeQueue xClassNodes;
            XamlNodeQueue xClassAttributeNodes; 
            XamlNodeQueue xPropertiesNodes; 
            XamlNodeQueue otherNodes;
            List> defaultValueNodes; 

            public BuilderClassNode(RootNode rootNode, ActivityBuilderXamlWriter writer)
                : base(writer)
            { 
                this.rootNode = rootNode;
 
                // by default, if we're not in a special sub-tree, ferret the nodes away on the side 
                this.otherNodes = new XamlNodeQueue(writer.SchemaContext);
                base.CurrentWriter = this.otherNodes.Writer; 
            }

            public void SetXClass(string builderName, XamlNodeQueue nameNodes)
            { 
                this.xClassNodes = new XamlNodeQueue(Writer.SchemaContext);
                this.xClassNodes.Writer.WriteStartMember(XamlLanguage.Class); 
                this.xClassNamespace = null; 
                string xClassName = builderName;
                if (string.IsNullOrEmpty(xClassName)) 
                {
                    xClassName = string.Format(CultureInfo.CurrentCulture, "_{0}", Guid.NewGuid().ToString().Replace("-", string.Empty).Substring(0, 4));
                }
 
                if (nameNodes != null)
                { 
                    XamlServices.Transform(nameNodes.Reader, this.xClassNodes.Writer, false); 
                }
                else 
                {
                    this.xClassNodes.Writer.WriteValue(xClassName);
                    this.xClassNodes.Writer.WriteEndMember();
                } 

                int nameStartIndex = xClassName.LastIndexOf('.'); 
                if (nameStartIndex > 0) 
                {
                    this.xClassNamespace = builderName.Substring(0, nameStartIndex); 
                    xClassName = builderName.Substring(nameStartIndex + 1);
                }

                this.xClassNamespace = string.Format(CultureInfo.CurrentUICulture, "clr-namespace:{0}", this.xClassNamespace ?? string.Empty); 
                this.xClassXamlType = new XamlType(this.xClassNamespace, xClassName, null, Writer.SchemaContext);
            } 
 
            // Attributes [DependsOn("Name")]
            public void SetAttributes(XamlNodeQueue attributeNodes) 
            {
                this.xClassAttributeNodes = attributeNodes;
            }
 
            // Properties [DependsOn("Attributes")]
            public void SetProperties(XamlNodeQueue propertyNodes, List> defaultValueNodes) 
            { 
                this.xPropertiesNodes = propertyNodes;
                this.defaultValueNodes = defaultValueNodes; 

                // exiting the properties tag. So we've now accrued any instances of Name and Attributes
                // that could possibly be hit flush our preamble
                FlushPreamble(); 
            }
 
            void FlushPreamble() 
            {
                if (this.otherNodes == null) // already flushed 
                {
                    return;
                }
                CurrentWriter = this.Writer.innerWriter; 
                string classNamespace = null;
                // first, see if we need to emit a namespace corresponding to our class 
                if (this.defaultValueNodes != null) 
                {
                    classNamespace = this.xClassNamespace; 
                }

                this.rootNode.FlushPendingNodes(classNamespace);
                this.rootNode = null; // not needed anymore 

                CurrentWriter.WriteStartObject(this.Writer.activityXamlType); 
 
                // first dump x:Class
                if (this.xClassNodes == null) 
                {
                    SetXClass(null, null); // this will setup a default
                }
                XamlServices.Transform(this.xClassNodes.Reader, CurrentWriter, false); 

                // String default values get written in attribute form immediately. 
                // Other values get deferred until after x:Members, etc. 
                XamlNodeQueue deferredPropertyNodes = null;
                if (this.defaultValueNodes != null) 
                {
                    foreach (KeyValuePair defaultValueNode in this.defaultValueNodes)
                    {
                        XamlReader reader = defaultValueNode.Value.Reader; 
                        if (reader.Read())
                        { 
                            bool isStringValue = false; 
                            if (reader.NodeType == XamlNodeType.Value)
                            { 
                                string stringValue = reader.Value as string;
                                if (stringValue != null)
                                {
                                    isStringValue = true; 
                                }
                            } 
                            if (isStringValue) 
                            {
                                CurrentWriter.WriteStartMember(new XamlMember(defaultValueNode.Key, this.xClassXamlType, true)); 
                                CurrentWriter.WriteNode(reader);
                                XamlServices.Transform(defaultValueNode.Value.Reader, CurrentWriter, false);
                                // don't need an EndMember since it will be sitting in the node list (we only needed to strip the StartMember)
                            } 
                            else
                            { 
                                // Else: We'll write this out in a minute, after the x:ClassAttributes and x:Properties 
                                if (deferredPropertyNodes == null)
                                { 
                                    deferredPropertyNodes = new XamlNodeQueue(Writer.SchemaContext);
                                }
                                deferredPropertyNodes.Writer.WriteStartMember(new XamlMember(defaultValueNode.Key, this.xClassXamlType, true));
                                deferredPropertyNodes.Writer.WriteNode(reader); 
                                XamlServices.Transform(defaultValueNode.Value.Reader, deferredPropertyNodes.Writer, false);
                            } 
                        } 
                    }
                } 

                // then dump x:ClassAttributes if we have any
                if (this.xClassAttributeNodes != null)
                { 
                    XamlServices.Transform(this.xClassAttributeNodes.Reader, CurrentWriter, false);
                } 
 
                // and x:Properties
                if (this.xPropertiesNodes != null) 
                {
                    XamlServices.Transform(this.xPropertiesNodes.Reader, CurrentWriter, false);
                }
 
                if (deferredPropertyNodes != null)
                { 
                    XamlServices.Transform(deferredPropertyNodes.Reader, CurrentWriter, false); 
                }
 
                if (this.otherNodes.Count > 0)
                {
                    XamlServices.Transform(this.otherNodes.Reader, CurrentWriter, false);
                } 
                this.otherNodes = null; // done with this
            } 
 
            protected internal override void Complete()
            { 
                if (this.otherNodes != null)
                {
                    // need to flush
                    FlushPreamble(); 
                }
            } 
 
            protected internal override void WriteStartMember(XamlMember xamlMember)
            { 
                if (Writer.currentDepth == this.Depth + 1 && !xamlMember.IsAttachable)
                {
                    if (xamlMember == Writer.activityBuilderName)
                    { 
                        // record that we're in ActivityBuilder.Name, since we'll need the class name for
                        // default value output 
                        Writer.PushState(new BuilderNameNode(this, Writer)); 
                        return;
                    } 
                    else if (xamlMember == Writer.activityBuilderAttributes)
                    {
                        // rewrite ActivityBuilder.Attributes to x:ClassAttributes
                        Writer.PushState(new AttributesNode(this, Writer)); 
                        return;
                    } 
                    else if (xamlMember == Writer.activityBuilderProperties) 
                    {
                        // rewrite ActivityBuilder.Properties to x:Members 
                        Writer.PushState(new PropertiesNode(this, Writer));
                        return;
                    }
                    else 
                    {
                        // any other member means we've passed properties due to [DependsOn] relationships 
                        FlushPreamble(); 
                        if (xamlMember.DeclaringType == Writer.activityBuilderXamlType)
                        { 
                            // Rewrite "" to ""
                            xamlMember = Writer.activityXamlType.GetMember(xamlMember.Name);
                            if (xamlMember == null)
                            { 
                                throw FxTrace.Exception.AsError(new InvalidOperationException(
                                    SR.MemberNotSupportedByActivityXamlServices(xamlMember.Name))); 
                            } 

                            if (xamlMember.Name == "Implementation") 
                            {
                                Writer.PushState(new ImplementationNode(Writer));
                            }
                        } 
                    }
                } 
                base.WriteStartMember(xamlMember); 
            }
        } 

        //  node that we'll map to x:Class
        class BuilderNameNode : BuilderXamlNode
        { 
            BuilderClassNode classNode;
            string builderName; 
            XamlNodeQueue nameNodes; 

            public BuilderNameNode(BuilderClassNode classNode, ActivityBuilderXamlWriter writer) 
                : base(writer)
            {
                this.classNode = classNode;
                this.nameNodes = new XamlNodeQueue(writer.SchemaContext); 
                base.CurrentWriter = this.nameNodes.Writer;
            } 
 
            protected internal override void Complete()
            { 
                this.classNode.SetXClass(this.builderName, this.nameNodes);
            }

            protected internal override void WriteValue(object value) 
            {
                if (Writer.currentDepth == this.Depth) 
                { 
                    this.builderName = (string)value;
                } 

                base.WriteValue(value);
            }
        } 

        //  node that we'll map to x:ClassAttributes 
        class AttributesNode : BuilderXamlNode 
        {
            XamlNodeQueue attributeNodes; 
            BuilderClassNode classNode;

            public AttributesNode(BuilderClassNode classNode, ActivityBuilderXamlWriter writer)
                : base(writer) 
            {
                this.classNode = classNode; 
                this.attributeNodes = new XamlNodeQueue(writer.SchemaContext); 
                base.CurrentWriter = this.attributeNodes.Writer;
                CurrentWriter.WriteStartMember(XamlLanguage.ClassAttributes); 
            }

            protected internal override void Complete()
            { 
                this.classNode.SetAttributes(this.attributeNodes);
            } 
        } 

        //  node that we'll map to x:Members 
        // since x:Members doesn't have GetObject/StartMember wrappers around the value, we need to eat those
        class PropertiesNode : BuilderXamlNode
        {
            List> defaultValueNodes; 
            XamlNodeQueue propertiesNodes;
            BuilderClassNode classNode; 
            bool skipGetObject; 

            public PropertiesNode(BuilderClassNode classNode, ActivityBuilderXamlWriter writer) 
                : base(writer)
            {
                this.classNode = classNode;
                this.propertiesNodes = new XamlNodeQueue(writer.SchemaContext); 
                base.CurrentWriter = this.propertiesNodes.Writer;
                CurrentWriter.WriteStartMember(XamlLanguage.Members); 
            } 

            protected internal override void WriteStartObject(XamlType xamlType) 
            {
                if (xamlType == Writer.activityPropertyXamlType && Writer.currentDepth == this.Depth + 3)
                {
                    xamlType = XamlLanguage.Property; 
                    Writer.PushState(new PropertyNode(this, Writer));
                } 
                base.WriteStartObject(xamlType); 
            }
 
            protected internal override void WriteGetObject()
            {
                if (Writer.currentDepth == this.Depth + 1)
                { 
                    this.skipGetObject = true;
                } 
                else 
                {
                    base.WriteGetObject(); 
                }
            }

            protected internal override void WriteEndObject() 
            {
                if (this.skipGetObject && Writer.currentDepth == this.Depth + 1) 
                { 
                    this.skipGetObject = false;
                } 
                else
                {
                    base.WriteEndObject();
                } 
            }
 
            protected internal override void WriteStartMember(XamlMember xamlMember) 
            {
                if (this.skipGetObject && Writer.currentDepth == this.Depth + 2) 
                {
                    return;
                }
                base.WriteStartMember(xamlMember); 
            }
 
            protected internal override void WriteEndMember() 
            {
                if (this.skipGetObject && Writer.currentDepth == this.Depth + 2) 
                {
                    return;
                }
                base.WriteEndMember(); 
            }
 
            protected internal override void Complete() 
            {
                this.classNode.SetProperties(this.propertiesNodes, this.defaultValueNodes); 
            }

            public void AddDefaultValue(string propertyName, XamlNodeQueue value)
            { 
                if (this.defaultValueNodes == null)
                { 
                    this.defaultValueNodes = new List>(); 
                }
 
                if (string.IsNullOrEmpty(propertyName))
                {
                    // default a name if one doesn't exist
                    propertyName = string.Format(CultureInfo.CurrentCulture, "_{0}", Guid.NewGuid().ToString().Replace("-", string.Empty)); 
                }
 
                this.defaultValueNodes.Add(new KeyValuePair(propertyName, value)); 
            }
        } 

        // ...
        class PropertyNode : BuilderXamlNode
        { 
            PropertiesNode properties;
            string propertyName; 
            XamlType propertyType; 
            XamlNodeQueue defaultValue;
 
            public PropertyNode(PropertiesNode properties, ActivityBuilderXamlWriter writer)
                : base(writer)
            {
                this.properties = properties; 
                base.CurrentWriter = properties.CurrentWriter;
            } 
 
            public void SetName(string name)
            { 
                this.propertyName = name;
            }

            public void SetType(XamlType type) 
            {
                this.propertyType = type; 
            } 

            public void SetDefaultValue(XamlNodeQueue defaultValue) 
            {
                this.defaultValue = defaultValue;
            }
 
            protected internal override void WriteStartMember(XamlMember xamlMember)
            { 
                if (xamlMember.DeclaringType == Writer.activityPropertyXamlType && Writer.currentDepth == this.Depth + 1) 
                {
                    if (xamlMember == Writer.activityPropertyName) 
                    {
                        // record that we're in a property name, since we'll need this for default value output
                        Writer.PushState(new PropertyNameNode(this, Writer));
                        xamlMember = DynamicActivityXamlReader.xPropertyName; 
                    }
                    else if (xamlMember == Writer.activityPropertyType) 
                    { 
                        // record that we're in a property type, since we'll need this for default value output
                        Writer.PushState(new PropertyTypeNode(this, Writer)); 
                        xamlMember = DynamicActivityXamlReader.xPropertyType;
                    }
                    else if (xamlMember == Writer.activityPropertyValue)
                    { 
                        // record that we're in a property value, since we'll need this for default value output.
                        // don't write anything since we'll dump the default values after we exit ActivityBuilder.Properties 
                        Writer.PushState(new PropertyValueNode(this, Writer)); 
                        xamlMember = null;
                    } 
                }

                if (xamlMember != null)
                { 
                    base.WriteStartMember(xamlMember);
                } 
            } 

            protected internal override void Complete() 
            {
                if (this.defaultValue != null)
                {
                    if (string.IsNullOrEmpty(this.propertyName)) 
                    {
                        // default a name if one doesn't exist 
                        this.propertyName = string.Format(CultureInfo.CurrentCulture, "_{0}", Guid.NewGuid().ToString().Replace("-", string.Empty)); 
                    }
 
                    if (this.defaultValue != null && this.propertyType != null)
                    {
                        // post-process the default value nodes to strip out
                        // StartObject+StartMember _Initialization+EndMember+EndObject 
                        // wrapper nodes if the type of the object matches the
                        // property Type (since we are moving from "object Value" to "T Value" 
                        this.defaultValue = StripTypeWrapping(this.defaultValue, this.propertyType); 
                    }
 
                    this.properties.AddDefaultValue(this.propertyName, this.defaultValue);
                }
            }
 
            static XamlNodeQueue StripTypeWrapping(XamlNodeQueue valueNodes, XamlType propertyType)
            { 
                XamlNodeQueue targetNodes = new XamlNodeQueue(valueNodes.Reader.SchemaContext); 
                XamlReader source = valueNodes.Reader;
                XamlWriter target = targetNodes.Writer; 
                int depth = 0;
                bool consumeWrapperEndTags = false;
                bool hasBufferedStartObject = false;
 
                while (source.Read())
                { 
                    switch (source.NodeType) 
                    {
                        case XamlNodeType.StartObject: 
                            depth++;
                            // only strip the wrapping type nodes if we have exactly this sequence:
                            // StartObject StartMember(Intialization) Value EndMember EndObject.
                            if (targetNodes.Count == 0 && depth == 1 && source.Type == propertyType && valueNodes.Count == 5) 
                            {
                                hasBufferedStartObject = true; 
                                continue; 
                            }
                            break; 

                        case XamlNodeType.GetObject:
                            depth++;
                            break; 

                        case XamlNodeType.StartMember: 
                            depth++; 
                            if (hasBufferedStartObject)
                            { 
                                if (depth == 2 && source.Member == XamlLanguage.Initialization)
                                {
                                    consumeWrapperEndTags = true;
                                    continue; 
                                }
                                else 
                                { 
                                    hasBufferedStartObject = false;
                                    targetNodes.Writer.WriteStartObject(propertyType); 
                                }
                            }
                            break;
 
                        case XamlNodeType.EndMember:
                            depth--; 
                            if (consumeWrapperEndTags && depth == 1) 
                            {
                                continue; 
                            }
                            break;

                        case XamlNodeType.EndObject: 
                            depth--;
                            if (consumeWrapperEndTags && depth == 0) 
                            { 
                                consumeWrapperEndTags = false;
                                continue; 
                            }
                            break;
                    }
 
                    target.WriteNode(source);
                } 
 
                return targetNodes;
            } 
        }

        // ...
        class PropertyNameNode : BuilderXamlNode 
        {
            PropertyNode property; 
 
            public PropertyNameNode(PropertyNode property, ActivityBuilderXamlWriter writer)
                : base(writer) 
            {
                this.property = property;
                base.CurrentWriter = property.CurrentWriter;
            } 

            protected internal override void WriteValue(object value) 
            { 
                if (Writer.currentDepth == this.Depth)
                { 
                    property.SetName((string)value);
                }

                base.WriteValue(value); 
            }
        } 
 
        // ...
        class PropertyTypeNode : BuilderXamlNode 
        {
            PropertyNode property;

            public PropertyTypeNode(PropertyNode property, ActivityBuilderXamlWriter writer) 
                : base(writer)
            { 
                this.property = property; 
                base.CurrentWriter = property.CurrentWriter;
            } 

            protected internal override void WriteValue(object value)
            {
                if (Writer.currentDepth == this.Depth) 
                {
                    // We only support property type as an attribute 
                    XamlTypeName xamlTypeName = XamlTypeName.Parse(value as string, Writer.namespaceTable); 
                    XamlType xamlType = Writer.SchemaContext.GetXamlType(xamlTypeName);
                    property.SetType(xamlType); // supports null 
                }

                base.WriteValue(value);
            } 
        }
 
        // ... 
        class PropertyValueNode : BuilderXamlNode
        { 
            PropertyNode property;
            XamlNodeQueue valueNodes;

            public PropertyValueNode(PropertyNode property, ActivityBuilderXamlWriter writer) 
                : base(writer)
            { 
                this.property = property; 
                this.valueNodes = new XamlNodeQueue(writer.SchemaContext);
                base.CurrentWriter = this.valueNodes.Writer; 
            }

            protected internal override void Complete()
            { 
                this.property.SetDefaultValue(this.valueNodes);
                base.Complete(); 
            } 
        }
 
        // ...
        // we need to track objects instantiated in here so that PropertyReferenceExtension
        // usages can be mapped appropriately
        class ImplementationNode : BuilderXamlNode 
        {
            Stack objectTypes; // objectType.Peek is the XamlType of the object we are currently writing 
            Stack xamlMembers; // xamlMembers.Peek is the XamlType of the nearest StartMember. Needed to compute type of GetObject. 

            public ImplementationNode(ActivityBuilderXamlWriter writer) 
                : base(writer)
            {
                this.objectTypes = new Stack();
                this.xamlMembers = new Stack(); 
            }
 
            // Transform  subtree into  IF there's 
            // enough type information to do so, otherwise leave it alone. (There will always be enough type info if the XAML
            // stream is valid, but we'd rather produce an invalid nodestream than throw an exception so the downstream 
            // consumer can examine the invalid nodestream and decide who's responsible.)
            protected internal override void WriteStartMember(XamlMember xamlMember)
            {
                if (xamlMember == Writer.activityBuilderPropertyReference && this.objectTypes.Count > 0 && this.objectTypes.Peek() != null) 
                {
                    // Bypass the StartMember, and delegate processing of this node to a PropertyReferenceNode 
                    // for whatever type of object we're writing. 
                    // Don't need to keep track of xamlMember because by the time we get back to this
                    // ImplementationNode the corresponding EndMember will already have been written. 
                    Writer.PushState(new PropertyReferenceNode(this.objectTypes.Peek(), Writer, xamlMember));
                }
                else
                { 
                    this.xamlMembers.Push(xamlMember);
                    base.WriteStartMember(xamlMember); 
                } 
            }
 
            protected internal override void WriteStartObject(XamlType xamlType)
            {
                this.objectTypes.Push(xamlType);
                base.WriteStartObject(xamlType); 
            }
 
            protected internal override void WriteGetObject() 
            {
                if(this.xamlMembers.Peek() == null) 
                {
                    this.objectTypes.Push(null); // Nodestream is invalid, just treat xamlType as unknown.
                }
                else 
                {
                    this.objectTypes.Push(this.xamlMembers.Peek().Type); 
                } 
                base.WriteGetObject();
            } 

            protected internal override void WriteEndObject()
            {
                this.objectTypes.Pop(); 
                base.WriteEndObject();
            } 
 
            protected internal override void WriteEndMember()
            { 
                // (Writer.currentDepth == this.Depth) means the ImplementationNode itself is being popped--stack will be empty
                if(Writer.currentDepth > this.Depth)
                {
                    this.xamlMembers.Pop(); 
                }
                base.WriteEndMember(); 
            } 
        }
 
        // ... maps to 
        class PropertyReferenceNode : BuilderXamlNode
        {
            XamlNodeQueue propertyReferenceNodes; 
            XamlType owningType;
            string sourceProperty; 
            string targetProperty; 
            bool inSourceProperty;
            bool inTargetProperty; 
            XamlMember originalStartMember;

            public PropertyReferenceNode(XamlType owningType, ActivityBuilderXamlWriter writer, XamlMember originalStartMember)
                : base(writer) 
            {
                this.owningType = owningType; 
                this.propertyReferenceNodes = new XamlNodeQueue(writer.SchemaContext); 

                // save any original output since we might not spit out our own nodes 
                this.originalStartMember = originalStartMember;
                base.CurrentWriter = this.propertyReferenceNodes.Writer;
            }
 
            protected internal override void WriteStartMember(XamlMember xamlMember)
            { 
                if (Writer.currentDepth == this.Depth + 2 // SO + SM 
                    && xamlMember.DeclaringType == Writer.activityPropertyReferenceXamlType)
                { 
                    if (xamlMember.Name == "SourceProperty")
                    {
                        this.inSourceProperty = true;
                    } 
                    else if (xamlMember.Name == "TargetProperty")
                    { 
                        this.inTargetProperty = true; 
                    }
                } 
                base.WriteStartMember(xamlMember); // save output just in case
            }

            protected internal override void WriteValue(object value) 
            {
                if (this.inSourceProperty) 
                { 
                    this.sourceProperty = (string)value;
                } 
                else if (this.inTargetProperty)
                {
                    this.targetProperty = (string)value;
                } 
                base.WriteValue(value); // save output just in case
            } 
 
            protected internal override void WriteEndMember()
            { 
                if (Writer.currentDepth == this.Depth + 2)
                {
                    this.inSourceProperty = false;
                    this.inTargetProperty = false; 
                }
                base.WriteEndMember(); // save output just in case 
            } 

            protected internal override void Complete() 
            {
                // write directly to the parent writer

                if(this.targetProperty == null) 
                {
                    // can't transform to , dump original nodes  
                    Writer.innerWriter.WriteStartMember(this.originalStartMember); 
                    XamlServices.Transform(this.propertyReferenceNodes.Reader, Writer.innerWriter, false);
                } 
                else
                {
                    // transform to 
                    XamlMember propertyMember = this.owningType.GetMember(this.targetProperty); 
                    if(propertyMember == null)
                    { 
                        // Xaml refers to invalid property, but transform it anyway on the assumption that 
                        // it came from  form.
                        propertyMember = new XamlMember(this.targetProperty, this.owningType, false); 
                    }
                    Writer.innerWriter.WriteStartMember(propertyMember);
                    XamlType propertyReferenceType = Writer.SchemaContext.GetXamlType(typeof(PropertyReferenceExtension<>).MakeGenericType(propertyMember.Type.UnderlyingType));
                    Writer.innerWriter.WriteStartObject(propertyReferenceType); 
                    Writer.innerWriter.WriteStartMember(propertyReferenceType.GetMember("PropertyName"));
                    Writer.innerWriter.WriteValue(this.sourceProperty); 
                    Writer.innerWriter.WriteEndMember(); 
                    Writer.innerWriter.WriteEndObject();
                    Writer.innerWriter.WriteEndMember(); 
                }
            }
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK