// takes a BamlCollectionHolder and its context and sets the value of the holder's collection to be // either the default collection instantiated by the holder's constructor or a newly created // collection created based on the expected type. // *** Used when we do not have an explicit tag. private void InitPropertyCollection(BamlCollectionHolder holder, ReaderContextStackData context) { // this method should only be called to initialize the collection Debug.Assert (holder.Collection == null); if (context.ContextType == ReaderFlags.PropertyArray) { // arrays are a little different than other collections, because we wrap them in an array extension. // Here we create an array extension and assign the element type based on the property. ArrayExtension arrayExt = new ArrayExtension(); arrayExt.Type = context.ExpectedType.GetElementType(); holder.Collection = arrayExt; } else if (holder.DefaultCollection != null) { // if we the property getter returned a default value, then we use that collection to insert // as the property's collection. holder.Collection = holder.DefaultCollection; } else { ThrowException(SRID.ParserNullPropertyCollection, holder.PropertyDefinition.Name); } context.ExpectedType = null; // Don't want to receive any other values }
// Start of an IList or IEnumerable property. Get the IList value from the parent // object and store it on the reader stack, so that records encountered under this // list can be added to it. protected virtual void ReadPropertyIListStartRecord( BamlPropertyIListStartRecord bamlPropertyIListStartRecord) { short attributeId = bamlPropertyIListStartRecord.AttributeId; object parent = GetCurrentObjectData(); BamlCollectionHolder holder = new BamlCollectionHolder(this, parent, attributeId); Type expectedType = holder.PropertyType; // If the property does not implement IList or IAddChild, see if the parent // (which is the current object on the top of the stack) implements IAddChild // and try that for adding items later on. First look at defined propertyType // obtained from the DP or PropertyInfo. If that doesn't work, then look at // the actual type of object retrieved using GetValue. ReaderFlags flags = ReaderFlags.Unknown; if (typeof(IList).IsAssignableFrom(expectedType)) { flags = ReaderFlags.PropertyIList; } else if (BamlRecordManager.TreatAsIAddChild(expectedType)) { flags = ReaderFlags.PropertyIAddChild; holder.Collection = holder.DefaultCollection; holder.ReadOnly = true; } else if (typeof(IEnumerable).IsAssignableFrom(expectedType) && (BamlRecordManager.AsIAddChild(GetCurrentObjectData())) != null) { flags = ReaderFlags.PropertyIAddChild; holder.Collection = CurrentContext.ObjectData; holder.ReadOnly = true; expectedType = CurrentContext.ObjectData.GetType(); } else { // if we reached this case, then we had a read-only IEnumerable property // under a non-IAddChild element. Throw an exception ThrowException(SRID.ParserReadOnlyProp, holder.PropertyDefinition.Name); } PushContext(flags | ReaderFlags.CollectionHolder, holder, expectedType, 0); // Set the name of the property into the context CurrentContext.ElementNameOrPropertyName = holder.AttributeName; }
// Start of an IDictionary encountered. Set up the BamlDictionaryHolder on the reader // stack so that items can be added to it. protected virtual void ReadPropertyIDictionaryStartRecord( BamlPropertyIDictionaryStartRecord bamlPropertyIDictionaryStartRecord) { short attributeId = bamlPropertyIDictionaryStartRecord.AttributeId; object parent = GetCurrentObjectData(); BamlCollectionHolder holder = new BamlCollectionHolder(this, parent, attributeId); PushContext(ReaderFlags.PropertyIDictionary | ReaderFlags.CollectionHolder, holder, holder.PropertyType, 0); // Set the name of the property into the context CurrentContext.ElementNameOrPropertyName = holder.AttributeName; }
// Read the start of an array property. Set up the BamlArrayHolder that is needed to // hold array contents. protected void ReadPropertyArrayStartRecord(BamlPropertyArrayStartRecord bamlPropertyArrayStartRecord) { short attributeId = bamlPropertyArrayStartRecord.AttributeId; object parent = GetCurrentObjectData(); BamlCollectionHolder holder = new BamlCollectionHolder(this, parent, attributeId, false /*needDefault*/); if (!holder.PropertyType.IsArray) { ThrowException(SRID.ParserNoMatchingArray, GetPropertyNameFromAttributeId(attributeId)); } Debug.Assert(!holder.ReadOnly); // this is being checked in XamlReaderHelper, just assert PushContext(ReaderFlags.PropertyArray | ReaderFlags.CollectionHolder, holder, holder.PropertyType, 0); // Set the name of the property into the context CurrentContext.ElementNameOrPropertyName = holder.AttributeName; }