/// <summary> /// Write Start of an Element, which is a tag of the form /<Classname /> /// </summary> /// <remarks> /// For template parsing, determine when it is withing a Trigger or /// MultiTrigger section. This is done for validity checking of /// unknown tags and attributes. /// </remarks> public override void WriteElementStart(XamlElementStartNode xamlElementStartNode) { StyleMode mode = _styleModeStack.Mode; bool tagWritten = false; if (mode == StyleMode.Base && _styleModeStack.Depth == 0) { // The default TargetType of the Template is needed for resolving names when // TargetType is not set. Remember it now appropriately for each kind of Template. // Ideally this should come from an attribute or other means instead of hard-coding here. if (KnownTypes.Types[(int)KnownElements.ControlTemplate].IsAssignableFrom(xamlElementStartNode.ElementType)) { _defaultTargetType = KnownTypes.Types[(int)KnownElements.Control]; } else if (KnownTypes.Types[(int)KnownElements.DataTemplate].IsAssignableFrom(xamlElementStartNode.ElementType)) { _defaultTargetType = KnownTypes.Types[(int)KnownElements.ContentPresenter]; #if PBTCOMPILER // The type to use for the dictionary key depends on what kind of // template this is. Remember it now. _templateKeyType = KnownTypes.Types[(int)KnownElements.DataTemplateKey]; #endif } else if (KnownTypes.Types[(int)KnownElements.ItemsPanelTemplate].IsAssignableFrom(xamlElementStartNode.ElementType)) { _defaultTargetType = KnownTypes.Types[(int)KnownElements.ItemsPresenter]; } } _setterOrTriggerPropertyMemberInfo = null; // Track elements during compile so that we can resolve id names to types. This // is useful when resolving Setter Property / Value attributes. _elementTypeStack.Push(xamlElementStartNode.ElementType); // Keep style mode and other state up-to-date. CommonElementStartProcessing(xamlElementStartNode, xamlElementStartNode.ElementType, ref mode); // The very first element encountered within a template block // should a template tree node. if (mode == StyleMode.Base && _styleModeStack.Depth > 0) { ; // Nothing special to do } else if (mode == StyleMode.TriggerBase && (xamlElementStartNode.ElementType == KnownTypes.Types[(int)KnownElements.Trigger] || xamlElementStartNode.ElementType == KnownTypes.Types[(int)KnownElements.MultiTrigger] || xamlElementStartNode.ElementType == KnownTypes.Types[(int)KnownElements.DataTrigger] || xamlElementStartNode.ElementType == KnownTypes.Types[(int)KnownElements.MultiDataTrigger] || xamlElementStartNode.ElementType == KnownTypes.Types[(int)KnownElements.EventTrigger])) { _inPropertyTriggerDepth = xamlElementStartNode.Depth; } else if (mode == StyleMode.TriggerBase && (KnownTypes.Types[(int)KnownElements.SetterBase].IsAssignableFrom(xamlElementStartNode.ElementType))) { // Just entered the <Setter .../> section of a Trigger _inSetterDepth = xamlElementStartNode.Depth; } #if PBTCOMPILER else if (_styleModeStack.Mode == StyleMode.DataTypeProperty && InDeferLoadedSection && _styleModeStack.Depth >= 2 && !_defNameFound) { // We have to treat DataType="{x:Type SomeType}" as a key in a // resource dictionary, if one is present. This means generating // a series of baml records to use as the key for the defer loaded // body of the Style. if (_styleModeStack.Depth == 2) { base.WriteKeyElementStart(new XamlElementStartNode( xamlElementStartNode.LineNumber, xamlElementStartNode.LinePosition, xamlElementStartNode.Depth, _templateKeyType.Assembly.FullName, _templateKeyType.FullName, _templateKeyType, null)); base.WriteConstructorParametersStart(new XamlConstructorParametersStartNode( xamlElementStartNode.LineNumber, xamlElementStartNode.LinePosition, xamlElementStartNode.Depth)); } base.WriteElementStart(xamlElementStartNode); tagWritten = true; } #endif // Handle custom serializers within the template section by creating an instance // of that serializer and handing off control. if (xamlElementStartNode.SerializerType != null && _styleModeStack.Depth > 0) { XamlSerializer serializer = XamlTypeMapper.CreateInstance(xamlElementStartNode.SerializerType) as XamlSerializer; if (serializer == null) { ThrowException(SRID.ParserNoSerializer, xamlElementStartNode.TypeFullName, xamlElementStartNode.LineNumber, xamlElementStartNode.LinePosition); } else { // Depending on whether this is the compile case or the parse xaml // case, we want to convert the xaml into baml or objects. #if PBTCOMPILER serializer.ConvertXamlToBaml(TokenReader, BamlRecordWriter == null ? ParserContext : BamlRecordWriter.ParserContext, xamlElementStartNode, BamlRecordWriter); #else // If we're in the content of the template, we'll convert to baml. Then TemplateBamlRecordReader // gets the option of instantiating it or keeping it in baml. For example, if this is a nested // <Button.Style>, it can be instantiated, but if it's a part of the .Resources of an element // in the template, it needs to be left in baml. // Notice that TreeBuilder null check is for the case when the current template is within the // content section of a parent template. This means we need to be writing to Baml. // <DataTemplate> // <RadioButton> // <RadioButton.Template> // <ControlTemplate> // <ControlTemplate.Triggers> // <Trigger Property="..." Value="..."> // <Setter Property="Style"> // <Style ... /> // </Setter> // </Trigger> // </ControlTemplate.Triggers> // </ControlTemplate> // </RadioButton.Template> // </RadioButton> // </DataTemplate> if ( _styleModeStack.Mode == StyleMode.VisualTree || TreeBuilder == null ) { serializer.ConvertXamlToBaml(TokenReader, BamlRecordWriter.ParserContext, xamlElementStartNode, BamlRecordWriter); } else { serializer.ConvertXamlToObject(TokenReader, StreamManager, BamlRecordWriter.ParserContext, xamlElementStartNode, TreeBuilder.RecordReader); } #endif } } else { _styleModeStack.Push(mode); if (!tagWritten) { base.WriteElementStart(xamlElementStartNode); } } }
public override void WriteElementStart(XamlElementStartNode xamlObjectNode) { string classFullName = null; classFullName = _compiler.StartElement(ref _class, _subClass, ref _classModifier, xamlObjectNode.ElementType, string.Empty); // If we have a serializer for this element's type, then use that // serializer rather than doing default serialization. // NOTE: We currently have faith that the serializer will return when // it is done with the subtree and leave everything in the correct // state. We may want to limit how much the called serializer can // read so that it is forced to return at the end of the subtree. if (xamlObjectNode.SerializerType != null) { XamlSerializer serializer; if (xamlObjectNode.SerializerType == typeof(XamlStyleSerializer)) { serializer = new XamlStyleSerializer(ParserHooks); } else if (xamlObjectNode.SerializerType == typeof(XamlTemplateSerializer)) { serializer = new XamlTemplateSerializer(ParserHooks); } else { serializer = Activator.CreateInstance( xamlObjectNode.SerializerType, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.CreateInstance, null, null, null) as XamlSerializer; } if (serializer == null) { ThrowException(SRID.ParserNoSerializer, xamlObjectNode.TypeFullName, xamlObjectNode.LineNumber, xamlObjectNode.LinePosition); } else { serializer.ConvertXamlToBaml(TokenReader, ParserContext, xamlObjectNode, BamlRecordWriter); _compiler.EndElement(_pass2); } } else if (BamlRecordWriter != null) { if (classFullName != null) { bool isRootPublic = _pass2 ? !_isInternalRoot : _compiler.IsRootPublic; Type rootType = isRootPublic ? xamlObjectNode.ElementType : typeof(ParserExtension); XamlElementStartNode xamlRootObjectNode = new XamlElementStartNode( xamlObjectNode.LineNumber, xamlObjectNode.LinePosition, xamlObjectNode.Depth, _compiler.AssemblyName, classFullName, rootType, xamlObjectNode.SerializerType); base.WriteElementStart(xamlRootObjectNode); } else { base.WriteElementStart(xamlObjectNode); } } }
/// <summary> /// Write Start element for a dictionary key section. /// </summary> public override void WriteKeyElementStart( XamlElementStartNode xamlKeyElementStartNode) { _styleModeStack.Push(StyleMode.Key); base.WriteKeyElementStart(xamlKeyElementStartNode); }
/// <summary> /// Write Start element for a dictionary key section. /// </summary> public virtual void WriteKeyElementStart( XamlElementStartNode xamlKeyElementStartNode) { if (BamlRecordWriter != null) { BamlRecordWriter.WriteKeyElementStart(xamlKeyElementStartNode); } }
// Write the start of a def attribute element used as the key in an // IDictionary public void WriteKeyElementStart( XamlElementStartNode xamlKeyElementNode) { Debug.Assert(!InStaticResourceSection, "We do not support x:Key within a StaticResource Section"); // Don't allow a bind or resource reference in a key element, since this // causes problems for resolution. Multi-pass or recursive key resolution // would be needed to robustly support this feature. if (!typeof(String).IsAssignableFrom(xamlKeyElementNode.ElementType) && !KnownTypes.Types[(int)KnownElements.StaticExtension].IsAssignableFrom(xamlKeyElementNode.ElementType) && !KnownTypes.Types[(int)KnownElements.TypeExtension].IsAssignableFrom(xamlKeyElementNode.ElementType) && !KnownTypes.Types[(int)KnownElements.ResourceKey].IsAssignableFrom(xamlKeyElementNode.ElementType)) { XamlParser.ThrowException(SRID.ParserBadKey, xamlKeyElementNode.TypeFullName, xamlKeyElementNode.LineNumber, xamlKeyElementNode.LinePosition); } // initialize the element and add to the stack BamlKeyElementStartRecord bamlElement = (BamlKeyElementStartRecord) BamlRecordManager.GetWriteRecord( BamlRecordType.KeyElementStart); // 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, xamlKeyElementNode.AssemblyName, xamlKeyElementNode.TypeFullName, out typeId)) { string serializerAssemblyName = string.Empty; if (xamlKeyElementNode.SerializerType != null) { serializerAssemblyName = xamlKeyElementNode.SerializerType.Assembly.FullName; } typeId = MapTable.AddTypeInfoMap(BinaryWriter, xamlKeyElementNode.AssemblyName, xamlKeyElementNode.TypeFullName, xamlKeyElementNode.ElementType, serializerAssemblyName, xamlKeyElementNode.SerializerTypeFullName); } bamlElement.TypeId = typeId; // 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 use this as a key (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 == 2) { _deferElementDepth++; _deferKeyCollecting = true; KeyDeferRecord keyRecord = (KeyDeferRecord)(_deferKeys[_deferKeys.Count-1]); keyRecord.RecordList = new ArrayList(5); Debug.Assert(keyRecord.RecordList.Count == 0, "Should have empty record list"); keyRecord.RecordList.Add(new ValueDeferRecord(bamlElement, xamlKeyElementNode.LineNumber, xamlKeyElementNode.LinePosition)); if (keyRecord.Record != null) { TransferOldSharedData(keyRecord.Record as IBamlDictionaryKey, bamlElement as IBamlDictionaryKey); keyRecord.Record = null; } keyRecord.LineNumber = xamlKeyElementNode.LineNumber; keyRecord.LinePosition = xamlKeyElementNode.LinePosition; return; } else { WriteAndReleaseRecord(bamlElement, xamlKeyElementNode); } }
// 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); } }
/// <summary> /// Write Start of an Element, which is a tag of the form /<Classname /> /// </summary> /// <remarks> /// For style parsing, determine when it is withing a Trigger or /// MultiTrigger section. This is done for validity checking of /// unknown tags and attributes. /// </remarks> public override void WriteElementStart(XamlElementStartNode xamlElementStartNode) { StyleMode mode = _styleModeStack.Mode; int depth = _styleModeStack.Depth; _setterOrTriggerPropertyInfo = null; bool tagWritten = false; // The very first element encountered within a style block should be the // target type tag, or a Setter. if (mode == StyleMode.Base && depth > 0) { if (KnownTypes.Types[(int)KnownElements.SetterBase].IsAssignableFrom(xamlElementStartNode.ElementType)) { if (_setterPropertyEncountered) { ThrowException(SRID.StyleImpliedAndComplexChildren, xamlElementStartNode.ElementType.Name, XamlStyleSerializer.SettersPropertyName, xamlElementStartNode.LineNumber, xamlElementStartNode.LinePosition); } mode = StyleMode.Setters; _setterElementEncountered = true; } else { ThrowException(SRID.StyleNoTopLevelElement, xamlElementStartNode.ElementType.Name, xamlElementStartNode.LineNumber, xamlElementStartNode.LinePosition); } } else if (mode == StyleMode.TriggerBase && (xamlElementStartNode.ElementType == KnownTypes.Types[(int)KnownElements.Trigger] || xamlElementStartNode.ElementType == KnownTypes.Types[(int)KnownElements.MultiTrigger] || xamlElementStartNode.ElementType == KnownTypes.Types[(int)KnownElements.DataTrigger] || xamlElementStartNode.ElementType == KnownTypes.Types[(int)KnownElements.MultiDataTrigger] || xamlElementStartNode.ElementType == KnownTypes.Types[(int)KnownElements.EventTrigger])) { _inPropertyTriggerDepth = xamlElementStartNode.Depth; } else if (mode == StyleMode.TriggerBase && (KnownTypes.Types[(int)KnownElements.SetterBase].IsAssignableFrom(xamlElementStartNode.ElementType))) { // Just entered the <Setter> section of a Trigger _inSetterDepth = xamlElementStartNode.Depth; } #if PBTCOMPILER else if (mode == StyleMode.TargetTypeProperty && InDeferLoadedSection && depth >= 2 && !_defNameFound) { // We have to treat TargetType="{x:Type SomeType}" as a key in a // resource dictionary, if one is present. This means generating // a series of baml records to use as the key for the defer loaded // body of the Style. if (depth == 2) { base.WriteKeyElementStart(xamlElementStartNode); } else { base.WriteElementStart(xamlElementStartNode); } tagWritten = true; } #endif if (mode == StyleMode.Setters) { if (xamlElementStartNode.ElementType == KnownTypes.Types[(int)KnownElements.EventSetter]) { #if !PBTCOMPILER ThrowException(SRID.StyleNoEventSetters, xamlElementStartNode.LineNumber, xamlElementStartNode.LinePosition); #else _inEventSetter = true; #endif } else if ((depth == 2 && _setterElementEncountered) || (depth == 3 && _setterPropertyEncountered)) { ThrowException(SRID.ParserNoSetterChild, xamlElementStartNode.TypeFullName, xamlElementStartNode.LineNumber, xamlElementStartNode.LinePosition); } } // Handle custom serializers within the style section by creating an instance // of that serializer and handing off control. if (xamlElementStartNode.SerializerType != null && depth > 0) { XamlSerializer serializer; if (xamlElementStartNode.SerializerType == typeof(XamlStyleSerializer)) { #if PBTCOMPILER // reset the event scope so that any other event setters encountered in this // style after the nested Style is done parsing will be added to a new scope _isSameScope = false; #endif serializer = new XamlStyleSerializer(ParserHooks); } else if (xamlElementStartNode.SerializerType == typeof(XamlTemplateSerializer)) { #if PBTCOMPILER // reset the event scope so that any other event setters encountered in this // style after the nested Template is done parsing will be added to a new scope _isSameScope = false; #endif serializer = new XamlTemplateSerializer(ParserHooks); } else { serializer = XamlTypeMapper.CreateInstance(xamlElementStartNode.SerializerType) as XamlSerializer; } if (serializer == null) { ThrowException(SRID.ParserNoSerializer, xamlElementStartNode.TypeFullName, xamlElementStartNode.LineNumber, xamlElementStartNode.LinePosition); } else { // If we're compiling (or otherwise producing baml), convert to baml. // When we don't have a TreeBuilder, we're producing baml. #if !PBTCOMPILER if( TreeBuilder == null ) { #endif serializer.ConvertXamlToBaml(TokenReader, BamlRecordWriter == null ? ParserContext : BamlRecordWriter.ParserContext, xamlElementStartNode, BamlRecordWriter); #if !PBTCOMPILER } else { serializer.ConvertXamlToObject(TokenReader, StreamManager, BamlRecordWriter.ParserContext, xamlElementStartNode, TreeBuilder.RecordReader); } #endif } } else { _styleModeStack.Push(mode); if (!_inEventSetter) { #if PBTCOMPILER // If we DO NOT need a dictionary key, then set the flag that says // a key was already found so that one is not manufactured from // the TargetType property. if (mode == StyleMode.Base && depth == 0) { _defNameFound = !xamlElementStartNode.NeedsDictionaryKey; } #endif if (!tagWritten) { base.WriteElementStart(xamlElementStartNode); } } } }
/// <summary> /// Write Start element for a dictionary key section. /// </summary> public override void WriteKeyElementStart( XamlElementStartNode xamlKeyElementStartNode) { _styleModeStack.Push(StyleMode.Key); #if PBTCOMPILER _defNameFound = true; #endif base.WriteKeyElementStart(xamlKeyElementStartNode); }