#nullable enable
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Reactive.Subjects;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System.Xml;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Templates;
using Avalonia.Data;
using Avalonia.Data.Converters;
using Avalonia.Data.Core;
using Avalonia.Input;
using Avalonia.Markup.Data;
using Avalonia.Markup.Xaml.MarkupExtensions;
using Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings;
using Avalonia.Markup.Xaml.Templates;
using Avalonia.Media;
using Avalonia.Media.Immutable;
using Avalonia.Metadata;
using Avalonia.UnitTests;
using Xunit;
namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
{
public class CompiledBindingExtensionTests
{
static CompiledBindingExtensionTests()
{
RuntimeHelpers.RunClassConstructor(typeof(RelativeSource).TypeHandle);
}
[Fact]
public void ResolvesClrPropertyBasedOnDataContextType()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.GetControl("textBlock");
var dataContext = new TestDataContext
{
StringProperty = "foobar"
};
window.DataContext = dataContext;
Assert.Equal(dataContext.StringProperty, textBlock.Text);
}
}
[Fact]
public void ResolvesClrPropertyBasedOnDataContextType_InterfaceInheritance()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.GetControl("textBlock");
var dataContext = new TestDataContext
{
StringProperty = "foobar"
};
window.DataContext = dataContext;
Assert.Equal(dataContext.StringProperty, textBlock.Text);
}
}
[Fact]
public void ResolvesPathPassedByProperty()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.GetControl("textBlock");
var dataContext = new TestDataContext
{
StringProperty = "foobar"
};
window.DataContext = dataContext;
Assert.Equal(dataContext.StringProperty, textBlock.Text);
}
}
[Fact]
public void ResolvesPathPassedByPropertyWithInnerItemTemplate()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.GetControl("itemsControl");
var dataContext = new TestDataContext
{
ListProperty =
{
"Hello"
}
};
window.DataContext = dataContext;
Assert.Equal(dataContext.ListProperty, textBlock.ItemsSource);
}
}
[Fact]
public void ResolvesStaticClrPropertyBased()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.GetControl("textBlock");
textBlock.DataContext = new TestDataContext();
Assert.Equal(TestDataContext.StaticProperty, textBlock.Text);
}
}
[Fact]
public void ResolvesDataTypeFromBindingProperty()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.GetControl("textBlock");
var dataContext = new TestDataContext
{
StringProperty = "foobar"
};
window.DataContext = dataContext;
Assert.Equal(dataContext.StringProperty, textBlock.Text);
}
}
[Fact]
public void ResolvesDataTypeFromBindingProperty_TypeExtension()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.GetControl("textBlock");
var dataContext = new TestDataContext
{
StringProperty = "foobar"
};
window.DataContext = dataContext;
Assert.Equal(dataContext.StringProperty, textBlock.Text);
}
}
[Fact]
public void ResolvesStreamTaskBindingCorrectly()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.GetControl("textBlock");
var dataContext = new TestDataContext
{
TaskProperty = Task.FromResult("foobar")
};
window.DataContext = dataContext;
Assert.Equal(dataContext.TaskProperty.Result, textBlock.Text);
}
}
[Fact]
public void ResolvesStreamObservableBindingCorrectly()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.GetControl("textBlock");
DelayedBinding.ApplyBindings(textBlock);
var subject = new Subject();
var dataContext = new TestDataContext
{
ObservableProperty = subject
};
window.DataContext = dataContext;
subject.OnNext("foobar");
Assert.Equal("foobar", textBlock.Text);
}
}
[Fact]
public void ResolvesIndexerBindingCorrectly()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.GetControl("textBlock");
var dataContext = new TestDataContext
{
ListProperty = { "A", "B", "C", "D", "E" }
};
window.DataContext = dataContext;
Assert.Equal(dataContext.ListProperty[3], textBlock.Text);
}
}
[Fact]
public void ResolvesArrayIndexerBindingCorrectly()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.GetControl("textBlock");
var dataContext = new TestDataContext
{
ArrayProperty = new[] { "A", "B", "C", "D", "E" }
};
window.DataContext = dataContext;
Assert.Equal(dataContext.ArrayProperty[3], textBlock.Text);
}
}
[Fact]
public void ResolvesObservableIndexerBindingCorrectly()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.GetControl("textBlock");
var dataContext = new TestDataContext
{
ObservableCollectionProperty = { "A", "B", "C", "D", "E" }
};
window.DataContext = dataContext;
Assert.Equal(dataContext.ObservableCollectionProperty[3], textBlock.Text);
dataContext.ObservableCollectionProperty[3] = "New Value";
Assert.Equal(dataContext.ObservableCollectionProperty[3], textBlock.Text);
}
}
[Fact]
public void InfersCompiledBindingDataContextFromDataContextBinding()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.GetControl("textBlock");
window.ApplyTemplate();
window.Presenter!.ApplyTemplate();
var dataContext = new TestDataContext
{
StringProperty = "A"
};
window.DataContext = dataContext;
Assert.Equal(dataContext.StringProperty, textBlock.Text);
}
}
[Fact]
public void ResolvesNonIntegerIndexerBindingCorrectly()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.GetControl("textBlock");
var dataContext = new TestDataContext();
dataContext.NonIntegerIndexerProperty["Test"] = "Initial Value";
window.DataContext = dataContext;
Assert.Equal(dataContext.NonIntegerIndexerProperty["Test"], textBlock.Text);
dataContext.NonIntegerIndexerProperty["Test"] = "New Value";
Assert.Equal(dataContext.NonIntegerIndexerProperty["Test"], textBlock.Text);
}
}
[Fact]
public void ResolvesNonIntegerIndexerBindingFromParentInterfaceCorrectly()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.GetControl("textBlock");
var dataContext = new TestDataContext();
dataContext.NonIntegerIndexerInterfaceProperty["Test"] = "Initial Value";
window.DataContext = dataContext;
Assert.Equal(dataContext.NonIntegerIndexerInterfaceProperty["Test"], textBlock.Text);
dataContext.NonIntegerIndexerInterfaceProperty["Test"] = "New Value";
Assert.Equal(dataContext.NonIntegerIndexerInterfaceProperty["Test"], textBlock.Text);
}
}
[Fact]
public void InfersDataTemplateTypeFromDataTypeProperty()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var target = window.GetControl("target");
var dataContext = new TestDataContext();
dataContext.StringProperty = "Initial Value";
window.DataContext = dataContext;
window.ApplyTemplate();
target.ApplyTemplate();
target.Presenter!.UpdateChild();
Assert.Equal(dataContext.StringProperty, ((TextBlock)target.Presenter.Child!).Text);
}
}
[Fact]
public void ThrowsOnUninferrableLooseDataTemplateNoDataTypeWithCompiledBindingPath()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
Assert.ThrowsAny(() => AvaloniaRuntimeXamlLoader.Load(xaml));
}
}
[Fact]
public void ThrowsOnUninferrableDataTypeFromNonCompiledDataContextBindingWithCompiledBindingPath()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
Assert.ThrowsAny(() => AvaloniaRuntimeXamlLoader.Load(xaml));
}
}
[Fact]
public void ReportsMultipleErrorsOnDataContextAndBindingPathErrors()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var ex = Assert.Throws(() => AvaloniaRuntimeXamlLoader.Load(xaml));
Assert.Collection(
ex.InnerExceptions,
inner => Assert.IsAssignableFrom(inner),
inner => Assert.IsAssignableFrom(inner),
inner => Assert.IsAssignableFrom(inner));
}
}
[Fact]
public void InfersDataTemplateTypeFromParentCollectionItemsType()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var target = window.GetControl("target");
var dataContext = new TestDataContext();
dataContext.ListProperty.Add("Test");
window.DataContext = dataContext;
window.ApplyTemplate();
target.ApplyTemplate();
target.Presenter!.ApplyTemplate();
Assert.Equal(dataContext.ListProperty[0], (string?)((ContentPresenter)target.Presenter.Panel!.Children[0]).Content);
}
}
[Fact]
public void InfersDataTemplateTypeFromParentDataGridItemsType()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var window = (Window)AvaloniaRuntimeXamlLoader.Load(@"
");
var target = window.GetControl("target");
var column = target.Columns.Single();
var dataContext = new TestDataContext();
dataContext.ListProperty.Add("Test");
window.DataContext = dataContext;
window.ApplyTemplate();
target.ApplyTemplate();
// Assert DataGridLikeColumn.Binding data type.
var compiledPath = ((CompiledBindingExtension)column.Binding!).Path;
var node = Assert.IsType(Assert.Single(compiledPath.Elements));
Assert.Equal(typeof(int), node.Property.PropertyType);
// Assert DataGridLikeColumn.Template data type by evaluating the template.
var firstItem = dataContext.ListProperty[0];
var textBlockFromTemplate = (TextBlock)column.Template!.Build(firstItem)!;
textBlockFromTemplate.DataContext = firstItem;
Assert.Equal(firstItem.Length.ToString(), textBlockFromTemplate.Text);
}
}
[Fact]
public void ExplicitDataTypeStillWorksOnDataGridLikeControls()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var window = (Window)AvaloniaRuntimeXamlLoader.Load(@"
");
var target = window.GetControl("target");
var column = target.Columns.Single();
var dataContext = new TestDataContext();
dataContext.ListProperty.Add("Test");
target.Items = dataContext.ListProperty;
window.ApplyTemplate();
target.ApplyTemplate();
// Assert DataGridLikeColumn.Binding data type.
var compiledPath = ((CompiledBindingExtension)column.Binding!).Path;
var node = Assert.IsType(Assert.Single(compiledPath.Elements));
Assert.Equal(typeof(int), node.Property.PropertyType);
// Assert DataGridLikeColumn.Template data type by evaluating the template.
var firstItem = dataContext.ListProperty[0];
var textBlockFromTemplate = (TextBlock)column.Template!.Build(firstItem)!;
textBlockFromTemplate.DataContext = firstItem;
Assert.Equal(firstItem.Length.ToString(), textBlockFromTemplate.Text);
}
}
[Fact]
public void ThrowsOnUninferrableDataTemplateInItemsControlWithoutItemsBinding()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
Assert.ThrowsAny(() => AvaloniaRuntimeXamlLoader.Load(xaml));
}
}
[Fact]
public void IgnoresDataTemplateTypeFromDataTypePropertyIfXDataTypeDefined()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var target = window.GetControl("target");
var dataContext = new TestDataContext();
dataContext.StringProperty = "Initial Value";
window.DataContext = dataContext;
window.ApplyTemplate();
target.ApplyTemplate();
target.Presenter!.UpdateChild();
Assert.Equal(dataContext.StringProperty, ((TextBlock)target.Presenter.Child!).Text);
}
}
[Fact]
public void InfersCustomDataTemplateBasedOnAttribute()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var target = window.GetControl("target");
var dataContext = new TestDataContext();
dataContext.StringProperty = "Initial Value";
window.DataContext = dataContext;
window.ApplyTemplate();
target.ApplyTemplate();
target.Presenter!.UpdateChild();
Assert.Equal(dataContext.StringProperty, ((TextBlock)target.Presenter.Child!).Text);
}
}
[Fact]
public void InfersCustomDataTemplateBasedOnAttributeFromBaseClass()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var target = window.GetControl("target");
var dataContext = new TestDataContext();
dataContext.StringProperty = "Initial Value";
window.DataContext = dataContext;
window.ApplyTemplate();
target.ApplyTemplate();
target.Presenter!.UpdateChild();
Assert.Equal(dataContext.StringProperty, ((TextBlock)target.Presenter.Child!).Text);
}
}
[Fact]
public void ResolvesElementNameBinding()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.GetControl("text2");
var dataContext = new TestDataContext
{
StringProperty = "foobar"
};
window.DataContext = dataContext;
Assert.Equal(dataContext.StringProperty, textBlock.Text);
}
}
[Fact]
public void ResolvesElementNameBindingFromLongForm()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.GetControl("text2");
var dataContext = new TestDataContext
{
StringProperty = "foobar"
};
window.DataContext = dataContext;
Assert.Equal(dataContext.StringProperty, textBlock.Text);
}
}
[Fact]
public void ResolvesElementNameBindingFromLongFormWithoutPath()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.GetControl("text2");
Assert.Equal("Avalonia.Controls.TextBlock", textBlock.Text);
}
}
[Fact]
public void ResolvesRelativeSourceBindingLongForm()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var target = window.GetControl("text");
window.ApplyTemplate();
window.Presenter!.ApplyTemplate();
target.ApplyTemplate();
Assert.Equal("test", target.Text);
}
}
[Fact]
public void ResolvesRelativeSourceBindingEvenLongerForm()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var target = window.GetControl("text");
window.ApplyTemplate();
window.Presenter!.ApplyTemplate();
target.ApplyTemplate();
//Assert.Equal("test", target.Text);
}
}
[Fact]
public void ResolvesRelativeSourceBindingFromTemplate()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var contentControl = AvaloniaRuntimeXamlLoader.Parse(xaml);
contentControl.DataContext = new TestDataContext(); // should be ignored
contentControl.Measure(new Size(10, 10));
var result = contentControl.GetTemplateChildren().OfType().First();
Assert.Equal(false, result.Focusable);
}
}
[Fact]
public void ResolvesRelativeSourceBindingFromStyleSelector()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var textBox = AvaloniaRuntimeXamlLoader.Parse(xaml);
textBox.DataContext = new TestDataContext(); // should be ignored
textBox.Measure(new Size(10, 10));
var result = textBox.GetTemplateChildren().OfType().First();
Assert.Equal(textBox.InnerLeftContent, result.Content);
}
}
[Fact]
public void Binds_To_TemplatedParent_From_Non_Control()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var button = window.FindControl