diff --git a/src/Microsoft.DotNet.Wpf/ApiCompat/Baselines/PresentationFramework-ref.baseline.txt b/src/Microsoft.DotNet.Wpf/ApiCompat/Baselines/PresentationFramework-ref.baseline.txt index d4b7ffccb6b..f37c11c5841 100644 --- a/src/Microsoft.DotNet.Wpf/ApiCompat/Baselines/PresentationFramework-ref.baseline.txt +++ b/src/Microsoft.DotNet.Wpf/ApiCompat/Baselines/PresentationFramework-ref.baseline.txt @@ -76,6 +76,7 @@ CannotChangeAttribute : Attribute 'System.Windows.LocalizabilityAttribute' on 'S CannotChangeAttribute : Attribute 'System.Windows.LocalizabilityAttribute' on 'System.Windows.Controls.AccessText.FontSize' changed from '[LocalizabilityAttribute(0)]' in the contract to '[LocalizabilityAttribute(LocalizationCategory.None)]' in the implementation. CannotChangeAttribute : Attribute 'System.Windows.LocalizabilityAttribute' on 'System.Windows.Controls.BooleanToVisibilityConverter' changed from '[LocalizabilityAttribute(17)]' in the contract to '[LocalizabilityAttribute(LocalizationCategory.NeverLocalize)]' in the implementation. CannotChangeAttribute : Attribute 'System.Windows.LocalizabilityAttribute' on 'System.Windows.Controls.CheckBox' changed from '[LocalizabilityAttribute(5)]' in the contract to '[LocalizabilityAttribute(LocalizationCategory.CheckBox)]' in the implementation. +CannotRemoveAttribute : Attribute 'System.ComponentModel.TypeConverterAttribute' exists on 'System.Windows.Controls.ColumnDefinition' in the contract but not the implementation. CannotChangeAttribute : Attribute 'System.Windows.LocalizabilityAttribute' on 'System.Windows.Controls.ComboBox' changed from '[LocalizabilityAttribute(6)]' in the contract to '[LocalizabilityAttribute(LocalizationCategory.ComboBox)]' in the implementation. CannotChangeAttribute : Attribute 'System.Windows.LocalizabilityAttribute' on 'System.Windows.Controls.ComboBoxItem' changed from '[LocalizabilityAttribute(6)]' in the contract to '[LocalizabilityAttribute(LocalizationCategory.ComboBox)]' in the implementation. CannotChangeAttribute : Attribute 'System.Windows.LocalizabilityAttribute' on 'System.Windows.Controls.ContentControl' changed from '[LocalizabilityAttribute(0, Readability=0)]' in the contract to '[LocalizabilityAttribute(LocalizationCategory.None, Readability=Readability.Unreadable)]' in the implementation. @@ -145,6 +146,7 @@ CannotChangeAttribute : Attribute 'System.Windows.LocalizabilityAttribute' on 'S CannotChangeAttribute : Attribute 'System.Windows.LocalizabilityAttribute' on 'System.Windows.Controls.RadioButton.GroupName' changed from '[LocalizabilityAttribute(17)]' in the contract to '[LocalizabilityAttribute(LocalizationCategory.NeverLocalize)]' in the implementation. CannotChangeAttribute : Attribute 'System.Windows.LocalizabilityAttribute' on 'System.Windows.Controls.RichTextBox' changed from '[LocalizabilityAttribute(15)]' in the contract to '[LocalizabilityAttribute(LocalizationCategory.Inherit)]' in the implementation. CannotChangeAttribute : Attribute 'System.ComponentModel.DesignerSerializationVisibilityAttribute' on 'System.Windows.Controls.RichTextBox.CaretPosition' changed from '[DesignerSerializationVisibilityAttribute(0)]' in the contract to '[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]' in the implementation. +CannotRemoveAttribute : Attribute 'System.ComponentModel.TypeConverterAttribute' exists on 'System.Windows.Controls.RowDefinition' in the contract but not the implementation. CannotChangeAttribute : Attribute 'System.ComponentModel.DesignerSerializationVisibilityAttribute' on 'System.Windows.Controls.ScrollContentPresenter.HorizontalOffset' changed from '[DesignerSerializationVisibilityAttribute(0)]' in the contract to '[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]' in the implementation. CannotChangeAttribute : Attribute 'System.ComponentModel.DesignerSerializationVisibilityAttribute' on 'System.Windows.Controls.ScrollContentPresenter.ScrollOwner' changed from '[DesignerSerializationVisibilityAttribute(0)]' in the contract to '[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]' in the implementation. CannotChangeAttribute : Attribute 'System.ComponentModel.DesignerSerializationVisibilityAttribute' on 'System.Windows.Controls.ScrollContentPresenter.VerticalOffset' changed from '[DesignerSerializationVisibilityAttribute(0)]' in the contract to '[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]' in the implementation. @@ -261,4 +263,4 @@ CannotChangeAttribute : Attribute 'System.ComponentModel.DesignerSerializationVi CannotChangeAttribute : Attribute 'System.Windows.Markup.DesignerSerializationOptionsAttribute' on 'System.Windows.Markup.XmlAttributeProperties.GetXmlSpace(System.Windows.DependencyObject)' changed from '[DesignerSerializationOptionsAttribute(1)]' in the contract to '[DesignerSerializationOptionsAttribute(DesignerSerializationOptions.SerializeAsAttribute)]' in the implementation. CannotChangeAttribute : Attribute 'System.ComponentModel.DesignerSerializationVisibilityAttribute' on 'System.Windows.Media.Animation.Storyboard.GetTarget(System.Windows.DependencyObject)' changed from '[DesignerSerializationVisibilityAttribute(0)]' in the contract to '[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]' in the implementation. CannotChangeAttribute : Attribute 'System.Windows.LocalizabilityAttribute' on 'System.Windows.Shapes.Shape' changed from '[LocalizabilityAttribute(0, Readability=0)]' in the contract to '[LocalizabilityAttribute(LocalizationCategory.None, Readability=Readability.Unreadable)]' in the implementation. -Total Issues: 262 +Total Issues: 264 diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/PresentationFramework.csproj b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/PresentationFramework.csproj index 9572a2184d0..a4240835efc 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/PresentationFramework.csproj +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/PresentationFramework.csproj @@ -548,6 +548,7 @@ + @@ -740,6 +741,7 @@ + diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ColumnDefinition.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ColumnDefinition.cs index 6962180fe76..365603058b4 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ColumnDefinition.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ColumnDefinition.cs @@ -907,6 +907,7 @@ private void PrivateValidate() /// ColumnDefinition is a FrameworkContentElement used by Grid /// to hold column / row specific properties. /// + [TypeConverter(typeof(ColumnDefinitionConverter))] public class ColumnDefinition : DefinitionBase { //------------------------------------------------------ diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ColumnDefinitionConverter.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ColumnDefinitionConverter.cs new file mode 100644 index 00000000000..5525977041e --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/ColumnDefinitionConverter.cs @@ -0,0 +1,92 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.ComponentModel; +using System.Windows.Controls; +using System.Windows.Markup; +using System.Globalization; +using System.Text; +using MS.Internal; + +namespace System.Windows.Controls +{ + internal sealed class ColumnDefinitionConverter : TypeConverter + { + #region Public Methods + + /// + /// CanConvertFrom - Returns whether or not this class can convert from a given type. + /// + /// + /// bool - True if this converter can convert from the provided type, false if not. + /// + /// The ITypeDescriptorContext for this call. + /// The Type being queried for support. + public override bool CanConvertFrom(ITypeDescriptorContext typeDescriptorContext, Type sourceType) + { + return sourceType == typeof(string); + } + + /// + /// CanConvertTo - Returns whether or not this class can convert to a given type. + /// + /// + /// bool - True if this converter can convert to the provided type, false if not. + /// + /// The ITypeDescriptorContext for this call. + /// The Type being queried for support. + public override bool CanConvertTo(ITypeDescriptorContext typeDescriptorContext, Type destinationType) + { + return destinationType == typeof(string); + } + + /// + /// ConvertFrom - Attempt to convert to a ColumnDefinitionCollection from the given object. + /// + /// + /// The object which was constructed. + /// + /// + /// An ArgumentNullException is thrown if the example object is null. + /// + /// The ITypeDescriptorContext for this call. + /// The CultureInfo which is respected when converting. + /// The Thickness to convert. + public override object ConvertFrom(ITypeDescriptorContext typeDescriptorContext, CultureInfo cultureInfo, object value) + { + if (value is string input) + { + ColumnDefinition columnDefinition = new ColumnDefinition{ Width = GridLengthConverter.FromString(input, cultureInfo) }; + return columnDefinition; + } + throw GetConvertFromException(value); + } + + /// + /// ConvertTo - Attempt to convert a ColumnDefinitionCollection to the given type + /// + /// + /// The object which was constructed. + /// + /// + /// An ArgumentNullException is thrown if the example object is null. + /// + /// The ITypeDescriptorContext for this call. + /// The CultureInfo which is respected when converting. + /// The ColumnDefinitionCollection to convert. + /// The type to which to convert the ColumnDefinitionCollection instance. + public override object ConvertTo(ITypeDescriptorContext typeDescriptorContext, CultureInfo cultureInfo, object value, Type destinationType) + { + ArgumentNullException.ThrowIfNull(value); + ArgumentNullException.ThrowIfNull(destinationType); + if (destinationType == typeof(string) && value is ColumnDefinition columnDefinition) + { + return GridLengthConverter.ToString(columnDefinition.Width, cultureInfo); + } + throw GetConvertToException(value, destinationType); + } + + #endregion Public Methods + } +} \ No newline at end of file diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/RowDefinition.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/RowDefinition.cs index b50920ea489..bc20a1cdaa8 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/RowDefinition.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/RowDefinition.cs @@ -907,6 +907,7 @@ private void PrivateValidate() /// RowDefinition is a FrameworkContentElement used by Grid /// to hold column / row specific properties. /// + [TypeConverter(typeof(RowDefinitionConverter))] public class RowDefinition : DefinitionBase { //------------------------------------------------------ diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/RowDefinitionConverter.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/RowDefinitionConverter.cs new file mode 100644 index 00000000000..0cc0eb467ba --- /dev/null +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/RowDefinitionConverter.cs @@ -0,0 +1,92 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.ComponentModel; +using System.Windows.Controls; +using System.Windows.Markup; +using System.Globalization; +using System.Text; +using MS.Internal; + +namespace System.Windows.Controls +{ + internal sealed class RowDefinitionConverter : TypeConverter + { + #region Public Methods + + /// + /// CanConvertFrom - Returns whether or not this class can convert from a given type. + /// + /// + /// bool - True if this converter can convert from the provided type, false if not. + /// + /// The ITypeDescriptorContext for this call. + /// The Type being queried for support. + public override bool CanConvertFrom(ITypeDescriptorContext typeDescriptorContext, Type sourceType) + { + return sourceType == typeof(string); + } + + /// + /// CanConvertTo - Returns whether or not this class can convert to a given type. + /// + /// + /// bool - True if this converter can convert to the provided type, false if not. + /// + /// The ITypeDescriptorContext for this call. + /// The Type being queried for support. + public override bool CanConvertTo(ITypeDescriptorContext typeDescriptorContext, Type destinationType) + { + return destinationType == typeof(string); + } + + /// + /// ConvertFrom - Attempt to convert to a RowDefinitionCollection from the given object. + /// + /// + /// The object which was constructed. + /// + /// + /// An ArgumentNullException is thrown if the example object is null. + /// + /// The ITypeDescriptorContext for this call. + /// The CultureInfo which is respected when converting. + /// The Thickness to convert. + public override object ConvertFrom(ITypeDescriptorContext typeDescriptorContext, CultureInfo cultureInfo, object value) + { + if (value is string input) + { + RowDefinition rowDefinition = new RowDefinition{ Height = GridLengthConverter.FromString(input, cultureInfo) }; + return rowDefinition; + } + throw GetConvertFromException(value); + } + + /// + /// ConvertTo - Attempt to convert a RowDefinitionCollection to the given type + /// + /// + /// The object which was constructed. + /// + /// + /// An ArgumentNullException is thrown if the example object is null. + /// + /// The ITypeDescriptorContext for this call. + /// The CultureInfo which is respected when converting. + /// The RowDefinitionCollection to convert. + /// The type to which to convert the RowDefinitionCollection instance. + public override object ConvertTo(ITypeDescriptorContext typeDescriptorContext, CultureInfo cultureInfo, object value, Type destinationType) + { + ArgumentNullException.ThrowIfNull(value); + ArgumentNullException.ThrowIfNull(destinationType); + if (destinationType == typeof(string) && value is RowDefinition rowDefinition) + { + return GridLengthConverter.ToString(rowDefinition.Height, cultureInfo); + } + throw GetConvertToException(value, destinationType); + } + + #endregion Public Methods + } +} \ No newline at end of file diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/Baml2006/WpfGeneratedKnownTypes.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/Baml2006/WpfGeneratedKnownTypes.cs index 0b2c324ad85..7fc4d1f247d 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/Baml2006/WpfGeneratedKnownTypes.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/Baml2006/WpfGeneratedKnownTypes.cs @@ -2753,6 +2753,7 @@ private WpfKnownType Create_BamlType_ColumnDefinition(bool isBamlType, bool useV bamlType.RuntimeNamePropertyName = "Name"; bamlType.XmlLangPropertyName = "Language"; bamlType.IsUsableDuringInit = true; + bamlType.TypeConverterType = typeof(System.Windows.Controls.ColumnDefinitionConverter); bamlType.Freeze(); return bamlType; } @@ -8634,6 +8635,7 @@ private WpfKnownType Create_BamlType_RowDefinition(bool isBamlType, bool useV3Ru bamlType.RuntimeNamePropertyName = "Name"; bamlType.XmlLangPropertyName = "Language"; bamlType.IsUsableDuringInit = true; + bamlType.TypeConverterType = typeof(System.Windows.Controls.RowDefinitionConverter); bamlType.Freeze(); return bamlType; } diff --git a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/XamlReaderHelper.cs b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/XamlReaderHelper.cs index 4ce11585b23..89408f55111 100644 --- a/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/XamlReaderHelper.cs +++ b/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Markup/XamlReaderHelper.cs @@ -456,6 +456,12 @@ internal bool IsXmlDataIsland() { return (_xmlDataIslandDepth != -1); } + + internal bool CanInitializeCollectionFromString(Type type) + { + return IsACollection(type) && XamlTypeMapper.GetTypeConverterType(type) == null + && XamlTypeMapper.GetTypeConverterType(GetCollectionItemType(type)) != null; + } #endregion internalMethods #region CacheCallbacks @@ -3225,13 +3231,13 @@ private void WritePropertyAttribute( propertyCanWrite = false; } - if (!propertyCanWrite) + if (!propertyCanWrite && !CanInitializeCollectionFromString(propInfo.PropertyType)) { ThrowExceptionWithLine(SR.Format(SR.ParserReadOnlyProp, attribLocalName)); } } - if (propInfo != null && !XamlTypeMapper.IsAllowedPropertySet(propInfo)) + if (propInfo != null && !CanInitializeCollectionFromString(propInfo.PropertyType) && !XamlTypeMapper.IsAllowedPropertySet(propInfo)) { ThrowException(nameof(SR.ParserCantSetAttribute), "property", $"{declaringType.Name}.{attribLocalName}", "set"); } diff --git a/src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/InfosetObjects/XamlObjectWriter.cs b/src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/InfosetObjects/XamlObjectWriter.cs index 88d5c88b72e..1356fc2f2eb 100644 --- a/src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/InfosetObjects/XamlObjectWriter.cs +++ b/src/Microsoft.DotNet.Wpf/src/System.Xaml/System/Xaml/InfosetObjects/XamlObjectWriter.cs @@ -782,6 +782,10 @@ public override void WriteEndMember() shouldSetValue = true; _context.ParentKeyIsUnconverted = true; } + else if (valueXamlType == XamlLanguage.String && property.Type.IsCollection && property.TypeConverter == null && property.Type.ItemType.TypeConverter != null) + { + shouldSetValue = Logic_InitializeCollectionFromString(_context); + } else { shouldSetValue = Logic_CreatePropertyValueFromValue(_context); @@ -1383,6 +1387,51 @@ private bool Logic_CreatePropertyValueFromValue(ObjectWriterContext ctx) return true; } + private bool Logic_InitializeCollectionFromString(ObjectWriterContext ctx) + { + XamlMember property = ctx.ParentProperty; + XamlType propertyType = property.Type; + object parentInstance = ctx.ParentInstance; + + // save collection initialization string as value + string value = ctx.CurrentInstance as string; + + // get collection item type + XamlType collectionItemType = propertyType.ItemType; + + // check if collection item type has typeconverter + XamlValueConverter converter = collectionItemType.TypeConverter; + + TypeConverter typeConverter = Runtime.GetConverterInstance(converter); + + // push frame onto stack to hold collection + ctx.PushScope(); + + // get collection as member from Parent and set as current instance + object inst = Runtime.GetValue(parentInstance, property); + + ctx.CurrentIsObjectFromMember = true; + ctx.CurrentType = propertyType; + ctx.CurrentInstance = inst; + ctx.CurrentCollection = inst; + + object parentCollection = ctx.ParentCollection ?? inst; + + foreach (string length in value.Split(new[] { ' ', ',' }, StringSplitOptions.RemoveEmptyEntries)) + { + // push frame to hold instance of new object to add + ctx.PushScope(); + object currentValue = typeConverter.ConvertFrom(length.Trim()); + ctx.CurrentType = collectionItemType; + ctx.CurrentInstance = currentValue; + Runtime.Add(parentCollection, propertyType, currentValue, collectionItemType); + ctx.PopScope(); + } + ctx.PopScope(); + ctx.CurrentInstance = parentCollection; + return false; + } + // For backcompat with 3.x parser, if the compat flag PreferUnconvertedKeys is set, // we don't convert keys if the dictionary implements non-generic IDictionary, unless: // - we've already failed calling IDictionary.Add on this same instance, or