diff --git a/src/Avalonia.Base/PropertyStore/BindingEntry.cs b/src/Avalonia.Base/PropertyStore/BindingEntry.cs index e3240952cb..d86caa250f 100644 --- a/src/Avalonia.Base/PropertyStore/BindingEntry.cs +++ b/src/Avalonia.Base/PropertyStore/BindingEntry.cs @@ -89,6 +89,7 @@ namespace Avalonia.PropertyStore if (value is BindingNotification n) { value = n.Value; + LoggingUtils.LogIfNecessary(_frame.Owner.Owner, Property, n); } if (value == AvaloniaProperty.UnsetValue) diff --git a/src/Avalonia.Base/PropertyStore/LocalValueUntypedBindingObserver.cs b/src/Avalonia.Base/PropertyStore/LocalValueUntypedBindingObserver.cs index 8a745482e7..099e997d38 100644 --- a/src/Avalonia.Base/PropertyStore/LocalValueUntypedBindingObserver.cs +++ b/src/Avalonia.Base/PropertyStore/LocalValueUntypedBindingObserver.cs @@ -37,6 +37,7 @@ namespace Avalonia.PropertyStore if (value is BindingNotification n) { value = n.Value; + LoggingUtils.LogIfNecessary(_owner.Owner, Property, n); } if (value == AvaloniaProperty.UnsetValue) diff --git a/src/Avalonia.Base/PropertyStore/LoggingUtils.cs b/src/Avalonia.Base/PropertyStore/LoggingUtils.cs index ecb3a847c1..cb11a5e87c 100644 --- a/src/Avalonia.Base/PropertyStore/LoggingUtils.cs +++ b/src/Avalonia.Base/PropertyStore/LoggingUtils.cs @@ -1,12 +1,21 @@ using System; using System.Runtime.CompilerServices; using Avalonia.Data; -using Avalonia.Logging; namespace Avalonia.PropertyStore { internal static class LoggingUtils { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void LogIfNecessary( + AvaloniaObject owner, + AvaloniaProperty property, + BindingNotification value) + { + if (value.ErrorType != BindingErrorType.None) + Log(owner, property, value.Error!); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void LogIfNecessary( AvaloniaObject owner, @@ -45,6 +54,19 @@ namespace Avalonia.PropertyStore } } + private static void Log( + AvaloniaObject owner, + AvaloniaProperty property, + Exception e) + { + owner.GetBindingWarningLogger(property, e)?.Log( + owner, + "Error in binding to {Target}.{Property}: {Message}", + owner, + property, + e.Message); + } + private static void Log( AvaloniaObject owner, AvaloniaProperty property, diff --git a/src/Avalonia.Base/PropertyStore/UntypedBindingEntry.cs b/src/Avalonia.Base/PropertyStore/UntypedBindingEntry.cs index 890b4424fb..82c5ff6c1a 100644 --- a/src/Avalonia.Base/PropertyStore/UntypedBindingEntry.cs +++ b/src/Avalonia.Base/PropertyStore/UntypedBindingEntry.cs @@ -113,6 +113,7 @@ namespace Avalonia.PropertyStore if (value is BindingNotification n) { value = n.Value; + LoggingUtils.LogIfNecessary(_frame.Owner.Owner, Property, n); } if (value == AvaloniaProperty.UnsetValue) diff --git a/tests/Avalonia.Base.UnitTests/VisualTests.cs b/tests/Avalonia.Base.UnitTests/VisualTests.cs index 382001229b..8dff5a6f61 100644 --- a/tests/Avalonia.Base.UnitTests/VisualTests.cs +++ b/tests/Avalonia.Base.UnitTests/VisualTests.cs @@ -281,13 +281,17 @@ namespace Avalonia.Base.UnitTests { var target = new Decorator(); var root = new TestRoot { Child = target, DataContext = "foo" }; - var called = false; + var called = 0; LogCallback checkLogMessage = (level, area, src, mt, pv) => { if (level >= Avalonia.Logging.LogEventLevel.Warning) { - called = true; + Assert.Equal("Error in binding to {Target}.{Property}: {Message}", mt); + Assert.Same(target, pv[0]); + Assert.Equal(Decorator.TagProperty, pv[1]); + Assert.Equal("Could not find a matching property accessor for 'Foo' on 'foo'", pv[2]); + ++called; } }; @@ -296,7 +300,7 @@ namespace Avalonia.Base.UnitTests target.Bind(Decorator.TagProperty, new Binding("Foo")); } - Assert.True(called); + Assert.Equal(1, called); } [Fact]