diff --git a/.ncrunch/Avalonia.FreeDesktop.net6.0.v3.ncrunchproject b/.ncrunch/Avalonia.FreeDesktop.net6.0.v3.ncrunchproject
new file mode 100644
index 0000000000..319cd523ce
--- /dev/null
+++ b/.ncrunch/Avalonia.FreeDesktop.net6.0.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.FreeDesktop.netstandard2.0.v3.ncrunchproject b/.ncrunch/Avalonia.FreeDesktop.netstandard2.0.v3.ncrunchproject
new file mode 100644
index 0000000000..319cd523ce
--- /dev/null
+++ b/.ncrunch/Avalonia.FreeDesktop.netstandard2.0.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Themes.Simple.net6.0.v3.ncrunchproject b/.ncrunch/Avalonia.Themes.Simple.net6.0.v3.ncrunchproject
index 02eb0d211e..bc1af9a143 100644
--- a/.ncrunch/Avalonia.Themes.Simple.net6.0.v3.ncrunchproject
+++ b/.ncrunch/Avalonia.Themes.Simple.net6.0.v3.ncrunchproject
@@ -1,5 +1,8 @@
+
+ ..\Avalonia.Themes.Fluent\Strings\InvariantResources.xaml
+
False
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.Themes.Simple.netstandard2.0.v3.ncrunchproject b/.ncrunch/Avalonia.Themes.Simple.netstandard2.0.v3.ncrunchproject
index 02eb0d211e..bc1af9a143 100644
--- a/.ncrunch/Avalonia.Themes.Simple.netstandard2.0.v3.ncrunchproject
+++ b/.ncrunch/Avalonia.Themes.Simple.netstandard2.0.v3.ncrunchproject
@@ -1,5 +1,8 @@
+
+ ..\Avalonia.Themes.Fluent\Strings\InvariantResources.xaml
+
False
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.X11.net6.0.v3.ncrunchproject b/.ncrunch/Avalonia.X11.net6.0.v3.ncrunchproject
new file mode 100644
index 0000000000..319cd523ce
--- /dev/null
+++ b/.ncrunch/Avalonia.X11.net6.0.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/.ncrunch/Avalonia.X11.netstandard2.0.v3.ncrunchproject b/.ncrunch/Avalonia.X11.netstandard2.0.v3.ncrunchproject
new file mode 100644
index 0000000000..319cd523ce
--- /dev/null
+++ b/.ncrunch/Avalonia.X11.netstandard2.0.v3.ncrunchproject
@@ -0,0 +1,5 @@
+
+
+ True
+
+
\ No newline at end of file
diff --git a/src/Avalonia.Base/Data/Core/TargetTypeConverter.cs b/src/Avalonia.Base/Data/Core/TargetTypeConverter.cs
index f633094860..7a4b0544bd 100644
--- a/src/Avalonia.Base/Data/Core/TargetTypeConverter.cs
+++ b/src/Avalonia.Base/Data/Core/TargetTypeConverter.cs
@@ -5,6 +5,7 @@ using Avalonia.Data.Converters;
using System.Windows.Input;
using Avalonia.Utilities;
using static Avalonia.Utilities.TypeUtilities;
+using System.ComponentModel;
namespace Avalonia.Data.Core;
@@ -65,6 +66,40 @@ internal abstract class TargetTypeConverter
return true;
}
+#pragma warning disable IL2026
+#pragma warning disable IL2067
+ // TODO: TypeConverters are not trimming friendly in some edge cases, we probably need
+ // to make compiled bindings emit conversion code at compile-time.
+ var toTypeConverter = TypeDescriptor.GetConverter(t);
+ var from = value.GetType();
+
+ if (toTypeConverter.CanConvertFrom(from))
+ {
+ result = toTypeConverter.ConvertFrom(null, culture, value);
+ return true;
+ }
+
+ var fromTypeConverter = TypeDescriptor.GetConverter(from);
+
+ if (fromTypeConverter.CanConvertTo(t))
+ {
+ result = fromTypeConverter.ConvertTo(null, culture, value, t);
+ return true;
+ }
+
+ // TODO: This requires reflection: we probably need to make compiled bindings emit
+ // conversion code at compile-time.
+ if (FindTypeConversionOperatorMethod(
+ value.GetType(),
+ t,
+ OperatorType.Implicit | OperatorType.Explicit) is { } cast)
+ {
+ result = cast.Invoke(null, new[] { value });
+ return true;
+ }
+#pragma warning restore IL2067
+#pragma warning restore IL2026
+
if (value is IConvertible convertible)
{
try
@@ -79,17 +114,6 @@ internal abstract class TargetTypeConverter
}
}
- // TODO: This requires reflection: we probably need to make compiled bindings emit
- // conversion code at compile-time.
- if (FindTypeConversionOperatorMethod(
- value.GetType(),
- t,
- OperatorType.Implicit | OperatorType.Explicit) is { } cast)
- {
- result = cast.Invoke(null, new[] { value });
- return true;
- }
-
result = null;
return false;
}
diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests.cs
index afc4a36fea..f724bf5f1c 100644
--- a/tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests.cs
+++ b/tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests.cs
@@ -6,6 +6,8 @@ using Avalonia.Controls;
using Avalonia.Controls.Presenters;
using Avalonia.Data;
using Avalonia.Data.Converters;
+using Avalonia.Media;
+using Avalonia.Media.Immutable;
using Avalonia.UnitTests;
using Avalonia.VisualTree;
using Xunit;
@@ -94,6 +96,28 @@ namespace Avalonia.Markup.Xaml.UnitTests.Data
Assert.Equal("Foo,Bar", target.Text);
}
}
+
+ [Fact]
+ public void Can_Bind_Brush_to_Hex_String()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var xaml = @"
+
+
+";
+ var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
+ var border = (Border)window.Content;
+ window.DataContext = new { HexString = "#ff0000" };
+
+ window.ApplyTemplate();
+
+ var brush = Assert.IsType(border.Background);
+ Assert.Equal(Colors.Red, brush.Color);
+ }
+ }
}
public class ConcatConverter : IMultiValueConverter
diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs
index 7c7b8bcb00..c2cec8cf79 100644
--- a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs
+++ b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs
@@ -24,6 +24,7 @@ using Avalonia.Markup.Xaml.MarkupExtensions;
using Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings;
using Avalonia.Markup.Xaml.Templates;
using Avalonia.Media;
+using Avalonia.Media.Immutable;
using Avalonia.Metadata;
using Avalonia.UnitTests;
using Xunit;
@@ -2022,6 +2023,30 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
}
}
+ [Fact]
+ public void Can_Bind_Brush_To_Hex_String()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ var xaml = $@"
+
+
+";
+ var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
+ var textBlock = window.FindControl("textBlock");
+
+ var dataContext = new TestData { StringProperty = "#ff0000" };
+ window.DataContext = dataContext;
+
+ var brush = Assert.IsType(textBlock!.Background);
+ Assert.Equal(Colors.Red, brush.Color);
+ }
+ }
+
static void Throws(string type, Action cb)
{
try