1 //----------------------------------------------------------------
2 // <copyright company="Microsoft Corporation">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //----------------------------------------------------------------
7 namespace Microsoft.Activities.Presentation.Xaml
9 using System.Activities;
10 using System.Activities.XamlIntegration;
11 using System.Collections.Generic;
12 using System.Reflection;
15 internal sealed class XamlObjectReaderWithSequence : XamlObjectReader
17 private int sequenceNumber;
18 private Dictionary<int, object> sequenceNumberToObjectMap;
19 private HashSet<object> visitedObjects;
21 private Stack<object> objects = new Stack<object>();
22 private XamlMember xamlMember = null;
24 public XamlObjectReaderWithSequence(object instance, XamlSchemaContext schemaContext)
25 : base(instance, schemaContext)
29 public Dictionary<int, object> SequenceNumberToObjectMap
33 if (this.sequenceNumberToObjectMap == null)
35 this.sequenceNumberToObjectMap = new Dictionary<int, object>();
38 return this.sequenceNumberToObjectMap;
42 private HashSet<object> VisitedObjects
46 if (this.visitedObjects == null)
48 this.visitedObjects = new HashSet<object>();
51 return this.visitedObjects;
55 public override bool Read()
57 bool readResult = base.Read();
61 switch (this.NodeType)
63 case XamlNodeType.StartObject:
64 this.objects.Push(this.Instance);
65 this.MapObjectWithSequenceNumber(this.Instance);
67 case XamlNodeType.GetObject:
68 this.objects.Push(this.Instance);
70 case XamlNodeType.EndObject:
73 case XamlNodeType.StartMember:
74 this.xamlMember = this.Member;
76 case XamlNodeType.EndMember:
77 this.xamlMember = null;
79 case XamlNodeType.Value:
80 this.MapObjectWithSequenceNumber(this.GetRealObject());
88 // Current Node contains the value after original object is serialized to a ValueNode, this method
89 // try to get the original object before it is serialized.
90 private object GetRealObject()
92 if (this.Value is string)
94 object parent = this.objects.Peek();
101 // handle <InArgument x:TypeArguments="...">[expression]</InArgument>
102 if (this.xamlMember == XamlLanguage.Initialization)
104 Argument argument = parent as Argument;
105 if (argument != null)
107 return argument.Expression;
113 if (this.xamlMember == null || !this.xamlMember.IsNameValid || this.xamlMember.IsAttachable || this.xamlMember.IsDirective)
118 // handle <x:Array Type="x:Int32"><x:Int32>1</x:Int32>...</x:Array>, type is not limited to x:Int32
119 // Here property.DeclaringType would be ArrayExtension, while parent would be a real array (System.Int32[]),
120 // calling property.GetValue(parent, null) would cause a TargetException since the type and object doesn't match.
121 // So stop further processing for ArrayExtension.
122 if (this.xamlMember.DeclaringType == XamlLanguage.Array)
124 // We can get the element type by parent.GetType().GetElementType(),
125 // but we really don't care about that, so just return null.
129 PropertyInfo property = this.xamlMember.UnderlyingMember as PropertyInfo;
131 if (property == null || !property.CanRead)
136 object realObject = property.GetValue(parent, null);
138 // NOTE this is to handle argument containing an IValueSerializable expression
139 // this logic should be kept the same as that in System.Activities.Debugger.XamlDebuggerXmlReader.NotifySourceLocationFound.
140 Argument argumentObject = realObject as Argument;
141 if (argumentObject != null && argumentObject.Expression is IValueSerializableExpression)
143 realObject = argumentObject.Expression;
152 private void MapObjectWithSequenceNumber(object mappedObject)
154 if (mappedObject == null)
159 if (!this.VisitedObjects.Contains(mappedObject) && !(mappedObject is string))
161 this.VisitedObjects.Add(mappedObject);
162 this.SequenceNumberToObjectMap.Add(this.sequenceNumber, mappedObject);
163 this.sequenceNumber++;