// following are for writing to the BAML // Somewhat mimics XMLTextWriter internal void WriteElementStart(XamlElementStartNode xamlElementNode) { // initialize the element and add to the stack BamlElementStartRecord bamlElement = (BamlElementStartRecord) BamlRecordManager.GetWriteRecord(BamlRecordType.ElementStart); // If we do not already have a type record for the type of this element, // then add a new TypeInfo record to the map table. short typeId; if (!MapTable.GetTypeInfoId(BinaryWriter, xamlElementNode.AssemblyName, xamlElementNode.TypeFullName, out typeId)) { string serializerAssemblyName = string.Empty; if (xamlElementNode.SerializerType != null) { serializerAssemblyName = xamlElementNode.SerializerType.Assembly.FullName; } typeId = MapTable.AddTypeInfoMap(BinaryWriter, xamlElementNode.AssemblyName, xamlElementNode.TypeFullName, xamlElementNode.ElementType, serializerAssemblyName, xamlElementNode.SerializerTypeFullName); } bamlElement.TypeId = typeId; bamlElement.CreateUsingTypeConverter = xamlElementNode.CreateUsingTypeConverter; bamlElement.IsInjected = xamlElementNode.IsInjected; // Check if the element we are about to write supports deferable content. // If so, then we have to queue up all the baml records that are contained // within this element and extract key information (if this is a dictionary). // At the end tag, the queued records will be written in an optimal order // and offsets inserted to permit fast runtime indexing of content. if (_deferLoadingSupport && _deferElementDepth > 0) { _deferElementDepth++; if (InStaticResourceSection) { // Gather all the BamlRecords within the StaticResource section _staticResourceElementDepth++; _staticResourceRecordList.Add(new ValueDeferRecord(bamlElement, xamlElementNode.LineNumber, xamlElementNode.LinePosition)); } else if (CollectingValues && KnownTypes.Types[(int)KnownElements.StaticResourceExtension] == xamlElementNode.ElementType) { // Mark the beginning of a StaticResource section _staticResourceElementDepth = 1; _staticResourceRecordList = new List<ValueDeferRecord>(5); _staticResourceRecordList.Add(new ValueDeferRecord(bamlElement, xamlElementNode.LineNumber, xamlElementNode.LinePosition)); } else { // Detect that we are within a DynamicResource Section. if (InDynamicResourceSection) { _dynamicResourceElementDepth++; } else if (CollectingValues && KnownTypes.Types[(int)KnownElements.DynamicResourceExtension] == xamlElementNode.ElementType) { _dynamicResourceElementDepth = 1; } ValueDeferRecord deferRecord = new ValueDeferRecord(bamlElement, xamlElementNode.LineNumber, xamlElementNode.LinePosition); if(_deferComplexPropertyDepth > 0) { // If we are in the middle of a complex property specified for a defered // type, we need to append to the _deferElement array. _deferElement.Add(deferRecord); } else if (_deferElementDepth == 2) { // If this element is directly below the dictionary root, then put a // placeholder record in the key collection. If this is not filled // in before we reach the end of this element's scope, then we don't // have a key, and that's an error. _deferKeys.Add(new KeyDeferRecord(xamlElementNode.LineNumber, xamlElementNode.LinePosition)); // Remember that this element record is for the start of a value, // so that the offset in the associated key record should be set // when this record is actually written out to the baml stream. deferRecord.UpdateOffset = true; _deferValues.Add(deferRecord); } else if (_deferKeyCollecting) { // Don't allow a bind or resource reference in a deferable key, since this // causes problems for resolution. Multi-pass or recursive key resolution // would be needed to robustly support this feature. if (typeof(String).IsAssignableFrom(xamlElementNode.ElementType) || KnownTypes.Types[(int)KnownElements.StaticExtension].IsAssignableFrom(xamlElementNode.ElementType) || KnownTypes.Types[(int)KnownElements.TypeExtension].IsAssignableFrom(xamlElementNode.ElementType)) { ((KeyDeferRecord)_deferKeys[_deferKeys.Count-1]).RecordList.Add(deferRecord); } else { XamlParser.ThrowException(SRID.ParserBadKey, xamlElementNode.TypeFullName, xamlElementNode.LineNumber, xamlElementNode.LinePosition); } } else { _deferValues.Add(deferRecord); } } } else if (_deferLoadingSupport && KnownTypes.Types[(int)KnownElements.ResourceDictionary].IsAssignableFrom(xamlElementNode.ElementType)) { _deferElementDepth = 1; _deferEndOfStartReached = false; _deferElement = new ArrayList(2); _deferKeys = new ArrayList(10); _deferValues = new ArrayList(100); _deferElement.Add(new ValueDeferRecord(bamlElement, xamlElementNode.LineNumber, xamlElementNode.LinePosition)); } else { WriteBamlRecord(bamlElement, xamlElementNode.LineNumber, xamlElementNode.LinePosition); BamlRecordManager.ReleaseWriteRecord(bamlElement); } }
// Helper to write out the baml record, with line numbers obtained from // the associated xaml node. private void WriteAndReleaseRecord( BamlRecord bamlRecord, XamlNode xamlNode) { int lineNumber = xamlNode != null ? xamlNode.LineNumber : 0; int linePosition = xamlNode != null ? xamlNode.LinePosition : 0; // If we are currently parsing a deferable content section, then queue // up the records for later writing if (_deferLoadingSupport && _deferElementDepth > 0) { if (InStaticResourceSection) { // Gather all the BamlRecords within the StaticResource section _staticResourceRecordList.Add(new ValueDeferRecord(bamlRecord, lineNumber, linePosition)); } else { ValueDeferRecord deferRec = new ValueDeferRecord(bamlRecord, lineNumber, linePosition); if (_deferEndOfStartReached) { // If we are starting/ending a complex property, and we are at the same // depth as the defered element, then track a mode so that we write to // the _deferElement array instead of the key/value arrays. if(_deferElementDepth == 1 && xamlNode is XamlPropertyComplexStartNode) { _deferComplexPropertyDepth++; } if(_deferComplexPropertyDepth > 0) { _deferElement.Add(deferRec); if(_deferElementDepth == 1 && xamlNode is XamlPropertyComplexEndNode) { _deferComplexPropertyDepth--; } } else if (_deferKeyCollecting) { ((KeyDeferRecord)_deferKeys[_deferKeys.Count-1]).RecordList.Add(deferRec); } else { _deferValues.Add(deferRec); } } else { _deferElement.Add(deferRec); } } } else { WriteBamlRecord(bamlRecord, lineNumber, linePosition); BamlRecordManager.ReleaseWriteRecord(bamlRecord); } }