Browse Source

Log warnings for converter exceptions.

refactor/bindingexpressions-in-valuestore
Steven Kirk 3 years ago
parent
commit
c4b652016a
  1. 11
      src/Avalonia.Base/Data/Core/BindingExpression.cs
  2. 38
      tests/Avalonia.Markup.UnitTests/Data/BindingTests_Logging.cs

11
src/Avalonia.Base/Data/Core/BindingExpression.cs

@ -8,6 +8,7 @@ using Avalonia.Data.Converters;
using Avalonia.Data.Core.ExpressionNodes;
using Avalonia.Data.Core.Parsers;
using Avalonia.Logging;
using static Avalonia.Rendering.Composition.Animations.PropertySetSnapshot;
namespace Avalonia.Data.Core;
@ -540,7 +541,7 @@ internal class BindingExpression : IObservable<object?>,
}
}
private static object? Convert(
private object? Convert(
IValueConverter converter,
object? converterParameter,
object? value,
@ -554,8 +555,12 @@ internal class BindingExpression : IObservable<object?>,
{
var valueString = value?.ToString() ?? "(null)";
var valueTypeName = value?.GetType().FullName ?? "null";
var ex = new InvalidCastException(
$"Could not convert '{valueString}' ({valueTypeName}) to {targetType} using '{converter}'.", e);
var message = $"Could not convert '{valueString}' ({valueTypeName}) to '{targetType}' using '{converter}'";
if (ShouldLogError(out var target))
Log(target, $"{message}: {e.Message}", LogEventLevel.Warning);
var ex = new InvalidCastException(message + '.', e);
return new BindingNotification(ex, BindingErrorType.Error);
}
}

38
tests/Avalonia.Markup.UnitTests/Data/BindingTests_Logging.cs

@ -1,7 +1,10 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using Avalonia.Controls;
using Avalonia.Controls.Converters;
using Avalonia.Data;
using Avalonia.Data.Converters;
using Avalonia.Data.Core;
using Avalonia.Data.Core.Plugins.Reflection;
using Avalonia.Input;
@ -248,6 +251,28 @@ namespace Avalonia.Markup.UnitTests.Data
target.Bind(Control.MarginProperty, binding);
}
}
[Fact]
public void Should_Log_Error_For_Unconvertible_Type_With_Converter()
{
var target = new Decorator { DataContext = new { Foo = new System.Version() } };
var root = new TestRoot(target);
var binding = new Binding("Foo")
{
Converter = new ThrowingConverter(),
};
using (AssertLog(
target,
binding.Path,
"Could not convert '0.0' (System.Version) to 'Avalonia.Thickness' " +
"using 'Avalonia.Markup.UnitTests.Data.BindingTests_Logging+ThrowingConverter': " +
"The method or operation is not implemented.",
property: Control.MarginProperty))
{
target.Bind(Control.MarginProperty, binding);
}
}
}
public class Fallback
@ -447,6 +472,19 @@ namespace Avalonia.Markup.UnitTests.Data
public string? Foo { get; set; }
}
private class ThrowingConverter : IValueConverter
{
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
private record LogMessage(LogEventLevel level, string area, object source, string messageTemplate, params object[] propertyValues);
}
}

Loading…
Cancel
Save