public void ReadSubtree3 () { var xr = new XamlObjectReader (5); xr.Read (); xr.Read (); var sr = xr.ReadSubtree (); Assert.AreEqual (XamlNodeType.None, sr.NodeType, "#1-2"); Assert.AreEqual (XamlNodeType.StartObject, xr.NodeType, "#1-3"); Assert.IsTrue (sr.Read (), "#2"); Assert.AreEqual (XamlNodeType.StartObject, sr.NodeType, "#2-2"); Assert.AreEqual (XamlNodeType.StartObject, xr.NodeType, "#2-3"); Assert.IsTrue (sr.Read (), "#3"); Assert.AreEqual (XamlNodeType.StartMember, sr.NodeType, "#3-2"); Assert.AreEqual (XamlNodeType.StartMember, xr.NodeType, "#3-3"); Assert.IsTrue (sr.Read (), "#4"); Assert.AreEqual (XamlNodeType.Value, sr.NodeType, "#4-2"); Assert.AreEqual (XamlNodeType.Value, xr.NodeType, "#4-3"); Assert.IsTrue (sr.Read (), "#5"); Assert.AreEqual (XamlNodeType.EndMember, sr.NodeType, "#5-2"); Assert.AreEqual (XamlNodeType.EndMember, xr.NodeType, "#5-3"); Assert.IsTrue (sr.Read (), "#6"); Assert.AreEqual (XamlNodeType.EndObject, sr.NodeType, "#6-2"); Assert.AreEqual (XamlNodeType.EndObject, xr.NodeType, "#6-3"); Assert.IsFalse (sr.Read (), "#7"); Assert.AreEqual (XamlNodeType.None, xr.NodeType, "#7-2"); }
public void ReadSubtree1 () { var xr = new XamlObjectReader (5); var sr = xr.ReadSubtree (); Assert.AreEqual (XamlNodeType.None, sr.NodeType, "#1-2"); Assert.AreEqual (XamlNodeType.None, xr.NodeType, "#1-3"); Assert.IsTrue (sr.Read (), "#2"); Assert.AreEqual (XamlNodeType.None, sr.NodeType, "#2-2"); Assert.AreEqual (XamlNodeType.None, xr.NodeType, "#2-3"); Assert.IsFalse (sr.Read (), "#3"); Assert.AreEqual (XamlNodeType.NamespaceDeclaration, xr.NodeType, "#3-2"); }
// This method collects view state attached properties and generates a Xaml node stream // with all view state information appearing within the ViewStateManager node. // It is called when workflow definition is being serialized to string. // inputReader - Nodestream with view state information as attached properties on the activity nodes. // The reader is positioned at the begining of the workflow definition. // idManager - This component issues running sequence numbers for IdRef. // Result - Node stream positioned at the begining of the workflow definition with a // ViewStateManager node containing all view state information. // Implementation logic: // 1. Scan the input nodestream Objects for attached properties that need to be converted (VirtualizedContainerService.HintSize and WorkflowViewStateService.ViewState). // 2. If the Object had a IdRef value then use it otherwise generate a new value. // 3. Store idRef value and corresponding viewstate related attached property nodes (from step 1) // in the viewStateInfo dictionary. // 4. Use the viewStateInfo dictionary to generate ViewStateManager node which is then inserted // into the end of output nodestream. public static XamlReader ConvertAttachedPropertiesToViewState(XamlObjectReader inputReader, ViewStateIdManager idManager) { // Stack to track StartObject/GetObject and EndObject nodes. Stack<Frame> stack = new Stack<Frame>(); XamlMember viewStateManager = new XamlMember(ViewStateManager, GetViewStateManager, SetViewStateManager, inputReader.SchemaContext); XamlMember idRefMember = new XamlMember(IdRef, GetIdRef, SetIdRef, inputReader.SchemaContext); // Xaml member corresponding to x:Class property of the workflow definition. Used to find x:Class value in the node stream. XamlMember activityBuilderName = new XamlMember(typeof(ActivityBuilder).GetProperty("Name"), inputReader.SchemaContext); string activityBuilderTypeName = typeof(ActivityBuilder).Name; // Dictionary to keep track of IdRefs and corresponding viewstate related // attached property nodes. Dictionary<string, XamlNodeList> viewStateInfo = new Dictionary<string, XamlNodeList>(); // Output node list XamlNodeList workflowDefinition = new XamlNodeList(inputReader.SchemaContext); using (XamlWriter workflowDefinitionWriter = workflowDefinition.Writer) { bool design2010NamespaceFound = false; bool inIdRefMember = false; bool inxClassMember = false; bool skipWritingWorkflowDefinition = false; bool skipReadingWorkflowDefinition = false; string xClassName = null; while (skipReadingWorkflowDefinition || inputReader.Read()) { skipWritingWorkflowDefinition = false; skipReadingWorkflowDefinition = false; switch (inputReader.NodeType) { case XamlNodeType.NamespaceDeclaration: if (inputReader.Namespace.Namespace.Equals(NameSpaces.Design2010, StringComparison.Ordinal)) { design2010NamespaceFound = true; } break; case XamlNodeType.StartObject: // Save the Xaml type and clr object on the stack frame. These are used later to generate // IdRef values and attaching the same to the clr object. stack.Push(new Frame() { Type = inputReader.Type, InstanceObject = inputReader.Instance }); // If the design2010 namespace was not found add the namespace node // before the start object is written out. if (!design2010NamespaceFound) { workflowDefinitionWriter.WriteNamespace(new NamespaceDeclaration(NameSpaces.Design2010, NameSpaces.Design2010Prefix)); design2010NamespaceFound = true; } break; case XamlNodeType.GetObject: // Push an empty frame to balance the Pop operation when the EndObject node // is encountered. stack.Push(new Frame() { Type = null }); break; case XamlNodeType.StartMember: // Track when we enter IdRef member so that we can save its value. if (inputReader.Member.Equals(idRefMember)) { inIdRefMember = true; } // Track when we enter x:Class member so that we can save its value. else if (inputReader.Member.Equals(activityBuilderName)) { inxClassMember = true; } // Start of VirtualizedContainerService.HintSize or WorkflowViewStateService.ViewState property. else if (IsAttachablePropertyForConvert(inputReader)) { // The top of stack here corresponds to the activity on which // the above properties are attached. if (stack.Peek().AttachedPropertyNodes == null) { stack.Peek().AttachedPropertyNodes = new XamlNodeList(inputReader.SchemaContext); } // Write the attached property's xaml nodes into the stack. XamlReader subTreeReader = inputReader.ReadSubtree(); XamlWriter attachedPropertyWriter = stack.Peek().AttachedPropertyNodes.Writer; while (subTreeReader.Read()) { attachedPropertyWriter.WriteNode(subTreeReader); } // The subtree reader loop put us at the begining of the next node in the input stream. // So skip reading/writing it out just yet. skipReadingWorkflowDefinition = true; skipWritingWorkflowDefinition = true; } break; case XamlNodeType.Value: // Read and save IdRef/x:Class member values. // Also update idManager to keep track of prefixes and ids seen. if (inIdRefMember) { string idRef = inputReader.Value as string; stack.Peek().IdRef = idRef; idManager.UpdateMap(idRef); } else if (inxClassMember) { xClassName = inputReader.Value as string; idManager.UpdateMap(xClassName); } break; case XamlNodeType.EndMember: // Exit IdRef/x:Class member state. if (inIdRefMember) { inIdRefMember = false; } else if (inxClassMember) { inxClassMember = false; } break; case XamlNodeType.EndObject: // Remove an item from the stack because we encountered the end of an object definition. Frame frameObject = stack.Pop(); // If the object had (viewstate related) attached properties we need to save them // into the viewStateInfo dictionary. if (frameObject.AttachedPropertyNodes != null) { frameObject.AttachedPropertyNodes.Writer.Close(); // If the object didn't have IdRef, generate a new one. if (string.IsNullOrWhiteSpace(frameObject.IdRef)) { // Use the object type name (or x:Class value) to generate a new id. if (frameObject.Type != null) { string prefix = frameObject.Type.Name; if (frameObject.Type.UnderlyingType != null) { prefix = frameObject.Type.UnderlyingType.Name; } if (string.CompareOrdinal(prefix, activityBuilderTypeName) == 0 && !string.IsNullOrWhiteSpace(xClassName)) { frameObject.IdRef = idManager.GetNewId(xClassName); } else { frameObject.IdRef = idManager.GetNewId(prefix); } } else //Fallback to generating a guid value. { frameObject.IdRef = Guid.NewGuid().ToString(); } // Since we didn't see a IdRef on this object, insert the generated // viewstate id into the output Xaml node-stream. workflowDefinitionWriter.WriteStartMember(idRefMember); workflowDefinitionWriter.WriteValue(frameObject.IdRef); workflowDefinitionWriter.WriteEndMember(); // Save the generated idRef on the corresponding clr object as well. if (frameObject.InstanceObject != null) { WorkflowViewState.SetIdRef(frameObject.InstanceObject, frameObject.IdRef); } } viewStateInfo[frameObject.IdRef] = frameObject.AttachedPropertyNodes; } // We're at the end of input nodestream and have collected data in viewStateInfo // so we need to create and insert the ViewStateManager nodes into the output nodestream. if (stack.Count == 0 && viewStateInfo.Count > 0) { XamlNodeList viewStateManagerNodeList = CreateViewStateManagerNodeList(viewStateInfo, inputReader.SchemaContext); XamlReader viewStateManagerNodeReader = viewStateManagerNodeList.GetReader(); // Insert the ViewStateManager nodes into the output node stream. workflowDefinitionWriter.WriteStartMember(viewStateManager); while (viewStateManagerNodeReader.Read()) { workflowDefinitionWriter.WriteNode(viewStateManagerNodeReader); } workflowDefinitionWriter.WriteEndMember(); // viewStateManager } break; } if (!skipWritingWorkflowDefinition) { workflowDefinitionWriter.WriteNode(inputReader); } } } return workflowDefinition.GetReader(); }
// This method removes IdRef nodes from the nodestream. This method would be called // when a 4.5 workflow definition is retargeted to 4.0. public static XamlReader RemoveIdRefs(XamlObjectReader inputReader) { XamlMember idRefMember = new XamlMember(IdRef, GetIdRef, SetIdRef, inputReader.SchemaContext); XamlNodeList outputNodeList = new XamlNodeList(inputReader.SchemaContext); using (XamlWriter outputWriter = outputNodeList.Writer) { while (inputReader.Read()) { if (inputReader.NodeType == XamlNodeType.StartMember && inputReader.Member.Equals(idRefMember)) { // Exhaust the idRefMember sub-tree. XamlReader idRefReader = inputReader.ReadSubtree(); while (idRefReader.Read()); } outputWriter.WriteNode(inputReader); } } return outputNodeList.GetReader(); }