Browse Source

Merge pull request #8905 from AvaloniaUI/fix-unpredictable-choice-between-methods-when-using-method-binding

Fix unpredictable choice between methods when using method binding.
pull/8920/head
Max Katz 4 years ago
committed by GitHub
parent
commit
d7924d1bff
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 15
      src/Avalonia.Base/Data/Core/Plugins/MethodAccessorPlugin.cs
  2. 13
      tests/Avalonia.Markup.UnitTests/Parsers/ExpressionObserverBuilderTests_Method.cs
  3. 26
      tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests_Method.cs

15
src/Avalonia.Base/Data/Core/Plugins/MethodAccessorPlugin.cs

@ -55,13 +55,20 @@ namespace Avalonia.Data.Core.Plugins
var methods = type.GetMethods(bindingFlags); var methods = type.GetMethods(bindingFlags);
foreach (MethodInfo methodInfo in methods) foreach (var methodInfo in methods)
{ {
if (methodInfo.Name == methodName) if (methodInfo.Name == methodName)
{ {
found = methodInfo; var parameters = methodInfo.GetParameters();
if (parameters.Length == 1 && parameters[0].ParameterType == typeof(object))
break; {
found = methodInfo;
break;
}
else if (parameters.Length == 0)
{
found = methodInfo;
}
} }
} }

13
tests/Avalonia.Markup.UnitTests/Parsers/ExpressionObserverBuilderTests_Method.cs

@ -19,12 +19,9 @@ namespace Avalonia.Markup.UnitTests.Parsers
public int MethodWithReturn() => 0; public int MethodWithReturn() => 0;
public int MethodWithReturnAndParameters(int i) => i; public int MethodWithReturnAndParameter(object i) => (int)i;
public static void StaticMethod() { } public static void StaticMethod() { }
public static void ManyParameters(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9) { }
public static int ManyParametersWithReturnType(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) => 1;
} }
[Fact] [Fact]
@ -42,10 +39,8 @@ namespace Avalonia.Markup.UnitTests.Parsers
[Theory] [Theory]
[InlineData(nameof(TestObject.MethodWithoutReturn), typeof(Action))] [InlineData(nameof(TestObject.MethodWithoutReturn), typeof(Action))]
[InlineData(nameof(TestObject.MethodWithReturn), typeof(Func<int>))] [InlineData(nameof(TestObject.MethodWithReturn), typeof(Func<int>))]
[InlineData(nameof(TestObject.MethodWithReturnAndParameters), typeof(Func<int, int>))] [InlineData(nameof(TestObject.MethodWithReturnAndParameter), typeof(Func<object, int>))]
[InlineData(nameof(TestObject.StaticMethod), typeof(Action))] [InlineData(nameof(TestObject.StaticMethod), typeof(Action))]
[InlineData(nameof(TestObject.ManyParameters), typeof(Action<int, int, int, int, int, int, int, int, int>))]
[InlineData(nameof(TestObject.ManyParametersWithReturnType), typeof(Func<int, int, int, int, int, int, int, int, int>))]
public async Task Should_Get_Method_WithCorrectDelegateType(string methodName, Type expectedType) public async Task Should_Get_Method_WithCorrectDelegateType(string methodName, Type expectedType)
{ {
var data = new TestObject(); var data = new TestObject();
@ -61,10 +56,10 @@ namespace Avalonia.Markup.UnitTests.Parsers
public async Task Can_Call_Method_Returned_From_Observer() public async Task Can_Call_Method_Returned_From_Observer()
{ {
var data = new TestObject(); var data = new TestObject();
var observer = ExpressionObserverBuilder.Build(data, nameof(TestObject.MethodWithReturnAndParameters)); var observer = ExpressionObserverBuilder.Build(data, nameof(TestObject.MethodWithReturnAndParameter));
var result = await observer.Take(1); var result = await observer.Take(1);
var callback = (Func<int, int>)result; var callback = (Func<object, int>)result;
Assert.Equal(1, callback(1)); Assert.Equal(1, callback(1));

26
tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests_Method.cs

@ -141,6 +141,28 @@ namespace Avalonia.Markup.Xaml.UnitTests.Data
} }
} }
[Fact]
public void Binding_Method_Preserves_Correct_Order()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
<Window xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'>
<Button Name='button' Command='{Binding Method3}' CommandParameter='5'/>
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var button = window.FindControl<Button>("button");
var vm = new ViewModel();
button.DataContext = vm;
window.ApplyTemplate();
PerformClick(button);
Assert.Equal("Called Method with parameter of object type. Argument value is 5", vm.Value);
}
}
[Fact] [Fact]
public void Binding_Method_To_Command_Collected() public void Binding_Method_To_Command_Collected()
{ {
@ -198,8 +220,10 @@ namespace Avalonia.Markup.Xaml.UnitTests.Data
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler PropertyChanged;
public string Method() => Value = "Called"; public string Method() => Value = "Called";
public string Method1(int i) => Value = $"Called {i}"; public string Method1(object i) => Value = $"Called {i}";
public string Method2(int i, int j) => Value = $"Called {i},{j}"; public string Method2(int i, int j) => Value = $"Called {i},{j}";
public string Method3() => Value = "Called";
public string Method3(object obj) => Value = $"Called Method with parameter of object type. Argument value is {obj}";
public string Value { get; private set; } = "Not called"; public string Value { get; private set; } = "Not called";
object _parameter; object _parameter;

Loading…
Cancel
Save