csharpc-sharpdotnetxamlavaloniauicross-platformcross-platform-xamlavaloniaguimulti-platformuser-interfacedotnetcore
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.
284 lines
7.9 KiB
284 lines
7.9 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Reactive.Linq;
|
|
using Avalonia.Controls;
|
|
using Avalonia.Data;
|
|
using Avalonia.Data.Converters;
|
|
using Avalonia.Data.Core;
|
|
using Avalonia.UnitTests;
|
|
using Xunit;
|
|
|
|
#nullable enable
|
|
|
|
namespace Avalonia.Base.UnitTests.Data.Core
|
|
{
|
|
public class BindingExpressionTests_SetValue
|
|
{
|
|
[Fact]
|
|
public void Should_Set_Simple_Property_Value()
|
|
{
|
|
var data = new Person { Name = "Frank" };
|
|
var target = BindingExpression.Create(data, o => o.Name);
|
|
|
|
using (target.ToObservable().Subscribe(_ => { }))
|
|
{
|
|
target.WriteValueToSource("Kups");
|
|
}
|
|
|
|
Assert.Equal("Kups", data.Name);
|
|
}
|
|
|
|
[Fact]
|
|
public void Should_Set_Attached_Property_Value()
|
|
{
|
|
var data = new AvaloniaObject();
|
|
var target = BindingExpression.Create(data, o => o[DockPanel.DockProperty]);
|
|
|
|
using (target.ToObservable().Subscribe(_ => { }))
|
|
{
|
|
target.WriteValueToSource(Dock.Right);
|
|
}
|
|
|
|
Assert.Equal(Dock.Right, data[DockPanel.DockProperty]);
|
|
}
|
|
|
|
[Fact]
|
|
public void Should_Set_Indexed_Value()
|
|
{
|
|
var data = new { Foo = new[] { "foo" } };
|
|
var target = BindingExpression.Create(data, o => o.Foo[0]);
|
|
|
|
using (target.ToObservable().Subscribe(_ => { }))
|
|
{
|
|
target.WriteValueToSource("bar");
|
|
}
|
|
|
|
Assert.Equal("bar", data.Foo[0]);
|
|
|
|
GC.KeepAlive(data);
|
|
}
|
|
|
|
[Fact]
|
|
public void Should_Set_Value_On_Simple_Property_Chain()
|
|
{
|
|
var data = new Person { Pet = new Dog { Name = "Fido" } };
|
|
var target = BindingExpression.Create(data, o => o.Pet!.Name);
|
|
|
|
using (target.ToObservable().Subscribe(_ => { }))
|
|
{
|
|
target.WriteValueToSource("Rover");
|
|
}
|
|
|
|
Assert.Equal("Rover", data.Pet.Name);
|
|
}
|
|
|
|
[Fact]
|
|
public void Should_Not_Try_To_Set_Value_On_Broken_Chain()
|
|
{
|
|
var data = new Person { Pet = new Dog { Name = "Fido" } };
|
|
var target = BindingExpression.Create(data, o => o.Pet!.Name);
|
|
|
|
// Ensure the UntypedBindingExpression's subscriptions are kept active.
|
|
using (target.ToObservable()!.OfType<string?>().Subscribe(x => { }))
|
|
{
|
|
data.Pet = null;
|
|
Assert.False(target.WriteValueToSource("Rover"));
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void SetValue_Should_Return_False_For_Missing_Property()
|
|
{
|
|
var data = new Person { Pet = new Cat() };
|
|
var target = BindingExpression.Create(data, o => (o.Pet as Dog)!.IsBarky);
|
|
|
|
using (target.ToObservable().Subscribe(_ => { }))
|
|
{
|
|
Assert.False(target.WriteValueToSource("baz"));
|
|
}
|
|
|
|
GC.KeepAlive(data);
|
|
}
|
|
|
|
[Fact]
|
|
public void SetValue_Should_Notify_New_Value_With_Inpc()
|
|
{
|
|
var data = new Person();
|
|
var target = BindingExpression.Create(data, o => o.Name);
|
|
var result = new List<object?>();
|
|
|
|
target.ToObservable().Subscribe(result.Add);
|
|
target.WriteValueToSource("Frank");
|
|
|
|
Assert.Equal(new[] { null, "Frank" }, result);
|
|
|
|
GC.KeepAlive(data);
|
|
}
|
|
|
|
[Fact]
|
|
public void SetValue_Should_Notify_New_Value_Without_Inpc()
|
|
{
|
|
var data = new Snail();
|
|
var target = BindingExpression.Create(data, o => o.Name);
|
|
var result = new List<object?>();
|
|
|
|
target.ToObservable().Subscribe(result.Add);
|
|
target.WriteValueToSource("Frank");
|
|
|
|
Assert.Equal(new[] { null, "Frank" }, result);
|
|
|
|
GC.KeepAlive(data);
|
|
}
|
|
|
|
[Fact]
|
|
public void SetValue_Should_Return_False_For_Missing_Object()
|
|
{
|
|
var data = new Person();
|
|
var target = BindingExpression.Create(data, o => (o.Pet as Dog)!.Name);
|
|
|
|
using (target.ToObservable().Subscribe(_ => { }))
|
|
{
|
|
Assert.False(target.WriteValueToSource("Fido"));
|
|
}
|
|
|
|
GC.KeepAlive(data);
|
|
}
|
|
|
|
[Fact]
|
|
public void SetValue_Should_Use_Converter()
|
|
{
|
|
var data = new Person { Name = "Frank" };
|
|
var target = BindingExpression.Create(
|
|
data,
|
|
o => o.Name,
|
|
converter: new CaseConverter());
|
|
|
|
using (target.ToObservable().Subscribe(_ => { }))
|
|
{
|
|
Assert.True(target.WriteValueToSource("Kups"));
|
|
}
|
|
|
|
Assert.Equal("kups", data.Name);
|
|
|
|
GC.KeepAlive(data);
|
|
}
|
|
|
|
[Fact]
|
|
public void TwoWay_Binding_Should_Not_Write_Unchanged_Value_Back_To_Property_With_Converter()
|
|
{
|
|
var data = new Cat();
|
|
var control = new Control();
|
|
var target = BindingExpression.Create(
|
|
data,
|
|
o => o.WhiskerCount,
|
|
converter: new CaseConverter(),
|
|
mode: BindingMode.TwoWay);
|
|
var instance = new InstancedBinding(
|
|
target,
|
|
BindingMode.TwoWay,
|
|
BindingPriority.LocalValue);
|
|
|
|
BindingOperations.Apply(control, Visual.OpacityProperty, instance);
|
|
|
|
Assert.Equal(4, control.Opacity);
|
|
Assert.Equal(9, data.Lives);
|
|
|
|
data.WhiskerCount = 3;
|
|
|
|
Assert.Equal(3, control.Opacity);
|
|
Assert.Equal(8, data.Lives);
|
|
|
|
GC.KeepAlive(data);
|
|
}
|
|
|
|
private interface IAnimal
|
|
{
|
|
string? Name { get; }
|
|
}
|
|
|
|
private class Person : NotifyingBase
|
|
{
|
|
private string? _name;
|
|
private IAnimal? _pet;
|
|
|
|
public string? Name
|
|
{
|
|
get => _name;
|
|
set
|
|
{
|
|
_name = value;
|
|
RaisePropertyChanged(nameof(Name));
|
|
}
|
|
}
|
|
|
|
public IAnimal? Pet
|
|
{
|
|
get => _pet;
|
|
set
|
|
{
|
|
_pet = value;
|
|
RaisePropertyChanged(nameof(Pet));
|
|
}
|
|
}
|
|
}
|
|
|
|
private class Animal : NotifyingBase, IAnimal
|
|
{
|
|
private string? _name;
|
|
|
|
public string? Name
|
|
{
|
|
get => _name;
|
|
set
|
|
{
|
|
_name = value;
|
|
RaisePropertyChanged(nameof(Name));
|
|
}
|
|
}
|
|
}
|
|
|
|
private class Dog : Animal
|
|
{
|
|
public bool IsBarky { get; set; }
|
|
}
|
|
|
|
private class Cat : Animal
|
|
{
|
|
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 Snail : IAnimal
|
|
{
|
|
public string? Name { get; set; }
|
|
}
|
|
|
|
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();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|