// Writes a collection of attributes representing properties with local values set on them. // If the value cannot be serialized as a string, adds the property to a collection of complexProperties. private static void WriteLocallySetProperties(Type elementTypeStandardized, ITextPointer context, XmlWriter xmlWriter, DependencyObject complexProperties) { TextPointer textPointer = context as TextPointer; if (textPointer == null) { // We can't have custom properties if we're not a TextPointer return; } LocalValueEnumerator locallySetProperties = context.GetLocalValueEnumerator(); DependencyProperty[] inheritableProperties = TextSchema.GetInheritableProperties(elementTypeStandardized); DependencyProperty[] nonInheritableProperties = TextSchema.GetNoninheritableProperties(elementTypeStandardized); while (locallySetProperties.MoveNext()) { DependencyProperty locallySetProperty = (DependencyProperty)locallySetProperties.Current.Property; // Don't serialize read-only properties, or any properties registered or owned by a // a class in the framework (we only want to serialize custom properties), to be // consistent with our behavior for non-custom inlines. // if (!locallySetProperty.ReadOnly && !IsPropertyKnown(locallySetProperty, inheritableProperties, nonInheritableProperties) && !TextSchema.IsKnownType(locallySetProperty.OwnerType)) { object propertyValue = context.ReadLocalValue(locallySetProperty); string stringValue = DPTypeDescriptorContext.GetStringValue(locallySetProperty, propertyValue); if (stringValue != null) { stringValue = FilterNaNStringValueForDoublePropertyType(stringValue, locallySetProperty.PropertyType); string propertyName = GetPropertyNameForElement(locallySetProperty, elementTypeStandardized, /*forceComplexName:*/false); xmlWriter.WriteAttributeString(propertyName, stringValue); } else { complexProperties.SetValue(locallySetProperty, propertyValue); } } } // *** WE NEED TO BETTER UNDERSTAND THE IMPLICATIONS OF SERIALIZING NON-DP CLR PROPERTIES, SO THE REST OF // *** THIS METHOD IS DISABLED UNTIL WE DECIDE THE BEST WAY TO HANDLE THEM. // *** CLRTypeDescriptorContext is essentially the same as DPTypeDescriptorContext. #if false // Check all CLR properties // Note that this is partially redundant. TypeDescriptor.GetProperties, when called on a // DependencyObject, will return all properties that are set-- including all those already // serialized as Inheritable, NonInheritable, or LocallySet properties. A potential // optimization, therefore, is to remove those serialization methods and simply use this one // for everything when we've opted into custom element serialization. PropertyDescriptorCollection descriptorCollection = TypeDescriptor.GetProperties(textPointer.Parent); IEnumerator descriptors = descriptorCollection.GetEnumerator(); while (descriptors.MoveNext()) { PropertyDescriptor current = (PropertyDescriptor)descriptors.Current; // ShouldSerializeValue() will return true for readonly properties that have explicitly // been told to serialize, such as Span.Inlines. If we serialize a read-only property, // however, the parser will throw an exception when we try to deserialize. So we // explicitly skip all read-only properties, and all DPs. if (!current.ShouldSerializeValue(textPointer.Parent) || current.IsReadOnly || current is MS.Internal.ComponentModel.DependencyObjectPropertyDescriptor) { continue; } // Serialize the property object propertyValue = current.GetValue(textPointer.Parent); if (propertyValue != null) { string stringValue = CLRTypeDescriptorContext.GetStringValue(current, propertyValue); if (stringValue != null) { stringValue = FilterNaNStringValueForDoublePropertyType(stringValue, current.PropertyType); xmlWriter.WriteAttributeString(current.Name, stringValue); } else { // } } } #endif }