Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Markup / TemplateXamlParser.cs / 1305600 / TemplateXamlParser.cs
/****************************************************************************\ * * File: TemplateXamlParser.cs * * Purpose: Class that interfaces with TokenReader and BamlWriter for * parsing Template * * History: * 11/22/04: [....] Created * * Copyright (C) 2004 by Microsoft Corporation. All rights reserved. * \***************************************************************************/ using System; using System.Xml; using System.IO; using System.Text; using System.Collections; using System.ComponentModel; using System.Diagnostics; using System.Reflection; using MS.Utility; #if PBTCOMPILER namespace MS.Internal.Markup #else using System.Windows; using System.Windows.Threading; namespace System.Windows.Markup #endif { ////// Handles overrides for case when Template is being built to a tree /// instead of compiling to a file. /// internal class TemplateXamlParser : XamlParser { #region Constructors #if !PBTCOMPILER ////// Constructor. /// ////// Note that we are re-using the token reader, so we'll swap out the XamlParser that /// the token reader uses with ourself. Then restore it when we're done parsing. /// internal TemplateXamlParser( XamlTreeBuilder treeBuilder, XamlReaderHelper tokenReader, ParserContext parserContext) : this(tokenReader, parserContext) { _treeBuilder = treeBuilder; } #endif ////// Constructor. /// ////// Note that we are re-using the token reader, so we'll swap out the XamlParser that /// the token reader uses with ourself. Then restore it when we're done parsing. /// internal TemplateXamlParser( XamlReaderHelper tokenReader, ParserContext parserContext) { TokenReader = tokenReader; ParserContext = parserContext; _previousXamlParser = TokenReader.ControllingXamlParser; TokenReader.ControllingXamlParser = this; _startingDepth = TokenReader.XmlReader.Depth; } #endregion Constructors #region Overrides ////// Override of the main switch statement that processes the xaml nodes. /// ////// We need to control when cleanup is done and when the calling parse loop /// is exited, so do this here. /// internal override void ProcessXamlNode( XamlNode xamlNode, ref bool cleanup, ref bool done) { switch(xamlNode.TokenType) { // Ignore some types of xaml nodes, since they are not // relevent to template parsing. case XamlNodeType.DocumentStart: case XamlNodeType.DocumentEnd: break; case XamlNodeType.ElementEnd: base.ProcessXamlNode(xamlNode, ref cleanup, ref done); // If we're at the depth that we started out, then we must be done. In that case quit // and restore the XamlParser that the token reader was using before parsing templates. if (_styleModeStack.Depth == 0) { done = true; // Stop the template parse cleanup = false; // Don't close the stream TokenReader.ControllingXamlParser = _previousXamlParser; } break; case XamlNodeType.PropertyArrayStart: case XamlNodeType.PropertyArrayEnd: case XamlNodeType.DefTag: ThrowException(SRID.TemplateTagNotSupported, xamlNode.TokenType.ToString(), xamlNode.LineNumber, xamlNode.LinePosition); break; #if PBTCOMPILER case XamlNodeType.EndAttributes: // if there's a DataType present but no x:Key, write out // the key now based on the DataType if (_dataTypePropertyNode != null && _dataTypePropertyNodeDepth == _styleModeStack.Depth) { if (!_defNameFound) { WriteDataTypeKey(_dataTypePropertyNode); } _dataTypePropertyNode = null; _dataTypePropertyNodeDepth = -1; } base.ProcessXamlNode(xamlNode, ref cleanup, ref done); break; #endif // Most nodes are handled by the base XamlParser by creating a // normal BamlRecord. default: base.ProcessXamlNode(xamlNode, ref cleanup, ref done); break; } } ////// Write start of an unknown tag /// ////// For template parsing, the 'Set' tag is an unknown tag, but this will map to a /// Trigger set command. Store this as an element start record here. /// Also 'Set.Value' will map to the a complex Value set portion of the Set command. /// public override void WriteUnknownTagStart(XamlUnknownTagStartNode xamlUnknownTagStartNode) { StyleMode mode = _styleModeStack.Mode; // Keep mode and other state up-to-date. This // must be called before updating stack. CommonElementStartProcessing(xamlUnknownTagStartNode, null, ref mode); _styleModeStack.Push(mode); #if PBTCOMPILER string localElementFullName = string.Empty; int lastIndex = xamlUnknownTagStartNode.Value.LastIndexOf('.'); // if local complex property bail out now and handle in 2nd pass when TypInfo is available if (-1 == lastIndex) { NamespaceMapEntry[] namespaceMaps = XamlTypeMapper.GetNamespaceMapEntries(xamlUnknownTagStartNode.XmlNamespace); if (namespaceMaps != null && namespaceMaps.Length == 1 && namespaceMaps[0].LocalAssembly) { localElementFullName = namespaceMaps[0].ClrNamespace + "." + xamlUnknownTagStartNode.Value; } } else if (IsLocalPass1) { return; } if (localElementFullName.Length == 0 || !IsLocalPass1) { #endif // It can be a fairly common error for, //, , or // to be specified at the wrong nesting level (See Windows bug 966137). Detect // these cases to give more meaningful error messages. if (xamlUnknownTagStartNode.Value == XamlTemplateSerializer.ControlTemplateTriggersFullPropertyName || xamlUnknownTagStartNode.Value == XamlTemplateSerializer.DataTemplateTriggersFullPropertyName || xamlUnknownTagStartNode.Value == XamlTemplateSerializer.HierarchicalDataTemplateTriggersFullPropertyName || xamlUnknownTagStartNode.Value == XamlTemplateSerializer.HierarchicalDataTemplateItemsSourceFullPropertyName || xamlUnknownTagStartNode.Value == XamlTemplateSerializer.HierarchicalDataTemplateItemTemplateFullPropertyName || xamlUnknownTagStartNode.Value == XamlTemplateSerializer.HierarchicalDataTemplateItemTemplateSelectorFullPropertyName || xamlUnknownTagStartNode.Value == XamlTemplateSerializer.HierarchicalDataTemplateItemContainerStyleFullPropertyName || xamlUnknownTagStartNode.Value == XamlTemplateSerializer.HierarchicalDataTemplateItemContainerStyleSelectorFullPropertyName || xamlUnknownTagStartNode.Value == XamlTemplateSerializer.HierarchicalDataTemplateItemStringFormatFullPropertyName || xamlUnknownTagStartNode.Value == XamlTemplateSerializer.HierarchicalDataTemplateItemBindingGroupFullPropertyName || xamlUnknownTagStartNode.Value == XamlTemplateSerializer.HierarchicalDataTemplateAlternationCountFullPropertyName ) { ThrowException(SRID.TemplateKnownTagWrongLocation, xamlUnknownTagStartNode.Value, xamlUnknownTagStartNode.LineNumber, xamlUnknownTagStartNode.LinePosition); } else { base.WriteUnknownTagStart(xamlUnknownTagStartNode); } #if PBTCOMPILER } #endif } /// /// Write Start element for a dictionary key section. /// public override void WriteKeyElementStart( XamlElementStartNode xamlKeyElementStartNode) { _styleModeStack.Push(StyleMode.Key); base.WriteKeyElementStart(xamlKeyElementStartNode); } ////// Write End element for a dictionary key section /// public override void WriteKeyElementEnd( XamlElementEndNode xamlKeyElementEndNode) { _styleModeStack.Pop(); base.WriteKeyElementEnd(xamlKeyElementEndNode); } ////// Write end of an unknown tag /// ////// For template parsing, the 'Set' tag is an unknown tag, but this will map to a /// Trigger set command. Store this as an element end record here. /// public override void WriteUnknownTagEnd(XamlUnknownTagEndNode xamlUnknownTagEndNode) { if (_inSetterDepth == xamlUnknownTagEndNode.Depth) { XamlElementEndNode elementEnd = new XamlElementEndNode( xamlUnknownTagEndNode.LineNumber, xamlUnknownTagEndNode.LinePosition, xamlUnknownTagEndNode.Depth); base.WriteElementEnd(elementEnd); _inSetterDepth = -1; } else { #if PBTCOMPILER NamespaceMapEntry[] namespaceMaps = XamlTypeMapper.GetNamespaceMapEntries(xamlUnknownTagEndNode.XmlNamespace); bool localTag = namespaceMaps != null && namespaceMaps.Length == 1 && namespaceMaps[0].LocalAssembly; if (!localTag || !IsLocalPass1) { #endif base.WriteUnknownTagEnd(xamlUnknownTagEndNode); #if PBTCOMPILER } #endif } _styleModeStack.Pop(); } ////// Write unknown attribute /// ////// For template parsing, the 'Set' tag is an unknown tag and contains properties that /// are passed as UnknownAttributes. Translate these into Property records. /// public override void WriteUnknownAttribute(XamlUnknownAttributeNode xamlUnknownAttributeNode) { #if PBTCOMPILER bool localAttrib = false; string localTagFullName = string.Empty; string localAttribName = xamlUnknownAttributeNode.Name; NamespaceMapEntry[] namespaceMaps = null; if (xamlUnknownAttributeNode.OwnerTypeFullName.Length > 0) { // These are attributes on a local tag ... localTagFullName = xamlUnknownAttributeNode.OwnerTypeFullName; localAttrib = true; } else { // These are attributes on a non-local tag ... namespaceMaps = XamlTypeMapper.GetNamespaceMapEntries(xamlUnknownAttributeNode.XmlNamespace); localAttrib = namespaceMaps != null && namespaceMaps.Length == 1 && namespaceMaps[0].LocalAssembly; } if (localAttrib) { // ... and if there are any periods in the attribute name, then ... int lastIndex = localAttribName.LastIndexOf('.'); if (-1 != lastIndex) { // ... these might be attached props or events defined by a locally defined component, // but being set on this non-local tag. string ownerTagName = localAttribName.Substring(0, lastIndex); if (namespaceMaps != null) { if (namespaceMaps.Length == 1 && namespaceMaps[0].LocalAssembly) { localTagFullName = namespaceMaps[0].ClrNamespace + "." + ownerTagName; } } else { TypeAndSerializer typeAndSerializer = XamlTypeMapper.GetTypeOnly(xamlUnknownAttributeNode.XmlNamespace, ownerTagName); if (typeAndSerializer != null) { Type ownerTagType = typeAndSerializer.ObjectType; localTagFullName = ownerTagType.FullName; } else { namespaceMaps = XamlTypeMapper.GetNamespaceMapEntries(xamlUnknownAttributeNode.XmlNamespace); if (namespaceMaps != null && namespaceMaps.Length == 1 && namespaceMaps[0].LocalAssembly) { localTagFullName = namespaceMaps[0].ClrNamespace + "." + ownerTagName; } else { localTagFullName = string.Empty; } } } localAttribName = localAttribName.Substring(lastIndex + 1); } } if (localTagFullName.Length == 0 || !IsLocalPass1) { #endif base.WriteUnknownAttribute(xamlUnknownAttributeNode); #if PBTCOMPILER } #endif } ////// WriteEndAttributes occurs after the last attribute (property, complex property or /// def record) is written. Note that if there are none of the above, then WriteEndAttributes /// is not called for a normal start tag. /// public override void WriteEndAttributes(XamlEndAttributesNode xamlEndAttributesNode) { #if PBTCOMPILER // reset the event scope so that a new tag may start a new scope for its own events if (_styleModeStack.Mode == StyleMode.VisualTree && !xamlEndAttributesNode.IsCompact) { _isSameScope = false; } #endif if (_styleModeStack.Mode == StyleMode.TriggerBase && !xamlEndAttributesNode.IsCompact) { MemberInfo dpInfo = null; if (_setterOrTriggerPropertyNode != null) { dpInfo = GetDependencyPropertyInfo(_setterOrTriggerPropertyNode); base.WriteProperty(_setterOrTriggerPropertyNode); _setterOrTriggerPropertyNode = null; _setterOrTriggerPropertyMemberInfo = dpInfo; } _setterTargetNameOrConditionSourceName = null; if (_setterOrTriggerValueNode != null) { ProcessPropertyValueNode(); } } base.WriteEndAttributes(xamlEndAttributesNode); } private MemberInfo GetDependencyPropertyInfo(XamlPropertyNode xamlPropertyNode) { string member = xamlPropertyNode.Value; MemberInfo dpInfo = GetCLRPropertyInfo(xamlPropertyNode, ref member); if (dpInfo != null) { // Note: Should we enforce that all DP fields should end with a // "Property" or "PropertyKey" postfix here? if (BamlRecordWriter != null) { short typeId; short propertyId = MapTable.GetAttributeOrTypeId(BamlRecordWriter.BinaryWriter, dpInfo.DeclaringType, member, out typeId); if (propertyId < 0) { xamlPropertyNode.ValueId = propertyId; xamlPropertyNode.MemberName = null; } else { xamlPropertyNode.ValueId = typeId; xamlPropertyNode.MemberName = member; } } } return dpInfo; } private MemberInfo GetCLRPropertyInfo(XamlPropertyNode xamlPropertyNode, ref string member) { // Strip off namespace prefix from the event or property name and // map this to an xmlnamespace. Also extract the class name, if present string prefix = string.Empty; string target = member; string propertyName = member; int dotIndex = member.LastIndexOf('.'); if (-1 != dotIndex) { target = propertyName.Substring(0, dotIndex); member = propertyName.Substring(dotIndex+1); } int colonIndex = target.IndexOf(':'); if (-1 != colonIndex) { // If using .net then match against the class. prefix = target.Substring(0, colonIndex); if (-1 == dotIndex) { member = target.Substring(colonIndex+1); } } string xmlNamespace = TokenReader.XmlReader.LookupNamespace(prefix); Type targetType = null; // Get the type associated with the property or event from the XamlTypeMapper and // use this to resolve the property or event into an EventInfo, PropertyInfo // or MethodInfo if (-1 != dotIndex) { targetType = XamlTypeMapper.GetTypeFromBaseString(target, ParserContext, false); } else if (_setterTargetNameOrConditionSourceName != null) { targetType = _IDTypes[_setterTargetNameOrConditionSourceName] as Type; if (targetType == null #if PBTCOMPILER && !IsLocalPass1 #endif ) { ThrowException(SRID.TemplateNoTriggerTarget, _setterTargetNameOrConditionSourceName, xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition); } } else { targetType = TargetType; } MemberInfo memberInfo = null; if (targetType != null) { string objectName = propertyName; memberInfo = XamlTypeMapper.GetClrInfo( false, targetType, xmlNamespace, member, ref objectName) as MemberInfo; } if (memberInfo != null) { PropertyInfo pi = memberInfo as PropertyInfo; if (pi != null) { // For trigger condition only allow if public or internal getter if (_inSetterDepth < 0 && _styleModeStack.Mode == StyleMode.TriggerBase) { if (!XamlTypeMapper.IsAllowedPropertyGet(pi)) { ThrowException(SRID.ParserCantSetTriggerCondition, pi.Name, xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition); } } else // for general Setters check prop setters { if (!XamlTypeMapper.IsAllowedPropertySet(pi)) { ThrowException(SRID.ParserCantSetAttribute, "Property Setter", pi.Name, "set", xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition); } } } } // local properties will be added to the baml in pass2 of the compilation. // so don't throw now. else #if PBTCOMPILER if (!IsLocalPass1) #endif { if (targetType != null) { ThrowException(SRID.TemplateNoProp, member, targetType.FullName, xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition); } else { ThrowException(SRID.TemplateNoTarget, member, xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition); } } return memberInfo; } ////// The Value="foo" property node for a Setter and a Trigger has been saved /// and is resolved some time afterwards using the associated Property="Bar" /// attribute. This is done so that the property record can be written using /// the type converter associated with "Bar" /// private void ProcessPropertyValueNode() { Debug.Assert(_setterOrTriggerValueNode != null); if (_setterOrTriggerPropertyMemberInfo != null) { // Now we have PropertyInfo or a MethodInfo for the property setter. // Get the type of the property from this which will be used // by BamlRecordWriter.WriteProperty to find an associated // TypeConverter to use at runtime. // To allow for per-property type converters we need to extract // information from the member info about the property Type propertyType = XamlTypeMapper.GetPropertyType(_setterOrTriggerPropertyMemberInfo); _setterOrTriggerValueNode.ValuePropertyType = propertyType; _setterOrTriggerValueNode.ValuePropertyMember = _setterOrTriggerPropertyMemberInfo; _setterOrTriggerValueNode.ValuePropertyName = XamlTypeMapper.GetPropertyName(_setterOrTriggerPropertyMemberInfo); _setterOrTriggerValueNode.ValueDeclaringType = _setterOrTriggerPropertyMemberInfo.DeclaringType; base.WriteProperty(_setterOrTriggerValueNode); } else { base.WriteBaseProperty(_setterOrTriggerValueNode); } _setterOrTriggerValueNode = null; _setterOrTriggerPropertyNode = null; _setterTargetNameOrConditionSourceName = null; _setterOrTriggerPropertyMemberInfo = null; } ////// Write Def Attribute /// ////// Template parsing supports x:ID, so check for this here /// public override void WriteDefAttribute(XamlDefAttributeNode xamlDefAttributeNode) { if (xamlDefAttributeNode.Name == BamlMapTable.NameString) { if (BamlRecordWriter != null) { BamlRecordWriter.WriteDefAttribute(xamlDefAttributeNode); } } else { #if PBTCOMPILER // Remember that x:Key was read in, since this key has precedence over // the DataType="{x:Type SomeType}" key that may also be present. if (xamlDefAttributeNode.Name == XamlReaderHelper.DefinitionName && _styleModeStack.Mode == StyleMode.Base) { _defNameFound = true; } #endif base.WriteDefAttribute(xamlDefAttributeNode); } } #if PBTCOMPILER ////// Write out a key to a dictionary that has been resolved at compile or parse /// time to a Type object. /// public override void WriteDefAttributeKeyType(XamlDefAttributeKeyTypeNode xamlDefNode) { // Remember that x:Key was read in, since this key has precedence over // the TargetType="{x:Type SomeType}" key that may also be present. if (_styleModeStack.Mode == StyleMode.Base) { _defNameFound = true; } base.WriteDefAttributeKeyType(xamlDefNode); } #endif ////// Write Start of an Element, which is a tag of the form / ////// /// For template parsing, determine when it is withing a Trigger or /// MultiTrigger section. This is done for validity checking of /// unknown tags and attributes. /// 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 thesection 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 // , 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. // // 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); } } } // // CommonElementStartProcessing // // This is used by WriteElementStart and WriteUnknownTagStart. It is used // to keep style mode up-to-date. // private void CommonElementStartProcessing (XamlNode xamlNode, Type elementType, ref StyleMode mode) { if (mode == StyleMode.Base && _styleModeStack.Depth > 0 ) { if (_templateRootCount++ > 0) { ThrowException(SRID.TemplateNoMultipleRoots, (elementType == null ? "Unknown tag" : elementType.Name), xamlNode.LineNumber, xamlNode.LinePosition); } // Validate that the root is an FE or FCE. If the type is unknown (and internal type), we'll // catch this during template instantiation. if (elementType != null && !KnownTypes.Types[(int)KnownElements.FrameworkElement].IsAssignableFrom(elementType) && !KnownTypes.Types[(int)KnownElements.FrameworkContentElement].IsAssignableFrom(elementType)) { ThrowException(SRID.TemplateInvalidRootElementTag, elementType.ToString(), xamlNode.LineNumber, xamlNode.LinePosition); } mode = StyleMode.VisualTree; } } ///// //// //// //// //// //// // ///// Write End Element /// ////// For template parsing, determine when it is withing a Trigger or /// MultiTrigger section. This is done for validity checking of /// unknown tags and attributes. /// public override void WriteElementEnd(XamlElementEndNode xamlElementEndNode) { bool tagWritten = false; if (_styleModeStack.Mode == StyleMode.TriggerBase && xamlElementEndNode.Depth == _inSetterDepth) { // Just exited thesection of a Trigger _inSetterDepth = -1; } if (xamlElementEndNode.Depth == _inPropertyTriggerDepth) { _inPropertyTriggerDepth = -1; } #if PBTCOMPILER if (_styleModeStack.Mode == StyleMode.DataTypeProperty && InDeferLoadedSection && !_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 in addition to generating the records to set // the TargetType value. if (_styleModeStack.Depth == 2) { base.WriteElementEnd(xamlElementEndNode); base.WriteConstructorParametersEnd(new XamlConstructorParametersEndNode( xamlElementEndNode.LineNumber, xamlElementEndNode.LinePosition, xamlElementEndNode.Depth)); base.WriteKeyElementEnd(xamlElementEndNode); tagWritten = true; } } #endif // Track elements during compile so that we can resolve names to types. This // is useful when resolving Setter Property / Value. _elementTypeStack.Pop(); _styleModeStack.Pop(); if (!tagWritten) { base.WriteElementEnd(xamlElementEndNode); } } private Type TargetType { get { return (_templateTargetTypeType != null ? _templateTargetTypeType #if PBTCOMPILER : IsLocalPass1 ? null #endif : _defaultTargetType); } } #if PBTCOMPILER /// /// Write the start of a constructor parameter section /// public override void WriteConstructorParameterType( XamlConstructorParameterTypeNode xamlConstructorParameterTypeNode) { if (_styleModeStack.Mode == StyleMode.DataTypeProperty && InDeferLoadedSection && !_defNameFound) { // Generate a series of baml records to use as the key for the defer loaded // body of the Style in addition to generating the records to set // the normal constructor. base.WriteConstructorParameterType(xamlConstructorParameterTypeNode); } base.WriteConstructorParameterType(xamlConstructorParameterTypeNode); } #endif ////// Write the start of a constructor parameter section /// public override void WriteConstructorParametersStart(XamlConstructorParametersStartNode xamlConstructorParametersStartNode) { #if PBTCOMPILER if (_styleModeStack.Mode == StyleMode.DataTypeProperty && InDeferLoadedSection && !_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 in addition to generating the records to set // the TargetType value. base.WriteConstructorParametersStart(xamlConstructorParametersStartNode); } #endif _styleModeStack.Push(); base.WriteConstructorParametersStart(xamlConstructorParametersStartNode); } ////// Write the end of a constructor parameter section /// public override void WriteConstructorParametersEnd(XamlConstructorParametersEndNode xamlConstructorParametersEndNode) { #if PBTCOMPILER if (_styleModeStack.Mode == StyleMode.DataTypeProperty && InDeferLoadedSection && !_defNameFound && _styleModeStack.Depth > 2) { // 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 in addition to generating the records to set // the TargetType value. base.WriteConstructorParametersEnd(xamlConstructorParametersEndNode); } #endif base.WriteConstructorParametersEnd(xamlConstructorParametersEndNode); _styleModeStack.Pop(); } ////// Write start of a complex property /// ////// For template parsing, treat complex property tags as /// xml element tags for the purpose of validity checking /// public override void WritePropertyComplexStart(XamlPropertyComplexStartNode xamlNode) { StyleMode mode = _styleModeStack.Mode; if (_styleModeStack.Depth == 1) { if (xamlNode.PropName == XamlTemplateSerializer.TargetTypePropertyName) { mode = StyleMode.TargetTypeProperty; } else if (xamlNode.PropName == XamlTemplateSerializer.DataTypePropertyName) { mode = StyleMode.DataTypeProperty; } else if (xamlNode.PropName == XamlTemplateSerializer.ItemsSourcePropertyName || xamlNode.PropName == XamlTemplateSerializer.ItemTemplatePropertyName || xamlNode.PropName == XamlTemplateSerializer.ItemTemplateSelectorPropertyName || xamlNode.PropName == XamlTemplateSerializer.ItemContainerStylePropertyName || xamlNode.PropName == XamlTemplateSerializer.ItemContainerStyleSelectorPropertyName || xamlNode.PropName == XamlTemplateSerializer.ItemStringFormatPropertyName || xamlNode.PropName == XamlTemplateSerializer.ItemBindingGroupPropertyName || xamlNode.PropName == XamlTemplateSerializer.AlternationCountPropertyName ) { mode = StyleMode.ComplexProperty; } else { ThrowException(SRID.TemplateUnknownProp, xamlNode.PropName, xamlNode.LineNumber, xamlNode.LinePosition); } } else if (mode == StyleMode.VisualTree) { _visualTreeComplexPropertyDepth++; } else if (mode == StyleMode.TriggerBase) { _triggerComplexPropertyDepth++; } #if PBTCOMPILER else if (mode == StyleMode.DataTypeProperty && InDeferLoadedSection && !_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 in addition to generating the records to set // the TargetType value. base.WritePropertyComplexStart(xamlNode); } #endif _styleModeStack.Push(mode); base.WritePropertyComplexStart(xamlNode); } ////// Write end of a complex property /// ////// For template parsing, treat complex property tags as /// xml element tags for the purpose of validity checking /// public override void WritePropertyComplexEnd(XamlPropertyComplexEndNode xamlNode) { StyleMode mode = _styleModeStack.Mode; if (mode == StyleMode.VisualTree) { _visualTreeComplexPropertyDepth--; } if (mode == StyleMode.TriggerBase) { _triggerComplexPropertyDepth--; } #if PBTCOMPILER else if (mode == StyleMode.DataTypeProperty && InDeferLoadedSection && !_defNameFound && _styleModeStack.Depth > 2) { // 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 in addition to generating the records to set // the TargetType value. base.WritePropertyComplexEnd(xamlNode); } #endif if (_styleModeStack.Depth <= 2) { mode = StyleMode.Base; } _styleModeStack.Pop(); base.WritePropertyComplexEnd(xamlNode); } ////// Write start of a list complex property /// ////// For template parsing, treat complex property tags as /// xml element tags for the purpose of validity checking /// public override void WritePropertyIListStart(XamlPropertyIListStartNode xamlNode) { StyleMode mode = _styleModeStack.Mode; if (_styleModeStack.Depth == 1) { if (xamlNode.PropName == XamlTemplateSerializer.TriggersPropertyName) { mode = StyleMode.TriggerBase; } else { ThrowException(SRID.TemplateUnknownProp, xamlNode.PropName, xamlNode.LineNumber, xamlNode.LinePosition); } } else if (mode == StyleMode.VisualTree) { _visualTreeComplexPropertyDepth++; } else if (mode == StyleMode.TriggerBase && _styleModeStack.Depth == 2) { mode = StyleMode.Base; } else if (mode == StyleMode.TriggerBase && _styleModeStack.Depth == 3 && xamlNode.PropName == XamlTemplateSerializer.EventTriggerActions) { mode = StyleMode.TriggerActions; } else if (mode == StyleMode.TriggerBase) { _triggerComplexPropertyDepth++; } _styleModeStack.Push(mode); base.WritePropertyIListStart(xamlNode); } ////// Write end of a list complex property /// ////// For template parsing, treat complex property tags as /// xml element tags for the purpose of validity checking when we're counting /// element tags. /// public override void WritePropertyIListEnd(XamlPropertyIListEndNode xamlNode) { if (_styleModeStack.Mode == StyleMode.VisualTree) { _visualTreeComplexPropertyDepth--; } else if (_styleModeStack.Mode == StyleMode.TriggerBase) { _triggerComplexPropertyDepth--; } base.WritePropertyIListEnd(xamlNode); _styleModeStack.Pop(); } ////// Write Property Array Start /// public override void WritePropertyArrayStart(XamlPropertyArrayStartNode xamlPropertyArrayStartNode) { if (_styleModeStack.Mode == StyleMode.VisualTree) { _visualTreeComplexPropertyDepth++; } else if (_styleModeStack.Mode == StyleMode.TriggerBase) { _triggerComplexPropertyDepth++; } base.WritePropertyArrayStart(xamlPropertyArrayStartNode); _styleModeStack.Push(); } ////// Write Property Array End /// public override void WritePropertyArrayEnd(XamlPropertyArrayEndNode xamlPropertyArrayEndNode) { if (_styleModeStack.Mode == StyleMode.VisualTree) { _visualTreeComplexPropertyDepth--; } else if (_styleModeStack.Mode == StyleMode.TriggerBase) { _triggerComplexPropertyDepth--; } base.WritePropertyArrayEnd(xamlPropertyArrayEndNode); _styleModeStack.Pop(); } ////// Write Property IDictionary Start /// public override void WritePropertyIDictionaryStart(XamlPropertyIDictionaryStartNode xamlPropertyIDictionaryStartNode) { StyleMode mode = _styleModeStack.Mode; if (mode == StyleMode.VisualTree) { _visualTreeComplexPropertyDepth++; } else if (mode == StyleMode.TriggerBase) { _triggerComplexPropertyDepth++; } else if (_styleModeStack.Depth == 1 && mode == StyleMode.Base) { if( xamlPropertyIDictionaryStartNode.PropName == XamlTemplateSerializer.ResourcesPropertyName) { mode = StyleMode.Resources; } else { ThrowException(SRID.TemplateUnknownProp, xamlPropertyIDictionaryStartNode.PropName, xamlPropertyIDictionaryStartNode.LineNumber, xamlPropertyIDictionaryStartNode.LinePosition); } } base.WritePropertyIDictionaryStart(xamlPropertyIDictionaryStartNode); _styleModeStack.Push(mode); } ////// Write Property IDictionary End /// public override void WritePropertyIDictionaryEnd(XamlPropertyIDictionaryEndNode xamlPropertyIDictionaryEndNode) { StyleMode mode = _styleModeStack.Mode; if (mode == StyleMode.VisualTree) { _visualTreeComplexPropertyDepth--; } else if (mode == StyleMode.TriggerBase) { _triggerComplexPropertyDepth--; } base.WritePropertyIDictionaryEnd(xamlPropertyIDictionaryEndNode); _styleModeStack.Pop(); } ////// Write Text node and do template related error checking /// public override void WriteText(XamlTextNode xamlTextNode) { StyleMode mode = _styleModeStack.Mode; // Text is only valid within certain locations in the Template section. // Check for all the valid locations and write out the text record. For // all other locations, see if the text is non-blank and throw an error // if it is. Ignore any whitespace, since this is not considered // significant in Style cases. if (mode == StyleMode.TargetTypeProperty) { // Remember the TargetType so that the setter parsing could use it // to resolve non-qualified property names if (xamlTextNode.Text != null) { _templateTargetTypeType = XamlTypeMapper.GetTypeFromBaseString(xamlTextNode.Text, ParserContext, true); } } #if PBTCOMPILER if (mode == StyleMode.DataTypeProperty && InDeferLoadedSection && !_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 in addition to generating the records to set // the TargetType value. base.WriteText(xamlTextNode); } #endif // Text is only valid within certain locations in the section. // Check for all the valid locations and write out the text record. For // all other locations, see if the text is non-blank and throw an error // if it is. Ignore any whitespace, since this is not considered // significant in Template cases. if (mode != StyleMode.TriggerBase || _inSetterDepth >= 0 || _triggerComplexPropertyDepth >= 0) { base.WriteText(xamlTextNode); } else { for (int i = 0; i< xamlTextNode.Text.Length; i++) { if (!XamlReaderHelper.IsWhiteSpace(xamlTextNode.Text[i])) { ThrowException(SRID.TemplateTextNotSupported, xamlTextNode.Text, xamlTextNode.LineNumber, xamlTextNode.LinePosition); } } } } #if PBTCOMPILER ////// Write an Event Connector and call the controlling compiler parser to generate event hookup code. /// public override void WriteClrEvent(XamlClrEventNode xamlClrEventNode) { if (_previousXamlParser != null) { Debug.Assert(_styleModeStack.Mode == StyleMode.VisualTree); // if this event token is not owned by this TemplateXamlParser, then just chain // the WriteClrEvent call to the controlling parser. Ulimately, this will // reach the markup compiler that will deal with this info as appropriate. bool isOriginatingEvent = xamlClrEventNode.IsOriginatingEvent; if (isOriginatingEvent) { // set up additional state on event node for the markup compiler to use. Debug.Assert(!xamlClrEventNode.IsStyleSetterEvent); xamlClrEventNode.IsTemplateEvent = true; xamlClrEventNode.IsSameScope = _isSameScope; // any intermediary controlling parsers need to get out of the way so that // the markup compiler can ultimately do its thing. xamlClrEventNode.IsOriginatingEvent = false; // Store away the type of the element we're currently in. E.g. // in , this will be typeof(Button). // In the case of regular CLR events, this type is the same as that // which can be found in xamlClrEventNode.EventMember. But in the // case of attached events, EventMember is the class that holds // the attached event, and the compiler needs to know the type of // the listener. xamlClrEventNode.ListenerType = (Type) _elementTypeStack.Peek(); } _previousXamlParser.WriteClrEvent(xamlClrEventNode); if (isOriginatingEvent) { if (!String.IsNullOrEmpty(xamlClrEventNode.LocalAssemblyName)) { // if this event is a local event need to generate baml for it now XamlPropertyNode xamlPropertyNode = new XamlPropertyNode(xamlClrEventNode.LineNumber, xamlClrEventNode.LinePosition, xamlClrEventNode.Depth, null, xamlClrEventNode.LocalAssemblyName, xamlClrEventNode.EventMember.ReflectedType.FullName, xamlClrEventNode.EventName, xamlClrEventNode.Value, BamlAttributeUsage.Default, false); base.WriteProperty(xamlPropertyNode); } else { // write out a connectionId to the baml stream only if a // new event scope was encountered if (!_isSameScope) { base.WriteConnectionId(xamlClrEventNode.ConnectionId); } // We have just finished processing the start of a new event scope. // So specifiy start of this new scope. _isSameScope = true; } } } } #endif ////// Write a Property, which has the form in markup of property="value". /// ////// When in a VisualTree, only DependencyProperties can be set directly on /// a FrameworkElementFactory. This method checks the state of parsing and /// with throw an exception if a clr property is set on a FrameworkElementFactory. /// public override void WriteProperty(XamlPropertyNode xamlPropertyNode) { StyleMode mode = _styleModeStack.Mode; if (mode == StyleMode.TriggerBase && WritePropertyForTriggers(xamlPropertyNode)) { return; } // If we are on the DataTemplate tag itself, and we encounter a DataType property, // this can be used as the key when placing this template in a ResourceDictionary. // In that case, remember what the property value is so that we can // later update the defer key held by the baml writer. if (mode == StyleMode.Base && xamlPropertyNode.PropName == XamlTemplateSerializer.DataTypePropertyName) { #if PBTCOMPILER // Treat DataType="some string" as a key in a resource dictionary. // Generate a sequence of baml records to describe the key. if (InDeferLoadedSection && !_defNameFound) { base.WriteKeyElementStart(new XamlElementStartNode( xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition, xamlPropertyNode.Depth, _templateKeyType.Assembly.FullName, _templateKeyType.FullName, _templateKeyType, null)); base.WriteConstructorParametersStart(new XamlConstructorParametersStartNode( xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition, xamlPropertyNode.Depth)); base.WriteText(new XamlTextNode( xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition, xamlPropertyNode.Depth, xamlPropertyNode.Value, null)); base.WriteConstructorParametersEnd(new XamlConstructorParametersEndNode( xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition, xamlPropertyNode.Depth)); base.WriteKeyElementEnd(new XamlElementEndNode( xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition, xamlPropertyNode.Depth)); } #endif } #if PBTCOMPILER else if (mode == StyleMode.DataTypeProperty && InDeferLoadedSection && !_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. base.WriteProperty(xamlPropertyNode); } #endif xamlPropertyNode.DefaultTargetType = TargetType; base.WriteProperty(xamlPropertyNode); // If the property being written identifies a Runtime name, then remember // the name and the type associated with it. This may be needed for // Setter value and property resolutions later on. if (xamlPropertyNode.AttributeUsage == BamlAttributeUsage.RuntimeName) { if (_IDTypes.ContainsKey(xamlPropertyNode.Value)) { ThrowException(SRID.TemplateDupName, xamlPropertyNode.Value, xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition); } else { _IDTypes[xamlPropertyNode.Value] = _elementTypeStack.Peek() as Type; } } } ////// Handle property node when within a Triggers section. Return true if this /// node is fully handled and needs no further processing. /// private bool WritePropertyForTriggers(XamlPropertyNode xamlPropertyNode) { if (_inSetterDepth >= 0) { if (xamlPropertyNode.PropName == XamlTemplateSerializer.SetterValueAttributeName) { _setterOrTriggerValueNode = xamlPropertyNode; // Delay writing out the Value attribute until WriteEndAttributes if this is a // normal property node. If this is a property node that was created from complex // syntax, then the WriteEndAttributes has already occurred, so process the // node now. if (xamlPropertyNode.ComplexAsSimple) { ProcessPropertyValueNode(); } return true; } else if (xamlPropertyNode.PropName == XamlTemplateSerializer.SetterPropertyAttributeName) { // Property names should be trimmed since whitespace is not significant // and can affect name resolution (See Windows bug 1035621) xamlPropertyNode.SetValue(xamlPropertyNode.Value.Trim()); _setterOrTriggerPropertyNode = xamlPropertyNode; // return now as Setter.TargetName might not have been set yet and we need that for resolving // the property name. So this is done in WriteEndattributes. return true; } else if (xamlPropertyNode.PropName == XamlTemplateSerializer.SetterTargetAttributeName) { _setterTargetNameOrConditionSourceName = xamlPropertyNode.Value; } } else { if (xamlPropertyNode.PropName == XamlTemplateSerializer.PropertyTriggerValuePropertyName) { // DataTrigger doesn't have a "Property" property so value has to be written directly. // This check filters out if "Property" was actually set vs. not present at all for // other Triggers. Type t = (Type)_elementTypeStack.Peek(); if (!KnownTypes.Types[(int)KnownElements.DataTrigger].IsAssignableFrom(t)) { _setterOrTriggerValueNode = xamlPropertyNode; // Delay writing out the Value attribute until WriteEndAttributes if this is a // normal property node. If this is a property node that was created from complex // syntax, then the WriteEndAttributes has already occurred, so process the // node now. if (xamlPropertyNode.ComplexAsSimple) { ProcessPropertyValueNode(); } return true; } } else if (xamlPropertyNode.PropName == XamlTemplateSerializer.PropertyTriggerPropertyName) { // Property names should be trimmed since whitespace is not significant // and can affect name resolution (See Windows bug 1035621) xamlPropertyNode.SetValue(xamlPropertyNode.Value.Trim()); _setterOrTriggerPropertyNode = xamlPropertyNode; // return now as Trigger.SourceName might not have been set yet and we need that for resolving // the property name. So this is done in WriteEndattributes. return true; } else if (xamlPropertyNode.PropName == XamlTemplateSerializer.PropertyTriggerSourceName) { _setterTargetNameOrConditionSourceName = xamlPropertyNode.Value; } } return false; } public override void WritePropertyWithExtension(XamlPropertyWithExtensionNode xamlPropertyWithExtensionNode) { xamlPropertyWithExtensionNode.DefaultTargetType = TargetType; base.WritePropertyWithExtension(xamlPropertyWithExtensionNode); } ////// Write a Property, which has the form in markup of property="value" where /// value has been resolved to a Type reference. /// ////// When in a VisualTree, only DependencyProperties can be set directly on /// a FrameworkElementFactory. This method checks the state of parsing and /// with throw an exception if a clr property is set on a FrameworkElementFactory. /// public override void WritePropertyWithType(XamlPropertyWithTypeNode xamlPropertyNode) { StyleMode mode = _styleModeStack.Mode; if (mode == StyleMode.Base && xamlPropertyNode.PropName == XamlTemplateSerializer.TargetTypePropertyName) { _templateTargetTypeType = xamlPropertyNode.ValueElementType; } // If we are on the DataTemplate tag itself, and we encounter a DataType property, // this can be used as the key when placing this template in a ResourceDictionary. // In that case, remember what the property value is so that we can // later update the defer key held by the baml writer. else if (mode == StyleMode.Base && xamlPropertyNode.PropName == XamlTemplateSerializer.DataTypePropertyName) { #if PBTCOMPILER // Treat DataType="some type" as a key in a resource dictionary. // Generate a sequence of baml records to describe the key. if (InDeferLoadedSection && !_defNameFound) { _dataTypePropertyNode = xamlPropertyNode; _dataTypePropertyNodeDepth = _styleModeStack.Depth; } #endif } #if PBTCOMPILER else if (mode == StyleMode.DataTypeProperty && InDeferLoadedSection && !_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. base.WritePropertyWithType(xamlPropertyNode); } #endif base.WritePropertyWithType(xamlPropertyNode); } #if PBTCOMPILER // This method writes out BAML to produce a resource key based on the // DataType property. private void WriteDataTypeKey(XamlPropertyWithTypeNode xamlPropertyNode) { base.WriteKeyElementStart(new XamlElementStartNode( xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition, xamlPropertyNode.Depth, _templateKeyType.Assembly.FullName, _templateKeyType.FullName, _templateKeyType, null)); base.WriteConstructorParametersStart(new XamlConstructorParametersStartNode( xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition, xamlPropertyNode.Depth)); base.WriteConstructorParameterType(new XamlConstructorParameterTypeNode( xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition, xamlPropertyNode.Depth, xamlPropertyNode.ValueTypeFullName, xamlPropertyNode.ValueTypeAssemblyName, xamlPropertyNode.ValueElementType)); base.WriteConstructorParametersEnd(new XamlConstructorParametersEndNode( xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition, xamlPropertyNode.Depth)); base.WriteKeyElementEnd(new XamlElementEndNode( xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition, xamlPropertyNode.Depth)); } #endif ////// Used when an exception is thrown -- does shutdown on the parser and throws the exception. /// /// Exception internal override void ParseError(XamlParseException e) { CloseWriterStream(); #if !PBTCOMPILER // If there is an associated treebuilder, tell it about the error. There may not // be a treebuilder, if this parser was built from a serializer for the purpose of // converting directly to baml, rather than converting to an object tree. if (TreeBuilder != null) { TreeBuilder.XamlTreeBuildError(e); } #endif throw e; } ////// Called when the parse was cancelled by the designer or the user. /// internal override void ParseCancelled() { // Override so we don't close the writer stream, since we're a sub-parser } ////// Called when the parse has been completed successfully. /// internal override void ParseCompleted() { // Override so we don't close the writer stream, since we're a sub-parser } // Used to determine if strict or loose parsing rules should be enforced. The TokenReader // does some validations that are not valid in the case of parsing Templates, so do a // looser parsing validation. internal override bool StrictParsing { get { return false; } } #endregion Overrides #region Methods ////// Helper function if we are going to a Reader/Writer stream closes the writer /// side. /// internal void CloseWriterStream() { #if !PBTCOMPILER // only close the BamlRecordWriter. (Rename to Root??) if (null != BamlRecordWriter) { if (BamlRecordWriter.BamlStream is WriterStream) { WriterStream writeStream = (WriterStream) BamlRecordWriter.BamlStream; writeStream.Close(); } } #endif } #endregion Methods #region Properties #if !PBTCOMPILER ////// TreeBuilder associated with this class /// XamlTreeBuilder TreeBuilder { get { return _treeBuilder; } } #else ////// Return true if we are not in pass one of a compile and we are parsing a /// defer load section of markup. Note that if this is nested within a /// Style, then don't consider it to be in a defer loaded section since /// this is used a cue to determine when to generate dictionary keys. /// bool InDeferLoadedSection { get { return BamlRecordWriter != null && BamlRecordWriter.InDeferLoadedSection && _previousXamlParser.GetType() != typeof(StyleXamlParser); } } ////// Return true if this is pass one of a compile process. /// bool IsLocalPass1 { get { return BamlRecordWriter == null; } } #endif #endregion Properties #region Data #if !PBTCOMPILER // TreeBuilder that created this parser XamlTreeBuilder _treeBuilder; #endif // The XamlParser that the TokenReader was using when this instance of // the TemplateXamlParser was created. This must be restored on exit XamlParser _previousXamlParser; // Depth in the Xaml file when parsing of this template block started. // This is used to determine when to stop parsing int _startingDepth; // Number of template root nodes encountered immediately under a Template. Only 1 // is allowed. int _templateRootCount; StyleModeStack _styleModeStack = new StyleModeStack(); // Depth in the element tree where ahas begun. int _inSetterDepth = -1; // The actual Type of the TargetType property on template. This may be null. Type _templateTargetTypeType; // The default TargetType of the template to use when TargetType is not set. Type _defaultTargetType; // The XamlPropertyNode for the "Foo" Property attribute in // or XamlPropertyNode _setterOrTriggerPropertyNode; // The Property node for Value attribute in or // XamlPropertyNode _setterOrTriggerValueNode; // Depth in the element tree where a Trigger or MultiTrigger // section has begun. Set to -1 to indicate it is not within such a section. int _inPropertyTriggerDepth = -1; // Depth of nested complex properties within a VisualTree. This is used to // track when it is valid to have a clr property vs a dependency property // specified in the VisualTree; int _visualTreeComplexPropertyDepth = -1; // Depth of nested complex properties within the Triggers section. This is used to // track when it is valid to have text. int _triggerComplexPropertyDepth = -1; #if PBTCOMPILER // True if x:Key property was found on the template tag bool _defNameFound; // During second pass, remember the info for the DataType property, so // that we can write out a key if no x:Key is present XamlPropertyWithTypeNode _dataTypePropertyNode; int _dataTypePropertyNodeDepth; // True if event is in the same VisualTree FEF. bool _isSameScope; // Type to use for the implicit key in the dictionary Type _templateKeyType; #endif // Stack to keep track of element types during compile. Stack _elementTypeStack = new Stack(5); // Dictionary of names, where the key is the name string and the value // is the element type that is using that name. Hashtable _IDTypes = new Hashtable(); // The value of that identifies the target // of the set operation or the value of // that identifies the source of a trigger condition. string _setterTargetNameOrConditionSourceName; // MemberInfo fo the DP Property value for the case where a Value is read as ComplexAsSimple. MemberInfo _setterOrTriggerPropertyMemberInfo; #endregion Data } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. /****************************************************************************\ * * File: TemplateXamlParser.cs * * Purpose: Class that interfaces with TokenReader and BamlWriter for * parsing Template * * History: * 11/22/04: [....] Created * * Copyright (C) 2004 by Microsoft Corporation. All rights reserved. * \***************************************************************************/ using System; using System.Xml; using System.IO; using System.Text; using System.Collections; using System.ComponentModel; using System.Diagnostics; using System.Reflection; using MS.Utility; #if PBTCOMPILER namespace MS.Internal.Markup #else using System.Windows; using System.Windows.Threading; namespace System.Windows.Markup #endif { /// /// Handles overrides for case when Template is being built to a tree /// instead of compiling to a file. /// internal class TemplateXamlParser : XamlParser { #region Constructors #if !PBTCOMPILER ////// Constructor. /// ////// Note that we are re-using the token reader, so we'll swap out the XamlParser that /// the token reader uses with ourself. Then restore it when we're done parsing. /// internal TemplateXamlParser( XamlTreeBuilder treeBuilder, XamlReaderHelper tokenReader, ParserContext parserContext) : this(tokenReader, parserContext) { _treeBuilder = treeBuilder; } #endif ////// Constructor. /// ////// Note that we are re-using the token reader, so we'll swap out the XamlParser that /// the token reader uses with ourself. Then restore it when we're done parsing. /// internal TemplateXamlParser( XamlReaderHelper tokenReader, ParserContext parserContext) { TokenReader = tokenReader; ParserContext = parserContext; _previousXamlParser = TokenReader.ControllingXamlParser; TokenReader.ControllingXamlParser = this; _startingDepth = TokenReader.XmlReader.Depth; } #endregion Constructors #region Overrides ////// Override of the main switch statement that processes the xaml nodes. /// ////// We need to control when cleanup is done and when the calling parse loop /// is exited, so do this here. /// internal override void ProcessXamlNode( XamlNode xamlNode, ref bool cleanup, ref bool done) { switch(xamlNode.TokenType) { // Ignore some types of xaml nodes, since they are not // relevent to template parsing. case XamlNodeType.DocumentStart: case XamlNodeType.DocumentEnd: break; case XamlNodeType.ElementEnd: base.ProcessXamlNode(xamlNode, ref cleanup, ref done); // If we're at the depth that we started out, then we must be done. In that case quit // and restore the XamlParser that the token reader was using before parsing templates. if (_styleModeStack.Depth == 0) { done = true; // Stop the template parse cleanup = false; // Don't close the stream TokenReader.ControllingXamlParser = _previousXamlParser; } break; case XamlNodeType.PropertyArrayStart: case XamlNodeType.PropertyArrayEnd: case XamlNodeType.DefTag: ThrowException(SRID.TemplateTagNotSupported, xamlNode.TokenType.ToString(), xamlNode.LineNumber, xamlNode.LinePosition); break; #if PBTCOMPILER case XamlNodeType.EndAttributes: // if there's a DataType present but no x:Key, write out // the key now based on the DataType if (_dataTypePropertyNode != null && _dataTypePropertyNodeDepth == _styleModeStack.Depth) { if (!_defNameFound) { WriteDataTypeKey(_dataTypePropertyNode); } _dataTypePropertyNode = null; _dataTypePropertyNodeDepth = -1; } base.ProcessXamlNode(xamlNode, ref cleanup, ref done); break; #endif // Most nodes are handled by the base XamlParser by creating a // normal BamlRecord. default: base.ProcessXamlNode(xamlNode, ref cleanup, ref done); break; } } ////// Write start of an unknown tag /// ////// For template parsing, the 'Set' tag is an unknown tag, but this will map to a /// Trigger set command. Store this as an element start record here. /// Also 'Set.Value' will map to the a complex Value set portion of the Set command. /// public override void WriteUnknownTagStart(XamlUnknownTagStartNode xamlUnknownTagStartNode) { StyleMode mode = _styleModeStack.Mode; // Keep mode and other state up-to-date. This // must be called before updating stack. CommonElementStartProcessing(xamlUnknownTagStartNode, null, ref mode); _styleModeStack.Push(mode); #if PBTCOMPILER string localElementFullName = string.Empty; int lastIndex = xamlUnknownTagStartNode.Value.LastIndexOf('.'); // if local complex property bail out now and handle in 2nd pass when TypInfo is available if (-1 == lastIndex) { NamespaceMapEntry[] namespaceMaps = XamlTypeMapper.GetNamespaceMapEntries(xamlUnknownTagStartNode.XmlNamespace); if (namespaceMaps != null && namespaceMaps.Length == 1 && namespaceMaps[0].LocalAssembly) { localElementFullName = namespaceMaps[0].ClrNamespace + "." + xamlUnknownTagStartNode.Value; } } else if (IsLocalPass1) { return; } if (localElementFullName.Length == 0 || !IsLocalPass1) { #endif // It can be a fairly common error for, //, , or // to be specified at the wrong nesting level (See Windows bug 966137). Detect // these cases to give more meaningful error messages. if (xamlUnknownTagStartNode.Value == XamlTemplateSerializer.ControlTemplateTriggersFullPropertyName || xamlUnknownTagStartNode.Value == XamlTemplateSerializer.DataTemplateTriggersFullPropertyName || xamlUnknownTagStartNode.Value == XamlTemplateSerializer.HierarchicalDataTemplateTriggersFullPropertyName || xamlUnknownTagStartNode.Value == XamlTemplateSerializer.HierarchicalDataTemplateItemsSourceFullPropertyName || xamlUnknownTagStartNode.Value == XamlTemplateSerializer.HierarchicalDataTemplateItemTemplateFullPropertyName || xamlUnknownTagStartNode.Value == XamlTemplateSerializer.HierarchicalDataTemplateItemTemplateSelectorFullPropertyName || xamlUnknownTagStartNode.Value == XamlTemplateSerializer.HierarchicalDataTemplateItemContainerStyleFullPropertyName || xamlUnknownTagStartNode.Value == XamlTemplateSerializer.HierarchicalDataTemplateItemContainerStyleSelectorFullPropertyName || xamlUnknownTagStartNode.Value == XamlTemplateSerializer.HierarchicalDataTemplateItemStringFormatFullPropertyName || xamlUnknownTagStartNode.Value == XamlTemplateSerializer.HierarchicalDataTemplateItemBindingGroupFullPropertyName || xamlUnknownTagStartNode.Value == XamlTemplateSerializer.HierarchicalDataTemplateAlternationCountFullPropertyName ) { ThrowException(SRID.TemplateKnownTagWrongLocation, xamlUnknownTagStartNode.Value, xamlUnknownTagStartNode.LineNumber, xamlUnknownTagStartNode.LinePosition); } else { base.WriteUnknownTagStart(xamlUnknownTagStartNode); } #if PBTCOMPILER } #endif } /// /// Write Start element for a dictionary key section. /// public override void WriteKeyElementStart( XamlElementStartNode xamlKeyElementStartNode) { _styleModeStack.Push(StyleMode.Key); base.WriteKeyElementStart(xamlKeyElementStartNode); } ////// Write End element for a dictionary key section /// public override void WriteKeyElementEnd( XamlElementEndNode xamlKeyElementEndNode) { _styleModeStack.Pop(); base.WriteKeyElementEnd(xamlKeyElementEndNode); } ////// Write end of an unknown tag /// ////// For template parsing, the 'Set' tag is an unknown tag, but this will map to a /// Trigger set command. Store this as an element end record here. /// public override void WriteUnknownTagEnd(XamlUnknownTagEndNode xamlUnknownTagEndNode) { if (_inSetterDepth == xamlUnknownTagEndNode.Depth) { XamlElementEndNode elementEnd = new XamlElementEndNode( xamlUnknownTagEndNode.LineNumber, xamlUnknownTagEndNode.LinePosition, xamlUnknownTagEndNode.Depth); base.WriteElementEnd(elementEnd); _inSetterDepth = -1; } else { #if PBTCOMPILER NamespaceMapEntry[] namespaceMaps = XamlTypeMapper.GetNamespaceMapEntries(xamlUnknownTagEndNode.XmlNamespace); bool localTag = namespaceMaps != null && namespaceMaps.Length == 1 && namespaceMaps[0].LocalAssembly; if (!localTag || !IsLocalPass1) { #endif base.WriteUnknownTagEnd(xamlUnknownTagEndNode); #if PBTCOMPILER } #endif } _styleModeStack.Pop(); } ////// Write unknown attribute /// ////// For template parsing, the 'Set' tag is an unknown tag and contains properties that /// are passed as UnknownAttributes. Translate these into Property records. /// public override void WriteUnknownAttribute(XamlUnknownAttributeNode xamlUnknownAttributeNode) { #if PBTCOMPILER bool localAttrib = false; string localTagFullName = string.Empty; string localAttribName = xamlUnknownAttributeNode.Name; NamespaceMapEntry[] namespaceMaps = null; if (xamlUnknownAttributeNode.OwnerTypeFullName.Length > 0) { // These are attributes on a local tag ... localTagFullName = xamlUnknownAttributeNode.OwnerTypeFullName; localAttrib = true; } else { // These are attributes on a non-local tag ... namespaceMaps = XamlTypeMapper.GetNamespaceMapEntries(xamlUnknownAttributeNode.XmlNamespace); localAttrib = namespaceMaps != null && namespaceMaps.Length == 1 && namespaceMaps[0].LocalAssembly; } if (localAttrib) { // ... and if there are any periods in the attribute name, then ... int lastIndex = localAttribName.LastIndexOf('.'); if (-1 != lastIndex) { // ... these might be attached props or events defined by a locally defined component, // but being set on this non-local tag. string ownerTagName = localAttribName.Substring(0, lastIndex); if (namespaceMaps != null) { if (namespaceMaps.Length == 1 && namespaceMaps[0].LocalAssembly) { localTagFullName = namespaceMaps[0].ClrNamespace + "." + ownerTagName; } } else { TypeAndSerializer typeAndSerializer = XamlTypeMapper.GetTypeOnly(xamlUnknownAttributeNode.XmlNamespace, ownerTagName); if (typeAndSerializer != null) { Type ownerTagType = typeAndSerializer.ObjectType; localTagFullName = ownerTagType.FullName; } else { namespaceMaps = XamlTypeMapper.GetNamespaceMapEntries(xamlUnknownAttributeNode.XmlNamespace); if (namespaceMaps != null && namespaceMaps.Length == 1 && namespaceMaps[0].LocalAssembly) { localTagFullName = namespaceMaps[0].ClrNamespace + "." + ownerTagName; } else { localTagFullName = string.Empty; } } } localAttribName = localAttribName.Substring(lastIndex + 1); } } if (localTagFullName.Length == 0 || !IsLocalPass1) { #endif base.WriteUnknownAttribute(xamlUnknownAttributeNode); #if PBTCOMPILER } #endif } ////// WriteEndAttributes occurs after the last attribute (property, complex property or /// def record) is written. Note that if there are none of the above, then WriteEndAttributes /// is not called for a normal start tag. /// public override void WriteEndAttributes(XamlEndAttributesNode xamlEndAttributesNode) { #if PBTCOMPILER // reset the event scope so that a new tag may start a new scope for its own events if (_styleModeStack.Mode == StyleMode.VisualTree && !xamlEndAttributesNode.IsCompact) { _isSameScope = false; } #endif if (_styleModeStack.Mode == StyleMode.TriggerBase && !xamlEndAttributesNode.IsCompact) { MemberInfo dpInfo = null; if (_setterOrTriggerPropertyNode != null) { dpInfo = GetDependencyPropertyInfo(_setterOrTriggerPropertyNode); base.WriteProperty(_setterOrTriggerPropertyNode); _setterOrTriggerPropertyNode = null; _setterOrTriggerPropertyMemberInfo = dpInfo; } _setterTargetNameOrConditionSourceName = null; if (_setterOrTriggerValueNode != null) { ProcessPropertyValueNode(); } } base.WriteEndAttributes(xamlEndAttributesNode); } private MemberInfo GetDependencyPropertyInfo(XamlPropertyNode xamlPropertyNode) { string member = xamlPropertyNode.Value; MemberInfo dpInfo = GetCLRPropertyInfo(xamlPropertyNode, ref member); if (dpInfo != null) { // Note: Should we enforce that all DP fields should end with a // "Property" or "PropertyKey" postfix here? if (BamlRecordWriter != null) { short typeId; short propertyId = MapTable.GetAttributeOrTypeId(BamlRecordWriter.BinaryWriter, dpInfo.DeclaringType, member, out typeId); if (propertyId < 0) { xamlPropertyNode.ValueId = propertyId; xamlPropertyNode.MemberName = null; } else { xamlPropertyNode.ValueId = typeId; xamlPropertyNode.MemberName = member; } } } return dpInfo; } private MemberInfo GetCLRPropertyInfo(XamlPropertyNode xamlPropertyNode, ref string member) { // Strip off namespace prefix from the event or property name and // map this to an xmlnamespace. Also extract the class name, if present string prefix = string.Empty; string target = member; string propertyName = member; int dotIndex = member.LastIndexOf('.'); if (-1 != dotIndex) { target = propertyName.Substring(0, dotIndex); member = propertyName.Substring(dotIndex+1); } int colonIndex = target.IndexOf(':'); if (-1 != colonIndex) { // If using .net then match against the class. prefix = target.Substring(0, colonIndex); if (-1 == dotIndex) { member = target.Substring(colonIndex+1); } } string xmlNamespace = TokenReader.XmlReader.LookupNamespace(prefix); Type targetType = null; // Get the type associated with the property or event from the XamlTypeMapper and // use this to resolve the property or event into an EventInfo, PropertyInfo // or MethodInfo if (-1 != dotIndex) { targetType = XamlTypeMapper.GetTypeFromBaseString(target, ParserContext, false); } else if (_setterTargetNameOrConditionSourceName != null) { targetType = _IDTypes[_setterTargetNameOrConditionSourceName] as Type; if (targetType == null #if PBTCOMPILER && !IsLocalPass1 #endif ) { ThrowException(SRID.TemplateNoTriggerTarget, _setterTargetNameOrConditionSourceName, xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition); } } else { targetType = TargetType; } MemberInfo memberInfo = null; if (targetType != null) { string objectName = propertyName; memberInfo = XamlTypeMapper.GetClrInfo( false, targetType, xmlNamespace, member, ref objectName) as MemberInfo; } if (memberInfo != null) { PropertyInfo pi = memberInfo as PropertyInfo; if (pi != null) { // For trigger condition only allow if public or internal getter if (_inSetterDepth < 0 && _styleModeStack.Mode == StyleMode.TriggerBase) { if (!XamlTypeMapper.IsAllowedPropertyGet(pi)) { ThrowException(SRID.ParserCantSetTriggerCondition, pi.Name, xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition); } } else // for general Setters check prop setters { if (!XamlTypeMapper.IsAllowedPropertySet(pi)) { ThrowException(SRID.ParserCantSetAttribute, "Property Setter", pi.Name, "set", xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition); } } } } // local properties will be added to the baml in pass2 of the compilation. // so don't throw now. else #if PBTCOMPILER if (!IsLocalPass1) #endif { if (targetType != null) { ThrowException(SRID.TemplateNoProp, member, targetType.FullName, xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition); } else { ThrowException(SRID.TemplateNoTarget, member, xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition); } } return memberInfo; } ////// The Value="foo" property node for a Setter and a Trigger has been saved /// and is resolved some time afterwards using the associated Property="Bar" /// attribute. This is done so that the property record can be written using /// the type converter associated with "Bar" /// private void ProcessPropertyValueNode() { Debug.Assert(_setterOrTriggerValueNode != null); if (_setterOrTriggerPropertyMemberInfo != null) { // Now we have PropertyInfo or a MethodInfo for the property setter. // Get the type of the property from this which will be used // by BamlRecordWriter.WriteProperty to find an associated // TypeConverter to use at runtime. // To allow for per-property type converters we need to extract // information from the member info about the property Type propertyType = XamlTypeMapper.GetPropertyType(_setterOrTriggerPropertyMemberInfo); _setterOrTriggerValueNode.ValuePropertyType = propertyType; _setterOrTriggerValueNode.ValuePropertyMember = _setterOrTriggerPropertyMemberInfo; _setterOrTriggerValueNode.ValuePropertyName = XamlTypeMapper.GetPropertyName(_setterOrTriggerPropertyMemberInfo); _setterOrTriggerValueNode.ValueDeclaringType = _setterOrTriggerPropertyMemberInfo.DeclaringType; base.WriteProperty(_setterOrTriggerValueNode); } else { base.WriteBaseProperty(_setterOrTriggerValueNode); } _setterOrTriggerValueNode = null; _setterOrTriggerPropertyNode = null; _setterTargetNameOrConditionSourceName = null; _setterOrTriggerPropertyMemberInfo = null; } ////// Write Def Attribute /// ////// Template parsing supports x:ID, so check for this here /// public override void WriteDefAttribute(XamlDefAttributeNode xamlDefAttributeNode) { if (xamlDefAttributeNode.Name == BamlMapTable.NameString) { if (BamlRecordWriter != null) { BamlRecordWriter.WriteDefAttribute(xamlDefAttributeNode); } } else { #if PBTCOMPILER // Remember that x:Key was read in, since this key has precedence over // the DataType="{x:Type SomeType}" key that may also be present. if (xamlDefAttributeNode.Name == XamlReaderHelper.DefinitionName && _styleModeStack.Mode == StyleMode.Base) { _defNameFound = true; } #endif base.WriteDefAttribute(xamlDefAttributeNode); } } #if PBTCOMPILER ////// Write out a key to a dictionary that has been resolved at compile or parse /// time to a Type object. /// public override void WriteDefAttributeKeyType(XamlDefAttributeKeyTypeNode xamlDefNode) { // Remember that x:Key was read in, since this key has precedence over // the TargetType="{x:Type SomeType}" key that may also be present. if (_styleModeStack.Mode == StyleMode.Base) { _defNameFound = true; } base.WriteDefAttributeKeyType(xamlDefNode); } #endif ////// Write Start of an Element, which is a tag of the form / ////// /// For template parsing, determine when it is withing a Trigger or /// MultiTrigger section. This is done for validity checking of /// unknown tags and attributes. /// 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 thesection 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 // , 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. // // 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); } } } // // CommonElementStartProcessing // // This is used by WriteElementStart and WriteUnknownTagStart. It is used // to keep style mode up-to-date. // private void CommonElementStartProcessing (XamlNode xamlNode, Type elementType, ref StyleMode mode) { if (mode == StyleMode.Base && _styleModeStack.Depth > 0 ) { if (_templateRootCount++ > 0) { ThrowException(SRID.TemplateNoMultipleRoots, (elementType == null ? "Unknown tag" : elementType.Name), xamlNode.LineNumber, xamlNode.LinePosition); } // Validate that the root is an FE or FCE. If the type is unknown (and internal type), we'll // catch this during template instantiation. if (elementType != null && !KnownTypes.Types[(int)KnownElements.FrameworkElement].IsAssignableFrom(elementType) && !KnownTypes.Types[(int)KnownElements.FrameworkContentElement].IsAssignableFrom(elementType)) { ThrowException(SRID.TemplateInvalidRootElementTag, elementType.ToString(), xamlNode.LineNumber, xamlNode.LinePosition); } mode = StyleMode.VisualTree; } } ///// //// //// //// //// //// // ///// Write End Element /// ////// For template parsing, determine when it is withing a Trigger or /// MultiTrigger section. This is done for validity checking of /// unknown tags and attributes. /// public override void WriteElementEnd(XamlElementEndNode xamlElementEndNode) { bool tagWritten = false; if (_styleModeStack.Mode == StyleMode.TriggerBase && xamlElementEndNode.Depth == _inSetterDepth) { // Just exited thesection of a Trigger _inSetterDepth = -1; } if (xamlElementEndNode.Depth == _inPropertyTriggerDepth) { _inPropertyTriggerDepth = -1; } #if PBTCOMPILER if (_styleModeStack.Mode == StyleMode.DataTypeProperty && InDeferLoadedSection && !_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 in addition to generating the records to set // the TargetType value. if (_styleModeStack.Depth == 2) { base.WriteElementEnd(xamlElementEndNode); base.WriteConstructorParametersEnd(new XamlConstructorParametersEndNode( xamlElementEndNode.LineNumber, xamlElementEndNode.LinePosition, xamlElementEndNode.Depth)); base.WriteKeyElementEnd(xamlElementEndNode); tagWritten = true; } } #endif // Track elements during compile so that we can resolve names to types. This // is useful when resolving Setter Property / Value. _elementTypeStack.Pop(); _styleModeStack.Pop(); if (!tagWritten) { base.WriteElementEnd(xamlElementEndNode); } } private Type TargetType { get { return (_templateTargetTypeType != null ? _templateTargetTypeType #if PBTCOMPILER : IsLocalPass1 ? null #endif : _defaultTargetType); } } #if PBTCOMPILER /// /// Write the start of a constructor parameter section /// public override void WriteConstructorParameterType( XamlConstructorParameterTypeNode xamlConstructorParameterTypeNode) { if (_styleModeStack.Mode == StyleMode.DataTypeProperty && InDeferLoadedSection && !_defNameFound) { // Generate a series of baml records to use as the key for the defer loaded // body of the Style in addition to generating the records to set // the normal constructor. base.WriteConstructorParameterType(xamlConstructorParameterTypeNode); } base.WriteConstructorParameterType(xamlConstructorParameterTypeNode); } #endif ////// Write the start of a constructor parameter section /// public override void WriteConstructorParametersStart(XamlConstructorParametersStartNode xamlConstructorParametersStartNode) { #if PBTCOMPILER if (_styleModeStack.Mode == StyleMode.DataTypeProperty && InDeferLoadedSection && !_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 in addition to generating the records to set // the TargetType value. base.WriteConstructorParametersStart(xamlConstructorParametersStartNode); } #endif _styleModeStack.Push(); base.WriteConstructorParametersStart(xamlConstructorParametersStartNode); } ////// Write the end of a constructor parameter section /// public override void WriteConstructorParametersEnd(XamlConstructorParametersEndNode xamlConstructorParametersEndNode) { #if PBTCOMPILER if (_styleModeStack.Mode == StyleMode.DataTypeProperty && InDeferLoadedSection && !_defNameFound && _styleModeStack.Depth > 2) { // 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 in addition to generating the records to set // the TargetType value. base.WriteConstructorParametersEnd(xamlConstructorParametersEndNode); } #endif base.WriteConstructorParametersEnd(xamlConstructorParametersEndNode); _styleModeStack.Pop(); } ////// Write start of a complex property /// ////// For template parsing, treat complex property tags as /// xml element tags for the purpose of validity checking /// public override void WritePropertyComplexStart(XamlPropertyComplexStartNode xamlNode) { StyleMode mode = _styleModeStack.Mode; if (_styleModeStack.Depth == 1) { if (xamlNode.PropName == XamlTemplateSerializer.TargetTypePropertyName) { mode = StyleMode.TargetTypeProperty; } else if (xamlNode.PropName == XamlTemplateSerializer.DataTypePropertyName) { mode = StyleMode.DataTypeProperty; } else if (xamlNode.PropName == XamlTemplateSerializer.ItemsSourcePropertyName || xamlNode.PropName == XamlTemplateSerializer.ItemTemplatePropertyName || xamlNode.PropName == XamlTemplateSerializer.ItemTemplateSelectorPropertyName || xamlNode.PropName == XamlTemplateSerializer.ItemContainerStylePropertyName || xamlNode.PropName == XamlTemplateSerializer.ItemContainerStyleSelectorPropertyName || xamlNode.PropName == XamlTemplateSerializer.ItemStringFormatPropertyName || xamlNode.PropName == XamlTemplateSerializer.ItemBindingGroupPropertyName || xamlNode.PropName == XamlTemplateSerializer.AlternationCountPropertyName ) { mode = StyleMode.ComplexProperty; } else { ThrowException(SRID.TemplateUnknownProp, xamlNode.PropName, xamlNode.LineNumber, xamlNode.LinePosition); } } else if (mode == StyleMode.VisualTree) { _visualTreeComplexPropertyDepth++; } else if (mode == StyleMode.TriggerBase) { _triggerComplexPropertyDepth++; } #if PBTCOMPILER else if (mode == StyleMode.DataTypeProperty && InDeferLoadedSection && !_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 in addition to generating the records to set // the TargetType value. base.WritePropertyComplexStart(xamlNode); } #endif _styleModeStack.Push(mode); base.WritePropertyComplexStart(xamlNode); } ////// Write end of a complex property /// ////// For template parsing, treat complex property tags as /// xml element tags for the purpose of validity checking /// public override void WritePropertyComplexEnd(XamlPropertyComplexEndNode xamlNode) { StyleMode mode = _styleModeStack.Mode; if (mode == StyleMode.VisualTree) { _visualTreeComplexPropertyDepth--; } if (mode == StyleMode.TriggerBase) { _triggerComplexPropertyDepth--; } #if PBTCOMPILER else if (mode == StyleMode.DataTypeProperty && InDeferLoadedSection && !_defNameFound && _styleModeStack.Depth > 2) { // 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 in addition to generating the records to set // the TargetType value. base.WritePropertyComplexEnd(xamlNode); } #endif if (_styleModeStack.Depth <= 2) { mode = StyleMode.Base; } _styleModeStack.Pop(); base.WritePropertyComplexEnd(xamlNode); } ////// Write start of a list complex property /// ////// For template parsing, treat complex property tags as /// xml element tags for the purpose of validity checking /// public override void WritePropertyIListStart(XamlPropertyIListStartNode xamlNode) { StyleMode mode = _styleModeStack.Mode; if (_styleModeStack.Depth == 1) { if (xamlNode.PropName == XamlTemplateSerializer.TriggersPropertyName) { mode = StyleMode.TriggerBase; } else { ThrowException(SRID.TemplateUnknownProp, xamlNode.PropName, xamlNode.LineNumber, xamlNode.LinePosition); } } else if (mode == StyleMode.VisualTree) { _visualTreeComplexPropertyDepth++; } else if (mode == StyleMode.TriggerBase && _styleModeStack.Depth == 2) { mode = StyleMode.Base; } else if (mode == StyleMode.TriggerBase && _styleModeStack.Depth == 3 && xamlNode.PropName == XamlTemplateSerializer.EventTriggerActions) { mode = StyleMode.TriggerActions; } else if (mode == StyleMode.TriggerBase) { _triggerComplexPropertyDepth++; } _styleModeStack.Push(mode); base.WritePropertyIListStart(xamlNode); } ////// Write end of a list complex property /// ////// For template parsing, treat complex property tags as /// xml element tags for the purpose of validity checking when we're counting /// element tags. /// public override void WritePropertyIListEnd(XamlPropertyIListEndNode xamlNode) { if (_styleModeStack.Mode == StyleMode.VisualTree) { _visualTreeComplexPropertyDepth--; } else if (_styleModeStack.Mode == StyleMode.TriggerBase) { _triggerComplexPropertyDepth--; } base.WritePropertyIListEnd(xamlNode); _styleModeStack.Pop(); } ////// Write Property Array Start /// public override void WritePropertyArrayStart(XamlPropertyArrayStartNode xamlPropertyArrayStartNode) { if (_styleModeStack.Mode == StyleMode.VisualTree) { _visualTreeComplexPropertyDepth++; } else if (_styleModeStack.Mode == StyleMode.TriggerBase) { _triggerComplexPropertyDepth++; } base.WritePropertyArrayStart(xamlPropertyArrayStartNode); _styleModeStack.Push(); } ////// Write Property Array End /// public override void WritePropertyArrayEnd(XamlPropertyArrayEndNode xamlPropertyArrayEndNode) { if (_styleModeStack.Mode == StyleMode.VisualTree) { _visualTreeComplexPropertyDepth--; } else if (_styleModeStack.Mode == StyleMode.TriggerBase) { _triggerComplexPropertyDepth--; } base.WritePropertyArrayEnd(xamlPropertyArrayEndNode); _styleModeStack.Pop(); } ////// Write Property IDictionary Start /// public override void WritePropertyIDictionaryStart(XamlPropertyIDictionaryStartNode xamlPropertyIDictionaryStartNode) { StyleMode mode = _styleModeStack.Mode; if (mode == StyleMode.VisualTree) { _visualTreeComplexPropertyDepth++; } else if (mode == StyleMode.TriggerBase) { _triggerComplexPropertyDepth++; } else if (_styleModeStack.Depth == 1 && mode == StyleMode.Base) { if( xamlPropertyIDictionaryStartNode.PropName == XamlTemplateSerializer.ResourcesPropertyName) { mode = StyleMode.Resources; } else { ThrowException(SRID.TemplateUnknownProp, xamlPropertyIDictionaryStartNode.PropName, xamlPropertyIDictionaryStartNode.LineNumber, xamlPropertyIDictionaryStartNode.LinePosition); } } base.WritePropertyIDictionaryStart(xamlPropertyIDictionaryStartNode); _styleModeStack.Push(mode); } ////// Write Property IDictionary End /// public override void WritePropertyIDictionaryEnd(XamlPropertyIDictionaryEndNode xamlPropertyIDictionaryEndNode) { StyleMode mode = _styleModeStack.Mode; if (mode == StyleMode.VisualTree) { _visualTreeComplexPropertyDepth--; } else if (mode == StyleMode.TriggerBase) { _triggerComplexPropertyDepth--; } base.WritePropertyIDictionaryEnd(xamlPropertyIDictionaryEndNode); _styleModeStack.Pop(); } ////// Write Text node and do template related error checking /// public override void WriteText(XamlTextNode xamlTextNode) { StyleMode mode = _styleModeStack.Mode; // Text is only valid within certain locations in the Template section. // Check for all the valid locations and write out the text record. For // all other locations, see if the text is non-blank and throw an error // if it is. Ignore any whitespace, since this is not considered // significant in Style cases. if (mode == StyleMode.TargetTypeProperty) { // Remember the TargetType so that the setter parsing could use it // to resolve non-qualified property names if (xamlTextNode.Text != null) { _templateTargetTypeType = XamlTypeMapper.GetTypeFromBaseString(xamlTextNode.Text, ParserContext, true); } } #if PBTCOMPILER if (mode == StyleMode.DataTypeProperty && InDeferLoadedSection && !_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 in addition to generating the records to set // the TargetType value. base.WriteText(xamlTextNode); } #endif // Text is only valid within certain locations in the section. // Check for all the valid locations and write out the text record. For // all other locations, see if the text is non-blank and throw an error // if it is. Ignore any whitespace, since this is not considered // significant in Template cases. if (mode != StyleMode.TriggerBase || _inSetterDepth >= 0 || _triggerComplexPropertyDepth >= 0) { base.WriteText(xamlTextNode); } else { for (int i = 0; i< xamlTextNode.Text.Length; i++) { if (!XamlReaderHelper.IsWhiteSpace(xamlTextNode.Text[i])) { ThrowException(SRID.TemplateTextNotSupported, xamlTextNode.Text, xamlTextNode.LineNumber, xamlTextNode.LinePosition); } } } } #if PBTCOMPILER ////// Write an Event Connector and call the controlling compiler parser to generate event hookup code. /// public override void WriteClrEvent(XamlClrEventNode xamlClrEventNode) { if (_previousXamlParser != null) { Debug.Assert(_styleModeStack.Mode == StyleMode.VisualTree); // if this event token is not owned by this TemplateXamlParser, then just chain // the WriteClrEvent call to the controlling parser. Ulimately, this will // reach the markup compiler that will deal with this info as appropriate. bool isOriginatingEvent = xamlClrEventNode.IsOriginatingEvent; if (isOriginatingEvent) { // set up additional state on event node for the markup compiler to use. Debug.Assert(!xamlClrEventNode.IsStyleSetterEvent); xamlClrEventNode.IsTemplateEvent = true; xamlClrEventNode.IsSameScope = _isSameScope; // any intermediary controlling parsers need to get out of the way so that // the markup compiler can ultimately do its thing. xamlClrEventNode.IsOriginatingEvent = false; // Store away the type of the element we're currently in. E.g. // in , this will be typeof(Button). // In the case of regular CLR events, this type is the same as that // which can be found in xamlClrEventNode.EventMember. But in the // case of attached events, EventMember is the class that holds // the attached event, and the compiler needs to know the type of // the listener. xamlClrEventNode.ListenerType = (Type) _elementTypeStack.Peek(); } _previousXamlParser.WriteClrEvent(xamlClrEventNode); if (isOriginatingEvent) { if (!String.IsNullOrEmpty(xamlClrEventNode.LocalAssemblyName)) { // if this event is a local event need to generate baml for it now XamlPropertyNode xamlPropertyNode = new XamlPropertyNode(xamlClrEventNode.LineNumber, xamlClrEventNode.LinePosition, xamlClrEventNode.Depth, null, xamlClrEventNode.LocalAssemblyName, xamlClrEventNode.EventMember.ReflectedType.FullName, xamlClrEventNode.EventName, xamlClrEventNode.Value, BamlAttributeUsage.Default, false); base.WriteProperty(xamlPropertyNode); } else { // write out a connectionId to the baml stream only if a // new event scope was encountered if (!_isSameScope) { base.WriteConnectionId(xamlClrEventNode.ConnectionId); } // We have just finished processing the start of a new event scope. // So specifiy start of this new scope. _isSameScope = true; } } } } #endif ////// Write a Property, which has the form in markup of property="value". /// ////// When in a VisualTree, only DependencyProperties can be set directly on /// a FrameworkElementFactory. This method checks the state of parsing and /// with throw an exception if a clr property is set on a FrameworkElementFactory. /// public override void WriteProperty(XamlPropertyNode xamlPropertyNode) { StyleMode mode = _styleModeStack.Mode; if (mode == StyleMode.TriggerBase && WritePropertyForTriggers(xamlPropertyNode)) { return; } // If we are on the DataTemplate tag itself, and we encounter a DataType property, // this can be used as the key when placing this template in a ResourceDictionary. // In that case, remember what the property value is so that we can // later update the defer key held by the baml writer. if (mode == StyleMode.Base && xamlPropertyNode.PropName == XamlTemplateSerializer.DataTypePropertyName) { #if PBTCOMPILER // Treat DataType="some string" as a key in a resource dictionary. // Generate a sequence of baml records to describe the key. if (InDeferLoadedSection && !_defNameFound) { base.WriteKeyElementStart(new XamlElementStartNode( xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition, xamlPropertyNode.Depth, _templateKeyType.Assembly.FullName, _templateKeyType.FullName, _templateKeyType, null)); base.WriteConstructorParametersStart(new XamlConstructorParametersStartNode( xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition, xamlPropertyNode.Depth)); base.WriteText(new XamlTextNode( xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition, xamlPropertyNode.Depth, xamlPropertyNode.Value, null)); base.WriteConstructorParametersEnd(new XamlConstructorParametersEndNode( xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition, xamlPropertyNode.Depth)); base.WriteKeyElementEnd(new XamlElementEndNode( xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition, xamlPropertyNode.Depth)); } #endif } #if PBTCOMPILER else if (mode == StyleMode.DataTypeProperty && InDeferLoadedSection && !_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. base.WriteProperty(xamlPropertyNode); } #endif xamlPropertyNode.DefaultTargetType = TargetType; base.WriteProperty(xamlPropertyNode); // If the property being written identifies a Runtime name, then remember // the name and the type associated with it. This may be needed for // Setter value and property resolutions later on. if (xamlPropertyNode.AttributeUsage == BamlAttributeUsage.RuntimeName) { if (_IDTypes.ContainsKey(xamlPropertyNode.Value)) { ThrowException(SRID.TemplateDupName, xamlPropertyNode.Value, xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition); } else { _IDTypes[xamlPropertyNode.Value] = _elementTypeStack.Peek() as Type; } } } ////// Handle property node when within a Triggers section. Return true if this /// node is fully handled and needs no further processing. /// private bool WritePropertyForTriggers(XamlPropertyNode xamlPropertyNode) { if (_inSetterDepth >= 0) { if (xamlPropertyNode.PropName == XamlTemplateSerializer.SetterValueAttributeName) { _setterOrTriggerValueNode = xamlPropertyNode; // Delay writing out the Value attribute until WriteEndAttributes if this is a // normal property node. If this is a property node that was created from complex // syntax, then the WriteEndAttributes has already occurred, so process the // node now. if (xamlPropertyNode.ComplexAsSimple) { ProcessPropertyValueNode(); } return true; } else if (xamlPropertyNode.PropName == XamlTemplateSerializer.SetterPropertyAttributeName) { // Property names should be trimmed since whitespace is not significant // and can affect name resolution (See Windows bug 1035621) xamlPropertyNode.SetValue(xamlPropertyNode.Value.Trim()); _setterOrTriggerPropertyNode = xamlPropertyNode; // return now as Setter.TargetName might not have been set yet and we need that for resolving // the property name. So this is done in WriteEndattributes. return true; } else if (xamlPropertyNode.PropName == XamlTemplateSerializer.SetterTargetAttributeName) { _setterTargetNameOrConditionSourceName = xamlPropertyNode.Value; } } else { if (xamlPropertyNode.PropName == XamlTemplateSerializer.PropertyTriggerValuePropertyName) { // DataTrigger doesn't have a "Property" property so value has to be written directly. // This check filters out if "Property" was actually set vs. not present at all for // other Triggers. Type t = (Type)_elementTypeStack.Peek(); if (!KnownTypes.Types[(int)KnownElements.DataTrigger].IsAssignableFrom(t)) { _setterOrTriggerValueNode = xamlPropertyNode; // Delay writing out the Value attribute until WriteEndAttributes if this is a // normal property node. If this is a property node that was created from complex // syntax, then the WriteEndAttributes has already occurred, so process the // node now. if (xamlPropertyNode.ComplexAsSimple) { ProcessPropertyValueNode(); } return true; } } else if (xamlPropertyNode.PropName == XamlTemplateSerializer.PropertyTriggerPropertyName) { // Property names should be trimmed since whitespace is not significant // and can affect name resolution (See Windows bug 1035621) xamlPropertyNode.SetValue(xamlPropertyNode.Value.Trim()); _setterOrTriggerPropertyNode = xamlPropertyNode; // return now as Trigger.SourceName might not have been set yet and we need that for resolving // the property name. So this is done in WriteEndattributes. return true; } else if (xamlPropertyNode.PropName == XamlTemplateSerializer.PropertyTriggerSourceName) { _setterTargetNameOrConditionSourceName = xamlPropertyNode.Value; } } return false; } public override void WritePropertyWithExtension(XamlPropertyWithExtensionNode xamlPropertyWithExtensionNode) { xamlPropertyWithExtensionNode.DefaultTargetType = TargetType; base.WritePropertyWithExtension(xamlPropertyWithExtensionNode); } ////// Write a Property, which has the form in markup of property="value" where /// value has been resolved to a Type reference. /// ////// When in a VisualTree, only DependencyProperties can be set directly on /// a FrameworkElementFactory. This method checks the state of parsing and /// with throw an exception if a clr property is set on a FrameworkElementFactory. /// public override void WritePropertyWithType(XamlPropertyWithTypeNode xamlPropertyNode) { StyleMode mode = _styleModeStack.Mode; if (mode == StyleMode.Base && xamlPropertyNode.PropName == XamlTemplateSerializer.TargetTypePropertyName) { _templateTargetTypeType = xamlPropertyNode.ValueElementType; } // If we are on the DataTemplate tag itself, and we encounter a DataType property, // this can be used as the key when placing this template in a ResourceDictionary. // In that case, remember what the property value is so that we can // later update the defer key held by the baml writer. else if (mode == StyleMode.Base && xamlPropertyNode.PropName == XamlTemplateSerializer.DataTypePropertyName) { #if PBTCOMPILER // Treat DataType="some type" as a key in a resource dictionary. // Generate a sequence of baml records to describe the key. if (InDeferLoadedSection && !_defNameFound) { _dataTypePropertyNode = xamlPropertyNode; _dataTypePropertyNodeDepth = _styleModeStack.Depth; } #endif } #if PBTCOMPILER else if (mode == StyleMode.DataTypeProperty && InDeferLoadedSection && !_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. base.WritePropertyWithType(xamlPropertyNode); } #endif base.WritePropertyWithType(xamlPropertyNode); } #if PBTCOMPILER // This method writes out BAML to produce a resource key based on the // DataType property. private void WriteDataTypeKey(XamlPropertyWithTypeNode xamlPropertyNode) { base.WriteKeyElementStart(new XamlElementStartNode( xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition, xamlPropertyNode.Depth, _templateKeyType.Assembly.FullName, _templateKeyType.FullName, _templateKeyType, null)); base.WriteConstructorParametersStart(new XamlConstructorParametersStartNode( xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition, xamlPropertyNode.Depth)); base.WriteConstructorParameterType(new XamlConstructorParameterTypeNode( xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition, xamlPropertyNode.Depth, xamlPropertyNode.ValueTypeFullName, xamlPropertyNode.ValueTypeAssemblyName, xamlPropertyNode.ValueElementType)); base.WriteConstructorParametersEnd(new XamlConstructorParametersEndNode( xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition, xamlPropertyNode.Depth)); base.WriteKeyElementEnd(new XamlElementEndNode( xamlPropertyNode.LineNumber, xamlPropertyNode.LinePosition, xamlPropertyNode.Depth)); } #endif ////// Used when an exception is thrown -- does shutdown on the parser and throws the exception. /// /// Exception internal override void ParseError(XamlParseException e) { CloseWriterStream(); #if !PBTCOMPILER // If there is an associated treebuilder, tell it about the error. There may not // be a treebuilder, if this parser was built from a serializer for the purpose of // converting directly to baml, rather than converting to an object tree. if (TreeBuilder != null) { TreeBuilder.XamlTreeBuildError(e); } #endif throw e; } ////// Called when the parse was cancelled by the designer or the user. /// internal override void ParseCancelled() { // Override so we don't close the writer stream, since we're a sub-parser } ////// Called when the parse has been completed successfully. /// internal override void ParseCompleted() { // Override so we don't close the writer stream, since we're a sub-parser } // Used to determine if strict or loose parsing rules should be enforced. The TokenReader // does some validations that are not valid in the case of parsing Templates, so do a // looser parsing validation. internal override bool StrictParsing { get { return false; } } #endregion Overrides #region Methods ////// Helper function if we are going to a Reader/Writer stream closes the writer /// side. /// internal void CloseWriterStream() { #if !PBTCOMPILER // only close the BamlRecordWriter. (Rename to Root??) if (null != BamlRecordWriter) { if (BamlRecordWriter.BamlStream is WriterStream) { WriterStream writeStream = (WriterStream) BamlRecordWriter.BamlStream; writeStream.Close(); } } #endif } #endregion Methods #region Properties #if !PBTCOMPILER ////// TreeBuilder associated with this class /// XamlTreeBuilder TreeBuilder { get { return _treeBuilder; } } #else ////// Return true if we are not in pass one of a compile and we are parsing a /// defer load section of markup. Note that if this is nested within a /// Style, then don't consider it to be in a defer loaded section since /// this is used a cue to determine when to generate dictionary keys. /// bool InDeferLoadedSection { get { return BamlRecordWriter != null && BamlRecordWriter.InDeferLoadedSection && _previousXamlParser.GetType() != typeof(StyleXamlParser); } } ////// Return true if this is pass one of a compile process. /// bool IsLocalPass1 { get { return BamlRecordWriter == null; } } #endif #endregion Properties #region Data #if !PBTCOMPILER // TreeBuilder that created this parser XamlTreeBuilder _treeBuilder; #endif // The XamlParser that the TokenReader was using when this instance of // the TemplateXamlParser was created. This must be restored on exit XamlParser _previousXamlParser; // Depth in the Xaml file when parsing of this template block started. // This is used to determine when to stop parsing int _startingDepth; // Number of template root nodes encountered immediately under a Template. Only 1 // is allowed. int _templateRootCount; StyleModeStack _styleModeStack = new StyleModeStack(); // Depth in the element tree where ahas begun. int _inSetterDepth = -1; // The actual Type of the TargetType property on template. This may be null. Type _templateTargetTypeType; // The default TargetType of the template to use when TargetType is not set. Type _defaultTargetType; // The XamlPropertyNode for the "Foo" Property attribute in // or XamlPropertyNode _setterOrTriggerPropertyNode; // The Property node for Value attribute in or // XamlPropertyNode _setterOrTriggerValueNode; // Depth in the element tree where a Trigger or MultiTrigger // section has begun. Set to -1 to indicate it is not within such a section. int _inPropertyTriggerDepth = -1; // Depth of nested complex properties within a VisualTree. This is used to // track when it is valid to have a clr property vs a dependency property // specified in the VisualTree; int _visualTreeComplexPropertyDepth = -1; // Depth of nested complex properties within the Triggers section. This is used to // track when it is valid to have text. int _triggerComplexPropertyDepth = -1; #if PBTCOMPILER // True if x:Key property was found on the template tag bool _defNameFound; // During second pass, remember the info for the DataType property, so // that we can write out a key if no x:Key is present XamlPropertyWithTypeNode _dataTypePropertyNode; int _dataTypePropertyNodeDepth; // True if event is in the same VisualTree FEF. bool _isSameScope; // Type to use for the implicit key in the dictionary Type _templateKeyType; #endif // Stack to keep track of element types during compile. Stack _elementTypeStack = new Stack(5); // Dictionary of names, where the key is the name string and the value // is the element type that is using that name. Hashtable _IDTypes = new Hashtable(); // The value of that identifies the target // of the set operation or the value of // that identifies the source of a trigger condition. string _setterTargetNameOrConditionSourceName; // MemberInfo fo the DP Property value for the case where a Value is read as ComplexAsSimple. MemberInfo _setterOrTriggerPropertyMemberInfo; #endregion Data } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- WindowsAuthenticationModule.cs
- QuaternionAnimationUsingKeyFrames.cs
- XmlAttributes.cs
- UIElementParaClient.cs
- ListBoxItemWrapperAutomationPeer.cs
- IncrementalReadDecoders.cs
- PartitionResolver.cs
- FirstMatchCodeGroup.cs
- RootAction.cs
- _BasicClient.cs
- WebBrowserContainer.cs
- ValueQuery.cs
- SID.cs
- Deflater.cs
- SmtpException.cs
- adornercollection.cs
- ToolBar.cs
- DataObjectPastingEventArgs.cs
- httpapplicationstate.cs
- FixedFindEngine.cs
- WebPartConnectionsCancelVerb.cs
- ListControl.cs
- QueryCacheEntry.cs
- PropertyHelper.cs
- GcHandle.cs
- IndicCharClassifier.cs
- SyndicationLink.cs
- SaveFileDialog.cs
- SpoolingTaskBase.cs
- TransportSecurityProtocol.cs
- ByteStorage.cs
- DesignerUtility.cs
- Delegate.cs
- FlatButtonAppearance.cs
- DatatypeImplementation.cs
- EventNotify.cs
- CommandHelpers.cs
- CookieHandler.cs
- ApplicationHost.cs
- SQLRoleProvider.cs
- DbXmlEnabledProviderManifest.cs
- PropertyChangedEventManager.cs
- Attributes.cs
- OutgoingWebRequestContext.cs
- ClientCredentials.cs
- CachedPathData.cs
- FrameworkElementFactoryMarkupObject.cs
- X509SubjectKeyIdentifierClause.cs
- DataStreamFromComStream.cs
- XmlSchemaSimpleContentExtension.cs
- XmlUtf8RawTextWriter.cs
- StylusPointPropertyId.cs
- ZipIOEndOfCentralDirectoryBlock.cs
- DiscardableAttribute.cs
- SimpleTextLine.cs
- SQLInt64Storage.cs
- WinEventWrap.cs
- ResourceReferenceExpressionConverter.cs
- _LocalDataStore.cs
- SecurityAlgorithmSuiteConverter.cs
- DecoderFallback.cs
- InputChannelAcceptor.cs
- StorageInfo.cs
- SessionViewState.cs
- HwndStylusInputProvider.cs
- MessagePartDescription.cs
- DataServicePagingProviderWrapper.cs
- KeyPressEvent.cs
- CodeBlockBuilder.cs
- SystemIPGlobalProperties.cs
- Debugger.cs
- StructuredTypeInfo.cs
- WindowExtensionMethods.cs
- ImportCatalogPart.cs
- PerfCounterSection.cs
- EntityDataSourceConfigureObjectContextPanel.cs
- ImportException.cs
- DataDocumentXPathNavigator.cs
- WasEndpointConfigContainer.cs
- SimpleApplicationHost.cs
- QueryExpr.cs
- LayoutEditorPart.cs
- ToolStripPanelCell.cs
- CharConverter.cs
- SoapServerMethod.cs
- DiscoveryDocumentSearchPattern.cs
- PlatformCulture.cs
- AdornerLayer.cs
- PropertyItem.cs
- DecimalConverter.cs
- PublisherMembershipCondition.cs
- IntSecurity.cs
- BrowserCapabilitiesFactoryBase.cs
- LogSwitch.cs
- FramingChannels.cs
- NameValueConfigurationCollection.cs
- Section.cs
- LeftCellWrapper.cs
- Int64Animation.cs
- SmtpMail.cs