2 // Copyright (c) Microsoft Corporation. All rights reserved.
5 namespace Microsoft.Activities.Presentation.Xaml
8 using System.Activities.Presentation.Toolbox;
11 // ActivityTemplateFactoryBuilderReader is a XamlReader that support <ActivityTemplateFactory x:Class ...
13 // Think of this class (and any other XamlReader) as a XAML node stream editor
14 // XAML node are *not* objects, they are represented as this. For example, when the reader encounter a StartObject node, its NodeType will become StartObject, and its Type will become the type of the starting object.
15 // The writer will then edit the stream and send the nodes to the underlying stream (by calling the methods on the underlying writer)
17 // The editing algorithm goes as follow:
19 // Initially, the first node is read from the underlying reader, if the first node is <ActivityTemplateFactory, then we start buffering nodes, otherwise we simply switch to the Bypass state
20 // We transform and buffer the transformed nodes until we reach the StartMember of Implementation Node, then we yield the control and switch to the ReadingFromBuffer state.
22 // All the external calls are then delegated to the reader provided by the buffer.
24 // Eventually, the buffer will used up, and we will switch to the Bypass state.
25 internal sealed class ActivityTemplateFactoryBuilderReader : XamlReader, IXamlLineInfo
27 private XamlSchemaContext schemaContext;
28 private XamlReader underlyingReader;
29 private XamlNodeQueue queuedNodes;
30 private XamlType activityTemplateFactoryBuilderType;
31 private XamlMember activityTemplateFactoryBuilderImplementationMember;
32 private XamlMember activityTemplateFactoryBuilderNameMember;
33 private XamlMember activityTemplateFactoryBuilderTargetTypeMember;
35 private bool hasLineInfo;
36 private ActivityTemplateFactoryBuilderReaderStates currentState = ActivityTemplateFactoryBuilderReaderStates.InitialState;
38 public ActivityTemplateFactoryBuilderReader(XamlReader underlyingReader, XamlSchemaContext schemaContext)
40 this.underlyingReader = underlyingReader;
41 this.schemaContext = schemaContext;
42 this.hasLineInfo = this.underlyingReader is IXamlLineInfo;
45 private enum ActivityTemplateFactoryBuilderReaderStates
48 ReadingFromBufferState,
52 public override bool IsEof
56 if (this.currentState == ActivityTemplateFactoryBuilderReaderStates.ReadingFromBufferState)
62 return this.underlyingReader.IsEof;
67 public override XamlMember Member
69 get { return this.CurrentReader.Member; }
72 public override NamespaceDeclaration Namespace
74 get { return this.CurrentReader.Namespace; }
77 public override XamlNodeType NodeType
79 get { return this.CurrentReader.NodeType; }
82 public override XamlSchemaContext SchemaContext
84 get { return this.schemaContext; }
87 public override XamlType Type
89 get { return this.CurrentReader.Type; }
92 public override object Value
94 get { return this.CurrentReader.Value; }
97 public bool HasLineInfo
99 get { return this.hasLineInfo; }
102 public int LineNumber
106 if (this.HasLineInfo)
108 return this.CurrentLineInfo.LineNumber;
117 public int LinePosition
121 if (this.HasLineInfo)
123 return this.CurrentLineInfo.LinePosition;
132 private XamlReader CurrentReader
136 switch (this.currentState)
138 case ActivityTemplateFactoryBuilderReaderStates.InitialState:
139 case ActivityTemplateFactoryBuilderReaderStates.BypassState:
140 return this.underlyingReader;
143 SharedFx.Assert(this.currentState == ActivityTemplateFactoryBuilderReaderStates.ReadingFromBufferState, "This is the only remaining ActivityTemplateFactoryBuilderReaderStates.");
144 return this.queuedNodes.Reader;
149 private IXamlLineInfo CurrentLineInfo
151 get { return (IXamlLineInfo)this.CurrentReader; }
154 private XamlType ActivityTemplateFactoryBuilderType
158 if (this.activityTemplateFactoryBuilderType == null)
160 this.activityTemplateFactoryBuilderType = new XamlType(typeof(ActivityTemplateFactoryBuilder), this.schemaContext);
163 return this.activityTemplateFactoryBuilderType;
167 private XamlMember ActivityTemplateFactoryBuilderImplementationMember
171 if (this.activityTemplateFactoryBuilderImplementationMember == null)
173 this.activityTemplateFactoryBuilderImplementationMember = ActivityTemplateFactoryBuilderXamlMembers.ActivityTemplateFactoryBuilderImplementationMember(this.schemaContext);
176 return this.activityTemplateFactoryBuilderImplementationMember;
180 private XamlMember ActivityTemplateFactoryBuilderNameMember
184 if (this.activityTemplateFactoryBuilderNameMember == null)
186 this.activityTemplateFactoryBuilderNameMember = ActivityTemplateFactoryBuilderXamlMembers.ActivityTemplateFactoryBuilderNameMember(this.schemaContext);
189 return this.activityTemplateFactoryBuilderNameMember;
193 private XamlMember ActivityTemplateFactoryBuilderTargetTypeMember
197 if (this.activityTemplateFactoryBuilderTargetTypeMember == null)
199 this.activityTemplateFactoryBuilderTargetTypeMember = ActivityTemplateFactoryBuilderXamlMembers.ActivityTemplateFactoryBuilderTargetTypeMember(this.schemaContext);
202 return this.activityTemplateFactoryBuilderTargetTypeMember;
206 public override bool Read()
208 switch (this.currentState)
210 case ActivityTemplateFactoryBuilderReaderStates.InitialState:
211 bool hasMoreNodes = this.underlyingReader.Read();
212 if (this.underlyingReader.NodeType == XamlNodeType.StartObject && IsActivityTemplateFactoryType(this.underlyingReader.Type))
214 Type underlyingType = this.underlyingReader.Type.UnderlyingType;
215 Type targetType = underlyingType.IsGenericType ? underlyingType.GetGenericArguments()[0] : null;
217 this.currentState = ActivityTemplateFactoryBuilderReaderStates.ReadingFromBufferState;
218 this.queuedNodes = new XamlNodeQueue(this.schemaContext);
219 this.queuedNodes.Writer.WriteStartObject(this.ActivityTemplateFactoryBuilderType, (IXamlLineInfo)this.underlyingReader);
223 while (this.underlyingReader.Read())
225 if (this.underlyingReader.NodeType == XamlNodeType.StartMember && this.underlyingReader.Member == XamlLanguage.Class)
227 this.underlyingReader.Read();
228 className = (string)this.underlyingReader.Value;
229 this.underlyingReader.Read();
230 this.queuedNodes.Writer.WriteStartMember(this.ActivityTemplateFactoryBuilderNameMember, (IXamlLineInfo)this.underlyingReader);
231 this.queuedNodes.Writer.WriteValue(className, (IXamlLineInfo)this.underlyingReader);
232 this.queuedNodes.Writer.WriteEndMember((IXamlLineInfo)this.underlyingReader);
233 if (targetType != null)
235 this.queuedNodes.Writer.WriteStartMember(this.ActivityTemplateFactoryBuilderTargetTypeMember, (IXamlLineInfo)this.underlyingReader);
236 object targetTypeString = targetType;
237 this.queuedNodes.Writer.WriteValue(targetTypeString);
238 this.queuedNodes.Writer.WriteEndMember();
241 else if (this.underlyingReader.NodeType == XamlNodeType.StartMember && this.IsActivityTemplateFactoryImplementationMember(this.underlyingReader.Member))
243 this.queuedNodes.Writer.WriteStartMember(this.ActivityTemplateFactoryBuilderImplementationMember, (IXamlLineInfo)this.underlyingReader);
251 case ActivityTemplateFactoryBuilderReaderStates.ReadingFromBufferState:
252 if (this.queuedNodes.Reader.Read())
258 this.currentState = ActivityTemplateFactoryBuilderReaderStates.BypassState;
259 this.queuedNodes = null;
260 return this.underlyingReader.Read();
264 SharedFx.Assert(this.currentState == ActivityTemplateFactoryBuilderReaderStates.BypassState, "This is the only remaining ActivityTemplateFactoryBuilderReaderStates.");
265 return this.underlyingReader.Read();
269 private static bool IsActivityTemplateFactoryType(XamlType xamlType)
271 if (xamlType.UnderlyingType == null)
276 return xamlType.UnderlyingType == typeof(ActivityTemplateFactory) || (xamlType.UnderlyingType.IsGenericType && xamlType.UnderlyingType.GetGenericTypeDefinition() == typeof(ActivityTemplateFactory<>));
279 private bool IsActivityTemplateFactoryImplementationMember(XamlMember xamlMember)
281 return IsActivityTemplateFactoryType(xamlMember.DeclaringType) && xamlMember == ActivityTemplateFactoryBuilderXamlMembers.ActivityTemplateFactoryImplementationMemberForReader(xamlMember.DeclaringType.UnderlyingType, this.schemaContext);