A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

232 lines
6.1 KiB

using System;
using System.Globalization;
using Avalonia.Controls;
using Avalonia.Data;
using Avalonia.Data.Converters;
using Avalonia.UnitTests;
using Xunit;
#nullable enable
namespace Avalonia.Base.UnitTests.Data.Core;
public abstract partial class BindingExpressionTests
{
[Fact]
public void Should_Write_Value_To_Source()
{
var data = new ViewModel { StringValue = "foo" };
var target = CreateTargetWithSource(data, o => o.StringValue, mode: BindingMode.TwoWay);
target.String = "bar";
Assert.Equal("bar", data.StringValue);
}
[Fact]
public void Should_Write_Value_To_Attached_Property_On_Source()
{
var data = new AvaloniaObject();
var target = CreateTargetWithSource(
data,
o => o[DockPanel.DockProperty],
mode: BindingMode.TwoWay,
targetProperty: Control.TagProperty);
target.Tag = Dock.Right;
Assert.Equal(Dock.Right, data[DockPanel.DockProperty]);
}
[Fact]
public void Should_Write_Indexed_Value_To_Source()
{
var data = new { Foo = new[] { "foo" } };
var target = CreateTargetWithSource(data, o => o.Foo[0], mode: BindingMode.TwoWay);
target.String = "bar";
Assert.Equal("bar", data.Foo[0]);
GC.KeepAlive(data);
}
[Fact]
public void Should_Write_Value_To_Source_On_Simple_Property_Chain()
{
var data = new ViewModel { Next = new() { StringValue = "foo" } };
var target = CreateTargetWithSource(data, o => o.Next!.StringValue, mode: BindingMode.TwoWay);
target.String = "bar";
Assert.Equal("bar", data.Next!.StringValue);
}
[Fact]
public void Target_Value_Can_Be_Set_On_Broken_Chain()
{
var data = new ViewModel { Next = new() { StringValue = "foo" } };
var target = CreateTargetWithSource(data, o => o.Next!.StringValue, mode: BindingMode.TwoWay);
data.Next = null;
target.String = "bar";
Assert.Equal("bar", target.String);
}
[Fact]
public void Should_Use_Converter_When_Writing_To_Source()
{
var data = new ViewModel { StringValue = "foo" };
var target = CreateTargetWithSource(
data,
o => o.StringValue,
mode: BindingMode.TwoWay,
converter: new CaseConverter());
target.String = "BaR";
Assert.Equal("bar", data.StringValue);
GC.KeepAlive(data);
}
[Fact]
public void TwoWay_Binding_Should_Not_Write_Unchanged_Value_Back_To_Property_With_Converter()
{
var data = new Cat();
var target = CreateTargetWithSource(
data,
o => o.WhiskerCount,
converter: new CaseConverter(),
mode: BindingMode.TwoWay);
Assert.Equal(4, target.Int);
Assert.Equal(9, data.Lives);
data.WhiskerCount = 3;
Assert.Equal(3, target.Int);
Assert.Equal(8, data.Lives);
GC.KeepAlive(data);
}
[Fact]
public void Setter_Should_Convert_Double_To_String()
{
var data = new ViewModel { StringValue = $"{5.6}" };
var target = CreateTargetWithSource(
data,
o => o.StringValue,
mode: BindingMode.TwoWay,
targetProperty: TargetClass.DoubleProperty);
target.Double = 6.7;
Assert.Equal($"{6.7}", data.StringValue);
GC.KeepAlive(data);
}
[Fact]
public void Setter_Should_Convert_String_To_Double()
{
var data = new ViewModel { DoubleValue = 5.6 };
var target = CreateTargetWithSource(
data,
o => o.DoubleValue,
mode: BindingMode.TwoWay,
targetProperty: TargetClass.StringProperty);
target.String = $"{6.7}";
Assert.Equal(6.7, data.DoubleValue);
GC.KeepAlive(data);
}
[Fact]
public void Setting_Invalid_Double_String_Should_Not_Change_Target()
{
var data = new ViewModel { DoubleValue = 5.6 };
var target = CreateTargetWithSource(
data,
o => o.DoubleValue,
mode: BindingMode.TwoWay,
targetProperty: TargetClass.StringProperty);
target.String = "foo";
Assert.Equal(5.6, data.DoubleValue);
GC.KeepAlive(data);
}
[Fact]
public void Setting_Invalid_Double_String_Should_Use_FallbackValue()
{
var data = new ViewModel { DoubleValue = 5.6 };
var target = CreateTargetWithSource(
data,
o => o.DoubleValue,
mode: BindingMode.TwoWay,
fallbackValue: 9.8,
targetProperty: TargetClass.StringProperty);
target.String = "foo";
Assert.Equal(9.8, data.DoubleValue);
GC.KeepAlive(data);
}
[Fact]
public void Should_Pass_ConverterParameter_To_Converter_ConvertBack()
{
var data = new ViewModel { StringValue = "Initial" };
var converter = new PrefixConverter();
var target = CreateTargetWithSource(
data,
o => o.StringValue,
converter: converter,
converterParameter: "foo",
mode: BindingMode.TwoWay);
target.String = "fooBar";
Assert.Equal("Bar", data.StringValue);
}
private class Cat : NotifyingBase
{
private int _whiskerCount = 4;
public int WhiskerCount
{
get => _whiskerCount;
set
{
_whiskerCount = value;
RaisePropertyChanged(nameof(WhiskerCount));
--Lives;
}
}
public int Lives { get; private set; } = 9;
}
private class CaseConverter : IValueConverter
{
public static readonly CaseConverter Instance = new();
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
return value?.ToString()?.ToUpper();
}
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
return value?.ToString()?.ToLower();
}
}
}