internal BamlCollectionHolder(BamlRecordReader reader, object parent, short attributeId, bool needDefault) { _reader = reader; _parent = parent; _propDef = new WpfPropertyDefinition(reader, attributeId, parent is DependencyObject); _attributeId = attributeId; if (needDefault) { InitDefaultValue(); } CheckReadOnly(); }
// Common section for setting a property defined by an attributeId to a value. private void ReadPropertyRecordBase( string attribValue, short attributeId, short converterTypeId) { if( CurrentContext.CreateUsingTypeConverter ) { // TypeConverter syntax rules state that there shall be no specifying // property values on the TypeConverter object specification. // But like every other rule in XAML, we have an exception. // Exception: the xml:space property value is tolerated. We set the // ParserContext information and drop the rest of the data on the // ground. (We will not set the XmlSpace attached property like // we would for non-TypeConverter-created objects.) #if DEBUG // If we ever have more than one exception to the TypeConverter // rule, we'll need to run this differentiation code outside of // debug-only code path, too. short ownerTypeId; string name; BamlAttributeUsage attributeUsage; MapTable.GetAttributeInfoFromId(attributeId, out ownerTypeId, out name, out attributeUsage); Debug.Assert( attributeUsage == BamlAttributeUsage.XmlSpace, "The xml:space attribute is the only one deemed compatible with TypeConverter syntax, but we've encountered something else. How did this slip by the XamlReaderHelper TypeConverter syntax check?"); #endif ParserContext.XmlSpace = attribValue; // ParserContext state updated, and that's all we'll do for this record. return; } // If we get this far, it means we are not going to create an object // using its type converter, hence it's safe to call GetCurrentObjectForData(). // (GetCurrentObjectData will create an instance using the default constructor, // eliminating the possibility of TypeConverter creation.) object element = GetCurrentObjectData(); // Get attributeUsage - using perf optimized call (avoiding attributeInfo record allocation) WpfPropertyDefinition propertyDefinition = new WpfPropertyDefinition(this, attributeId, element is DependencyObject); #if !STRESS try { #endif switch (propertyDefinition.AttributeUsage) { case BamlAttributeUsage.RuntimeName: // Add Name to appropriate scope DoRegisterName(attribValue, element); break; case BamlAttributeUsage.XmlLang: ParserContext.XmlLang = attribValue; break; case BamlAttributeUsage.XmlSpace: ParserContext.XmlSpace = attribValue; break; } // Try DependencyProperty case: If the property is a DP we can handle it faster than the general reflection case if (propertyDefinition.DependencyProperty != null) { Debug.Assert(element is DependencyObject); object propertyValue = ParseProperty( (DependencyObject)element, propertyDefinition.PropertyType, propertyDefinition.Name, propertyDefinition.DependencyProperty, attribValue, converterTypeId); // If the value returned is not unset, then perform a DependencyObject.SetValue. An // UnsetValue can occur if a resource reference is bound or some other way of setting // up the value is done in ParseProperty. if (propertyValue != DependencyProperty.UnsetValue) { SetPropertyValue( element, propertyDefinition, propertyValue ); } } else if (propertyDefinition.PropertyInfo != null) { // General case of CLR or Attached property // Calculate the value of the property object propertyValue = ParseProperty( element, propertyDefinition.PropertyType, propertyDefinition.Name, propertyDefinition.PropertyInfo, attribValue, converterTypeId); // If the value returned is not unset, then perform a PropertyInfo.SetValue. // An UnsetValue can occur if a resource reference is bound or some other // way of setting up the value is done in ParseProperty. if (propertyValue != DependencyProperty.UnsetValue) { // Assign the value to the property SetPropertyValue( element, propertyDefinition, propertyValue ); } } else if (propertyDefinition.AttachedPropertySetter != null) { // Attached property // General case of CLR or Attached property // Calculate the value of the property object propertyValue = ParseProperty( element, propertyDefinition.PropertyType, propertyDefinition.Name, propertyDefinition.AttachedPropertySetter, attribValue, converterTypeId); // If the value returned is not unset, then perform a PropertyInfo.SetValue. // An UnsetValue can occur if a resource reference is bound or some other // way of setting up the value is done in ParseProperty. if (propertyValue != DependencyProperty.UnsetValue) { // Attached Property accessible via SetFoo/GetFoo static methods SetPropertyValue( element, propertyDefinition, propertyValue ); } } else { // Neither DP, nor Clr, nor Attached property. // We may have found the attribute record (which should always work unless // the file is corrupted), but it may not resolve to a property with the // currently loaded set of assemblies. Try a locally defined event before complaining. bool isRE = false; object reidOrEi = null; bool isInternal = false; if (_componentConnector != null && _rootElement != null) { reidOrEi = GetREOrEiFromAttributeId(attributeId, out isInternal, out isRE); } if (reidOrEi != null) { Delegate d; if (isRE) { RoutedEvent reid = reidOrEi as RoutedEvent; d = XamlTypeMapper.CreateDelegate(ParserContext, reid.HandlerType, ParserContext.RootElement, attribValue); if (d == null) { ThrowException(SRID.ParserCantCreateDelegate, reid.HandlerType.Name, attribValue); } UIElement uiel = element as UIElement; if (uiel != null) { uiel.AddHandler(reid, d); } else { ContentElement ce = element as ContentElement; if (ce != null) { ce.AddHandler(reid, d); } else { // In the case where the element doesn't support any routed event AddHandler // we know the null pointer exception is caught and wrapped in a XAML parse exception // below (we would have added an error message but 3.5 doesn't allow us to add one). UIElement3D uie3D = element as UIElement3D; uie3D.AddHandler(reid, d); } } } else { EventInfo ei = reidOrEi as EventInfo; d = XamlTypeMapper.CreateDelegate(ParserContext, ei.EventHandlerType, ParserContext.RootElement, attribValue); if (d == null) { ThrowException(SRID.ParserCantCreateDelegate, ei.EventHandlerType.Name, attribValue); } if (isInternal) { bool added = XamlTypeMapper.AddInternalEventHandler(ParserContext, ParserContext.RootElement, ei, element, d); if (!added) { ThrowException(SRID.ParserCantSetAttribute, "event", ei.Name, "add"); } } else { ei.AddEventHandler(element, d); } } return; } else { ThrowException(SRID.ParserCantGetDPOrPi, propertyDefinition.Name); } } #if !STRESS } catch (Exception e) { if (CriticalExceptions.IsCriticalException(e) || e is XamlParseException) { throw; } TargetInvocationException tie = e as TargetInvocationException; if( tie != null ) { e = tie.InnerException; } ThrowExceptionWithLine(SR.Get(SRID.ParserCannotSetValue, element.GetType().FullName, propertyDefinition.AttributeInfo.Name, attribValue), e); } #endif }
// Read a Property record, get the current element off the context stack and a Type // object from the TypeId in the property record. This is the object to set // on the property. protected virtual void ReadPropertyTypeRecord(BamlPropertyTypeReferenceRecord bamlPropertyRecord) { if (null == CurrentContext || (ReaderFlags.DependencyObject != CurrentContext.ContextType && ReaderFlags.ClrObject != CurrentContext.ContextType)) { ThrowException(SRID.ParserUnexpInBAML, "Property"); } // Define attrbuteId short attributeId = bamlPropertyRecord.AttributeId; // Identify the target element object element = GetCurrentObjectData(); // Get value type Type valueType = MapTable.GetTypeFromId(bamlPropertyRecord.TypeId); // Identify the property WpfPropertyDefinition propertyDefinition = new WpfPropertyDefinition(this, attributeId, element is DependencyObject); #if !STRESS try { #endif if( !SetPropertyValue( element, propertyDefinition, valueType )) { ThrowException(SRID.ParserCantGetDPOrPi, GetPropertyNameFromAttributeId(attributeId)); } #if !STRESS } catch (Exception e) { if (CriticalExceptions.IsCriticalException(e) || e is XamlParseException) { throw; } TargetInvocationException tie = e as TargetInvocationException; if( tie != null ) { e = tie.InnerException; } ThrowExceptionWithLine(SR.Get(SRID.ParserCannotSetValue, element.GetType().FullName, propertyDefinition.Name, valueType.Name), e); } #endif }
// // Set a value onto a property of an object. The property could be a DP // or a CLR property (figure out from the PropertyDefinition). // private bool SetPropertyValue( Object o, WpfPropertyDefinition propertyDefinition, object value ) { bool succeeded = true; // // DP case // if (propertyDefinition.DependencyProperty != null) { if( TraceMarkup.IsEnabled ) { TraceMarkup.Trace( TraceEventType.Start, TraceMarkup.SetPropertyValue, o, propertyDefinition.DependencyProperty.Name, value); } Debug.Assert(o is DependencyObject); SetDependencyValue((DependencyObject)o, propertyDefinition.DependencyProperty, value); if( TraceMarkup.IsEnabled ) { TraceMarkup.Trace( TraceEventType.Stop, TraceMarkup.SetPropertyValue, o, propertyDefinition.DependencyProperty.Name, value); } } // // Non-attached CLR property case. // else if (propertyDefinition.PropertyInfo != null) { if( TraceMarkup.IsEnabled ) { TraceMarkup.Trace( TraceEventType.Start, TraceMarkup.SetPropertyValue, o, propertyDefinition.PropertyInfo.Name, value); } if (propertyDefinition.IsInternal) { bool set = XamlTypeMapper.SetInternalPropertyValue(ParserContext, ParserContext.RootElement, propertyDefinition.PropertyInfo, o, value); if (!set) { ThrowException(SRID.ParserCantSetAttribute, "property", propertyDefinition.Name, "set"); } } else { propertyDefinition.PropertyInfo.SetValue(o, value, BindingFlags.Default, null, null, TypeConverterHelper.InvariantEnglishUS); } if( TraceMarkup.IsEnabled ) { TraceMarkup.Trace( TraceEventType.Stop, TraceMarkup.SetPropertyValue, o, propertyDefinition.PropertyInfo.Name, value); } } // // Attached CLR property case // else if (propertyDefinition.AttachedPropertySetter != null) { if( TraceMarkup.IsEnabled ) { TraceMarkup.Trace( TraceEventType.Start, TraceMarkup.SetPropertyValue, o, propertyDefinition.AttachedPropertySetter.Name, value); } propertyDefinition.AttachedPropertySetter.Invoke(null, new object[] { o, value }); if( TraceMarkup.IsEnabled ) { TraceMarkup.Trace( TraceEventType.Stop, TraceMarkup.SetPropertyValue, o, propertyDefinition.AttachedPropertySetter.Name, value); } } // // Error case // else { succeeded = false; } return succeeded; }
private void BaseReadOptimizedMarkupExtension( object element, short attributeId, WpfPropertyDefinition propertyDefinition, object value) { #if !STRESS try { #endif // if the value is a ME, get the actual value from it. MarkupExtension me = value as MarkupExtension; if (me != null) { value = ProvideValueFromMarkupExtension(me, element, propertyDefinition.DpOrPiOrMi); if( TraceMarkup.IsEnabled ) { TraceMarkup.TraceActivityItem( TraceMarkup.ProvideValue, me, element, propertyDefinition.DpOrPiOrMi, value ); } } if( !SetPropertyValue( element, propertyDefinition, value )) { ThrowException(SRID.ParserCantGetDPOrPi, GetPropertyNameFromAttributeId(attributeId)); } #if !STRESS } catch( Exception e ) { if (CriticalExceptions.IsCriticalException(e) || e is XamlParseException) { throw; } TargetInvocationException tie = e as TargetInvocationException; if( tie != null ) { e = tie.InnerException; } string message = SR.Get(SRID.ParserCannotConvertPropertyValue, propertyDefinition.Name, propertyDefinition.PropertyType.FullName); ThrowExceptionWithLine(message, e); } #endif }
protected virtual void ReadPropertyWithExtensionRecord(BamlPropertyWithExtensionRecord bamlPropertyRecord) { if (null == CurrentContext || (ReaderFlags.DependencyObject != CurrentContext.ContextType && ReaderFlags.ClrObject != CurrentContext.ContextType)) { ThrowException(SRID.ParserUnexpInBAML, "Property"); } // Define attrbuteId short attributeId = bamlPropertyRecord.AttributeId; // Identify the target element object element = GetCurrentObjectData(); // Identify the property WpfPropertyDefinition propertyDefinition = new WpfPropertyDefinition(this, attributeId, element is DependencyObject); // Get the value of the property object value = GetExtensionValue(bamlPropertyRecord, propertyDefinition.Name); // Read and set the value provided by the MarkupExtension on the element's property BaseReadOptimizedMarkupExtension(element, attributeId, propertyDefinition, value); }
// Read a property record that has value information known only to the // property's ValidType. protected virtual void ReadPropertyCustomRecord(BamlPropertyCustomRecord bamlPropertyRecord) { if (null == CurrentContext || (ReaderFlags.DependencyObject != CurrentContext.ContextType && ReaderFlags.ClrObject != CurrentContext.ContextType)) { ThrowException(SRID.ParserUnexpInBAML, "PropertyCustom"); } // the value of the property object valueObject = null; // Get the element to set the property on object element = GetCurrentObjectData(); // Get the attributeId short attributeId = bamlPropertyRecord.AttributeId; // Identify the property WpfPropertyDefinition propertyDefinition = new WpfPropertyDefinition(this, attributeId, element is DependencyObject); if (!bamlPropertyRecord.ValueObjectSet) { #if !STRESS // Get the value of the property that is obtained from the binary data in the record. try { #endif valueObject = GetCustomValue(bamlPropertyRecord, propertyDefinition.PropertyType, propertyDefinition.Name); #if !STRESS } catch (Exception e) { if( CriticalExceptions.IsCriticalException(e) || e is XamlParseException ) { throw; } string message = SR.Get(SRID.ParserCannotConvertPropertyValue, propertyDefinition.Name, propertyDefinition.PropertyType.FullName); ThrowExceptionWithLine(message, e); } #endif } else { valueObject = bamlPropertyRecord.ValueObject; } FreezeIfRequired(valueObject); if (propertyDefinition.DependencyProperty != null) { Debug.Assert(element is DependencyObject, "Guaranteed by PropertyDefinition constructor"); SetDependencyValue((DependencyObject)element, propertyDefinition.DependencyProperty, valueObject); } else if (propertyDefinition.PropertyInfo != null) { // Regular case for CLR property if (propertyDefinition.IsInternal) { bool set = XamlTypeMapper.SetInternalPropertyValue(ParserContext, ParserContext.RootElement, propertyDefinition.PropertyInfo, element, valueObject); if (!set) { ThrowException(SRID.ParserCantSetAttribute, "property", propertyDefinition.Name, "set"); } } else { propertyDefinition.PropertyInfo.SetValue(element, valueObject, BindingFlags.Default, null, null, TypeConverterHelper.InvariantEnglishUS); } } else if (propertyDefinition.AttachedPropertySetter != null) { propertyDefinition.AttachedPropertySetter.Invoke(null, new object[] { element, valueObject }); } else { ThrowException(SRID.ParserCantGetDPOrPi, GetPropertyNameFromAttributeId(attributeId)); } }
// Read the start of a complex property section. Determine the property to set // with the object that will be constructed from the following records. protected virtual void ReadPropertyComplexStartRecord( BamlPropertyComplexStartRecord bamlPropertyRecord) { if (null == CurrentContext || !(ReaderFlags.ClrObject == CurrentContext.ContextType || ReaderFlags.DependencyObject == CurrentContext.ContextType)) { ThrowException(SRID.ParserUnexpInBAML, "PropertyComplexStart"); } short attributeId = bamlPropertyRecord.AttributeId; WpfPropertyDefinition propertyDefinition = new WpfPropertyDefinition( this, attributeId, ReaderFlags.DependencyObject == CurrentContext.ContextType /*targetIsDependencyObject*/ ); // Try DependencyProperty optimization. if (propertyDefinition.DependencyProperty != null) { // For the case of a DependencyProperty, store the BamlAttributeInfo on the // stack, because we may need to know the actual added owner type for the DP // to use in error messages. This is not available in the DP if there // are multiple owners. PushContext(ReaderFlags.PropertyComplexDP, propertyDefinition.AttributeInfo, propertyDefinition.PropertyType, 0); } else if (propertyDefinition.PropertyInfo != null) { // Regular case for clr property PushContext(ReaderFlags.PropertyComplexClr, propertyDefinition.PropertyInfo, propertyDefinition.PropertyType, 0); } else if (propertyDefinition.AttachedPropertySetter != null) { // Assignable Attached property PushContext(ReaderFlags.PropertyComplexClr, propertyDefinition.AttachedPropertySetter, propertyDefinition.PropertyType, 0); } else if (propertyDefinition.AttachedPropertyGetter != null) { // Readonly Attached property PushContext(ReaderFlags.PropertyComplexClr, propertyDefinition.AttachedPropertyGetter, propertyDefinition.PropertyType, 0); } else { ThrowException(SRID.ParserCantGetDPOrPi, GetPropertyNameFromAttributeId(attributeId)); } // Set the name of the property into the context CurrentContext.ElementNameOrPropertyName = propertyDefinition.Name; }
// Read the content property record and set the ContentProperty in the context. internal virtual void ReadContentPropertyRecord( BamlContentPropertyRecord bamlContentPropertyRecord) { object contentProperty = null; short attributeId = bamlContentPropertyRecord.AttributeId; // Try KnownTypes Optimization: When the property is known use generated code for accessing it object parent = GetCurrentObjectData(); if (parent != null) { short elementId = BamlMapTable.GetKnownTypeIdFromType(parent.GetType()); if (elementId < 0) { contentProperty = KnownTypes.GetCollectionForCPA(parent, (KnownElements)(-elementId)); } } if (contentProperty == null) { WpfPropertyDefinition propertyDefinition = new WpfPropertyDefinition(this, attributeId, parent is DependencyObject); // Try DependencyProperty Optimization: When a DP exists for the property, use it for accessing the property if (propertyDefinition.DependencyProperty != null) { Debug.Assert(parent is DependencyObject); if (typeof(IList).IsAssignableFrom(propertyDefinition.PropertyType)) { contentProperty = ((DependencyObject)parent).GetValue(propertyDefinition.DependencyProperty) as IList; // We assume that the contentProperty will become a collection now. // However, in case when the DP is implemented incorrectly it may return null even if the clr property has non-null value. // So leaving contentProperty==null will drive us to general clr case below, which must do better job. } else { // When the property is not a IList store a DP itself as a contentProperty for assigning a simple value contentProperty = propertyDefinition.DependencyProperty; } } if (contentProperty == null) { // We consider only PropertyInfo case here. // We do not consider AttachedPropertySetter in this case because content property cannot be attached. if (propertyDefinition.PropertyInfo != null) { // Try to treat the content property as IList if (propertyDefinition.IsInternal) { contentProperty = XamlTypeMapper.GetInternalPropertyValue(ParserContext, ParserContext.RootElement, propertyDefinition.PropertyInfo, parent) as IList; // if Content Property does not support IList, then see if it is // accessible\allowed as a regular setter. // if (contentProperty == null) { bool isPublicProperty; bool allowProtected = (ParserContext.RootElement is IComponentConnector) && (ParserContext.RootElement == parent); if (!XamlTypeMapper.IsAllowedPropertySet(propertyDefinition.PropertyInfo, allowProtected, out isPublicProperty)) { ThrowException(SRID.ParserCantSetContentProperty, propertyDefinition.Name, propertyDefinition.PropertyInfo.ReflectedType.Name); } } } else { contentProperty = propertyDefinition.PropertyInfo.GetValue( parent, BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy, null, null, TypeConverterHelper.InvariantEnglishUS) as IList; } if (contentProperty == null) { // The property returned null, try setting it directly. contentProperty = propertyDefinition.PropertyInfo; } } } } if (contentProperty == null) { ThrowException(SRID.ParserCantGetDPOrPi, GetPropertyNameFromAttributeId(attributeId)); } CurrentContext.ContentProperty = contentProperty; }