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 ancase (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 { StackobjectTypes; // 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 toclass 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
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- BufferedWebEventProvider.cs
- SafeMarshalContext.cs
- Converter.cs
- DataReceivedEventArgs.cs
- XpsDocument.cs
- HttpWebResponse.cs
- ObjectIDGenerator.cs
- PropertyExpression.cs
- BinaryFormatterWriter.cs
- ChtmlTextBoxAdapter.cs
- WebPartHelpVerb.cs
- ActivityStatusChangeEventArgs.cs
- KeyboardNavigation.cs
- AdRotatorDesigner.cs
- FixedTextView.cs
- ConfigXmlWhitespace.cs
- WasAdminWrapper.cs
- SHA1.cs
- Executor.cs
- WebPartDisplayModeCancelEventArgs.cs
- CodeIdentifier.cs
- CodeCatchClauseCollection.cs
- DataError.cs
- TextServicesLoader.cs
- DesignerVerbCollection.cs
- WindowsEditBox.cs
- ContextStack.cs
- SafeRightsManagementEnvironmentHandle.cs
- PolicyException.cs
- SafeNativeMethods.cs
- SHA512.cs
- Compilation.cs
- ThreadWorkerController.cs
- RowBinding.cs
- IItemProperties.cs
- AutoGeneratedField.cs
- ProviderException.cs
- BypassElement.cs
- ZipIOZip64EndOfCentralDirectoryLocatorBlock.cs
- EntityDesignerDataSourceView.cs
- CodeCatchClauseCollection.cs
- ControlParameter.cs
- DataSourceXmlAttributeAttribute.cs
- DBAsyncResult.cs
- Point3DConverter.cs
- Listbox.cs
- DelegateTypeInfo.cs
- WindowsGrip.cs
- RawMouseInputReport.cs
- StaticDataManager.cs
- PathNode.cs
- ValueTable.cs
- LoginUtil.cs
- ColumnMapCopier.cs
- ByteStreamGeometryContext.cs
- SortKey.cs
- DbBuffer.cs
- TextEditorLists.cs
- RewritingProcessor.cs
- ClientTargetCollection.cs
- BindingNavigator.cs
- Convert.cs
- ArraySegment.cs
- XmlWhitespace.cs
- WebContext.cs
- UnaryExpressionHelper.cs
- CannotUnloadAppDomainException.cs
- PropertyManager.cs
- TdsEnums.cs
- Stacktrace.cs
- Monitor.cs
- SafeNativeMethods.cs
- SrgsSubset.cs
- EntityConnectionStringBuilderItem.cs
- XDRSchema.cs
- WebPartHelpVerb.cs
- FamilyMap.cs
- WebBrowserNavigatedEventHandler.cs
- SingleTagSectionHandler.cs
- ChtmlTextWriter.cs
- QueryAsyncResult.cs
- newinstructionaction.cs
- EventProvider.cs
- BookmarkEventArgs.cs
- XslNumber.cs
- StorageSetMapping.cs
- PropertyPath.cs
- WebConfigManager.cs
- _CacheStreams.cs
- DBSqlParserColumnCollection.cs
- TextParagraphCache.cs
- X509CertificateRecipientServiceCredential.cs
- DataGridPageChangedEventArgs.cs
- AnyAllSearchOperator.cs
- UriExt.cs
- SafeHandle.cs
- SystemSounds.cs
- ChildrenQuery.cs
- Size3DConverter.cs
- EntityConnectionStringBuilder.cs