2 // Copyright (c) Microsoft Corporation. All rights reserved.
5 namespace Microsoft.Activities.Presentation.Xaml
8 using System.Activities.Presentation.Toolbox;
11 // ActivityTemplateFactoryBuilderWriter is a XamlWriter that support <ActivityTemplateFactory x:Class ...
13 // Think of this class (and any other XamlWriter) as a XAML node stream editor
14 // XAML node are *not* objects, they are represented as method calls. For example, when WriteStartObject is called, a StartObject node is send to this writer.
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 // The system starts as the InitialState. There are five states in total: (InitialState, BufferingState, BufferingNameState, BufferingTargetTypeState, BypassState)
20 // If the very first StartObject node is ActivityTemplateFactory, then start buffering by going to the buffering state, otherwise simply go to the ByPassState.
22 // In the buffering state, the nodes are buffered in a XamlNodeQueue, until we see the Implementation Node.
23 // When we reach the Implementation node, we will flush all the nodes transformed to the underlyingWriter, we will also switch to the ByPass state.
25 // During the buffering, it is possible that we encounter the Name/TargetType node - the name node cannot enter the buffer because editing is required, we will use a separate state to track that.
26 internal sealed class ActivityTemplateFactoryBuilderWriter : XamlWriter
28 private XamlSchemaContext schemaContext;
29 private XamlWriter underlyingWriter;
30 private XamlType activityTemplateFactoryType;
31 private XamlMember activityTemplateFactoryImplementationMember;
32 private XamlMember activityTemplateFactoryBuilderImplementationMember;
33 private XamlMember activityTemplateFactoryBuilderNameMember;
34 private XamlMember activityTemplateFactoryBuilderTargetTypeMember;
36 // Buffering of nodes before starting the Implementation node
37 private ActivityTemplateFactoryBuilderWriterStates currentState = ActivityTemplateFactoryBuilderWriterStates.InitialState;
38 private XamlNodeQueue queuedNodes;
39 private string className;
40 private string targetType;
41 private bool xamlLanguageNamespaceWritten = false;
43 public ActivityTemplateFactoryBuilderWriter(XamlWriter underlyingWriter, XamlSchemaContext schemaContext)
45 this.schemaContext = schemaContext;
46 this.underlyingWriter = underlyingWriter;
49 private enum ActivityTemplateFactoryBuilderWriterStates
54 BufferingTargetTypeState,
58 public override XamlSchemaContext SchemaContext
60 get { return this.schemaContext; }
63 private XamlType ActivityTemplateFactoryType
67 if (this.activityTemplateFactoryType == null)
69 this.activityTemplateFactoryType = new XamlType(typeof(ActivityTemplateFactory), this.schemaContext);
72 return this.activityTemplateFactoryType;
76 private XamlMember ActivityTemplateFactoryImplementationMember
80 if (this.activityTemplateFactoryImplementationMember == null)
82 this.activityTemplateFactoryImplementationMember = ActivityTemplateFactoryBuilderXamlMembers.ActivityTemplateFactoryImplementationMemberForWriter(this.schemaContext);
85 return this.activityTemplateFactoryImplementationMember;
89 private XamlMember ActivityTemplateFactoryBuilderImplementationMember
93 if (this.activityTemplateFactoryBuilderImplementationMember == null)
95 this.activityTemplateFactoryBuilderImplementationMember = ActivityTemplateFactoryBuilderXamlMembers.ActivityTemplateFactoryBuilderImplementationMember(this.schemaContext);
98 return this.activityTemplateFactoryBuilderImplementationMember;
102 private XamlMember ActivityTemplateFactoryBuilderNameMember
106 if (this.activityTemplateFactoryBuilderNameMember == null)
108 this.activityTemplateFactoryBuilderNameMember = ActivityTemplateFactoryBuilderXamlMembers.ActivityTemplateFactoryBuilderNameMember(this.schemaContext);
111 return this.activityTemplateFactoryBuilderNameMember;
115 private XamlMember ActivityTemplateFactoryBuilderTargetTypeMember
119 if (this.activityTemplateFactoryBuilderTargetTypeMember == null)
121 this.activityTemplateFactoryBuilderTargetTypeMember = ActivityTemplateFactoryBuilderXamlMembers.ActivityTemplateFactoryBuilderTargetTypeMember(this.schemaContext);
124 return this.activityTemplateFactoryBuilderTargetTypeMember;
128 public override void WriteNamespace(NamespaceDeclaration namespaceDeclaration)
130 if (namespaceDeclaration.Prefix == "x")
132 this.xamlLanguageNamespaceWritten = true;
135 this.underlyingWriter.WriteNamespace(namespaceDeclaration);
138 public override void WriteStartObject(XamlType type)
140 switch (this.currentState)
142 case ActivityTemplateFactoryBuilderWriterStates.InitialState:
143 if (type.Equals(new XamlType(typeof(ActivityTemplateFactoryBuilder), this.schemaContext)))
145 this.queuedNodes = new XamlNodeQueue(this.schemaContext);
146 this.currentState = ActivityTemplateFactoryBuilderWriterStates.BufferingState;
150 this.currentState = ActivityTemplateFactoryBuilderWriterStates.BypassState;
151 this.underlyingWriter.WriteStartObject(type);
155 case ActivityTemplateFactoryBuilderWriterStates.BypassState:
156 this.underlyingWriter.WriteStartObject(type);
160 this.currentState == ActivityTemplateFactoryBuilderWriterStates.BufferingState
161 || this.currentState == ActivityTemplateFactoryBuilderWriterStates.BufferingNameState
162 || this.currentState == ActivityTemplateFactoryBuilderWriterStates.BufferingTargetTypeState,
163 "These are the only possible ActivityTemplateFactoryBuilderWriterStates.");
164 SharedFx.Assert("It is impossible to start any object during the buffering state.");
169 public override void WriteEndObject()
171 switch (this.currentState)
173 case ActivityTemplateFactoryBuilderWriterStates.InitialState:
174 SharedFx.Assert("It is impossible to end an object during InitialState");
176 case ActivityTemplateFactoryBuilderWriterStates.BufferingState:
177 this.queuedNodes.Writer.WriteEndObject();
179 case ActivityTemplateFactoryBuilderWriterStates.BypassState:
180 this.underlyingWriter.WriteEndObject();
184 this.currentState == ActivityTemplateFactoryBuilderWriterStates.BufferingNameState
185 || this.currentState == ActivityTemplateFactoryBuilderWriterStates.BufferingTargetTypeState,
186 "These are the only possible ActivityTemplateFactoryBuilderWriterStates.");
187 SharedFx.Assert("It is impossible to end an object when we are buffering the name / targetType.");
192 public override void WriteGetObject()
194 switch (this.currentState)
196 case ActivityTemplateFactoryBuilderWriterStates.InitialState:
197 SharedFx.Assert("It is impossible to end an object during InitialState");
199 case ActivityTemplateFactoryBuilderWriterStates.BufferingState:
200 this.queuedNodes.Writer.WriteGetObject();
202 case ActivityTemplateFactoryBuilderWriterStates.BypassState:
203 this.underlyingWriter.WriteGetObject();
207 this.currentState == ActivityTemplateFactoryBuilderWriterStates.BufferingNameState
208 || this.currentState == ActivityTemplateFactoryBuilderWriterStates.BufferingTargetTypeState,
209 "These are the only possible ActivityTemplateFactoryBuilderWriterStates.");
210 SharedFx.Assert("It is impossible to get an object when we are buffering the name / targetType.");
215 public override void WriteStartMember(XamlMember xamlMember)
217 switch (this.currentState)
219 case ActivityTemplateFactoryBuilderWriterStates.InitialState:
220 SharedFx.Assert("It is impossible to start a member during InitialState");
222 case ActivityTemplateFactoryBuilderWriterStates.BufferingState:
223 if (xamlMember == this.ActivityTemplateFactoryBuilderImplementationMember)
225 xamlMember = this.ActivityTemplateFactoryImplementationMember;
227 if (!this.xamlLanguageNamespaceWritten)
229 // Required namespace for XAML x:Class
230 this.underlyingWriter.WriteNamespace(new NamespaceDeclaration("http://schemas.microsoft.com/winfx/2006/xaml", "x"));
233 this.underlyingWriter.WriteStartObject(this.ActivityTemplateFactoryType);
234 this.underlyingWriter.WriteStartMember(XamlLanguage.Class);
235 this.underlyingWriter.WriteValue(this.className);
236 this.underlyingWriter.WriteEndMember();
237 this.underlyingWriter.WriteStartMember(XamlLanguage.TypeArguments);
238 this.underlyingWriter.WriteValue(this.targetType);
239 this.underlyingWriter.WriteEndMember();
240 this.Transform(this.queuedNodes.Reader, this.underlyingWriter);
241 this.underlyingWriter.WriteStartMember(xamlMember);
242 this.currentState = ActivityTemplateFactoryBuilderWriterStates.BypassState;
245 if (xamlMember == this.ActivityTemplateFactoryBuilderNameMember)
247 this.currentState = ActivityTemplateFactoryBuilderWriterStates.BufferingNameState;
249 else if (xamlMember == this.ActivityTemplateFactoryBuilderTargetTypeMember)
251 this.currentState = ActivityTemplateFactoryBuilderWriterStates.BufferingTargetTypeState;
255 this.queuedNodes.Writer.WriteStartMember(xamlMember);
259 case ActivityTemplateFactoryBuilderWriterStates.BypassState:
260 this.underlyingWriter.WriteStartMember(xamlMember);
264 this.currentState == ActivityTemplateFactoryBuilderWriterStates.BufferingNameState
265 || this.currentState == ActivityTemplateFactoryBuilderWriterStates.BufferingTargetTypeState,
266 "These are the only possible ActivityTemplateFactoryBuilderWriterStates.");
267 SharedFx.Assert("It is impossible to get an object when we are buffering the name / targetType.");
272 public override void WriteEndMember()
274 switch (this.currentState)
276 case ActivityTemplateFactoryBuilderWriterStates.InitialState:
277 SharedFx.Assert("It is impossible to end a member during InitialState");
279 case ActivityTemplateFactoryBuilderWriterStates.BufferingState:
280 this.queuedNodes.Writer.WriteEndMember();
282 case ActivityTemplateFactoryBuilderWriterStates.BypassState:
283 this.underlyingWriter.WriteEndMember();
287 this.currentState == ActivityTemplateFactoryBuilderWriterStates.BufferingNameState
288 || this.currentState == ActivityTemplateFactoryBuilderWriterStates.BufferingTargetTypeState,
289 "These are the only possible ActivityTemplateFactoryBuilderWriterStates.");
291 // Intentionally skipped the end member of Name / TargetType node
292 this.currentState = ActivityTemplateFactoryBuilderWriterStates.BufferingState;
297 public override void WriteValue(object value)
299 switch (this.currentState)
301 case ActivityTemplateFactoryBuilderWriterStates.InitialState:
302 SharedFx.Assert("It is impossible to write a value during InitialState");
304 case ActivityTemplateFactoryBuilderWriterStates.BufferingState:
305 this.queuedNodes.Writer.WriteValue(value);
307 case ActivityTemplateFactoryBuilderWriterStates.BufferingNameState:
308 this.className = (string)value;
310 case ActivityTemplateFactoryBuilderWriterStates.BufferingTargetTypeState:
311 this.targetType = (string)value;
315 this.currentState == ActivityTemplateFactoryBuilderWriterStates.BypassState,
316 "This is the only possible ActivityTemplateFactoryBuilderWriterStates");
317 this.underlyingWriter.WriteValue(value);
322 private void Transform(XamlReader reader, XamlWriter myWriter)
324 while (!reader.IsEof)
327 myWriter.WriteNode(reader);