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