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.
3079 lines
125 KiB
3079 lines
125 KiB
#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 : XamlTestBase
|
|
{
|
|
static CompiledBindingExtensionTests()
|
|
{
|
|
RuntimeHelpers.RunClassConstructor(typeof(RelativeSource).TypeHandle);
|
|
}
|
|
|
|
[Fact]
|
|
public void ResolvesClrPropertyBasedOnDataContextType()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<TextBlock Text='{CompiledBinding StringProperty}' Name='textBlock' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("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 = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:IHasPropertyDerived'>
|
|
<TextBlock Text='{CompiledBinding StringProperty}' Name='textBlock' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("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 = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<TextBlock Text='{CompiledBinding Path=StringProperty}' Name='textBlock' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("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 = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<ItemsControl Name='itemsControl' ItemsSource='{CompiledBinding Path=ListProperty}'>
|
|
<ItemsControl.ItemTemplate>
|
|
<DataTemplate>
|
|
<TextBlock />
|
|
</DataTemplate>
|
|
</ItemsControl.ItemTemplate>
|
|
</ItemsControl>
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<ItemsControl>("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 = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<TextBlock Text='{CompiledBinding StaticProperty}' Name='textBlock' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
textBlock.DataContext = new TestDataContext();
|
|
|
|
Assert.Equal(TestDataContext.StaticProperty, textBlock.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void ResolvesDataTypeFromBindingProperty()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'>
|
|
<TextBlock Text='{CompiledBinding StringProperty, DataType=local:TestDataContext}' Name='textBlock' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("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 = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'>
|
|
<TextBlock Text='{CompiledBinding StringProperty, DataType={x:Type local:TestDataContext}}' Name='textBlock' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("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 = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<TextBlock Text='{CompiledBinding TaskProperty^}' Name='textBlock' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
var dataContext = new TestDataContext
|
|
{
|
|
TaskProperty = Task.FromResult("foobar")
|
|
};
|
|
|
|
window.DataContext = dataContext;
|
|
|
|
Assert.Equal("foobar", textBlock.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void ResolvesStreamObservableBindingCorrectly()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<TextBlock Text='{CompiledBinding ObservableProperty^}' Name='textBlock' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
DelayedBinding.ApplyBindings(textBlock);
|
|
|
|
var subject = new Subject<string>();
|
|
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 = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<TextBlock Text='{CompiledBinding ListProperty[3]}' Name='textBlock' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
var dataContext = new TestDataContext
|
|
{
|
|
ListProperty = { "A", "B", "C", "D", "E" }
|
|
};
|
|
|
|
window.DataContext = dataContext;
|
|
|
|
Assert.Equal(dataContext.ListProperty[3], textBlock.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void IndexerSetterBindsCorrectly()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(@"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<TextBox Text='{CompiledBinding ListProperty[3], Mode=TwoWay}' Name='textBox' />
|
|
</Window>");
|
|
var textBox = window.GetControl<TextBox>("textBox");
|
|
|
|
var dataContext = new TestDataContext
|
|
{
|
|
ListProperty = { "A", "B", "C", "D", "E" }
|
|
};
|
|
|
|
window.DataContext = dataContext;
|
|
|
|
Assert.Equal(dataContext.ListProperty[3], textBox.Text);
|
|
|
|
textBox.Text = "Z";
|
|
|
|
Assert.Equal("Z", dataContext.ListProperty[3]);
|
|
Assert.Equal(dataContext.ListProperty[3], textBox.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void ResolvesArrayIndexerBindingCorrectly()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<TextBlock Text='{CompiledBinding ArrayProperty[3]}' Name='textBlock' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("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 = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<TextBlock Text='{CompiledBinding ObservableCollectionProperty[3]}' Name='textBlock' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("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 = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<TextBlock DataContext='{CompiledBinding StringProperty}' Text='{CompiledBinding}' Name='textBlock' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("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 = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<TextBlock Text='{CompiledBinding NonIntegerIndexerProperty[Test]}' Name='textBlock' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("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 = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<TextBlock Text='{CompiledBinding NonIntegerIndexerInterfaceProperty[Test]}' Name='textBlock' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("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 = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<Window.DataTemplates>
|
|
<DataTemplate DataType='{x:Type x:String}'>
|
|
<TextBlock Text='{CompiledBinding}' Name='textBlock' />
|
|
</DataTemplate>
|
|
</Window.DataTemplates>
|
|
<ContentControl Name='target' Content='{CompiledBinding StringProperty}' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var target = window.GetControl<ContentControl>("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 = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<Window.DataTemplates>
|
|
<DataTemplate>
|
|
<TextBlock Text='{CompiledBinding StringProperty}' Name='textBlock' />
|
|
</DataTemplate>
|
|
</Window.DataTemplates>
|
|
<ContentControl Name='target' Content='{CompiledBinding}' />
|
|
</Window>";
|
|
Assert.ThrowsAny<XmlException>(() => AvaloniaRuntimeXamlLoader.Load(xaml));
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void ThrowsOnUninferrableDataTypeFromNonCompiledDataContextBindingWithCompiledBindingPath()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<ContentControl Name='target' DataContext='{Binding}'>
|
|
<TextBlock Text='{CompiledBinding StringProperty}' Name='textBlock' />
|
|
</ContentControl>
|
|
</Window>";
|
|
Assert.ThrowsAny<XmlException>(() => AvaloniaRuntimeXamlLoader.Load(xaml));
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void ReportsMultipleErrorsOnDataContextAndBindingPathErrors()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'>
|
|
<ContentControl Content='{CompiledBinding NoDataContext}'
|
|
Tag='{CompiledBinding NonExistentProp, DataType=local:TestDataContext}'
|
|
Height='{CompiledBinding invalid.}' />
|
|
</Window>";
|
|
var ex = Assert.Throws<AggregateException>(() => AvaloniaRuntimeXamlLoader.Load(xaml));
|
|
Assert.Collection(
|
|
ex.InnerExceptions,
|
|
inner => Assert.IsAssignableFrom<XmlException>(inner),
|
|
inner => Assert.IsAssignableFrom<XmlException>(inner),
|
|
inner => Assert.IsAssignableFrom<XmlException>(inner));
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void InfersDataTemplateTypeFromParentCollectionItemsType()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<ItemsControl ItemsSource='{CompiledBinding ListProperty}' Name='target'>
|
|
<ItemsControl.ItemTemplate>
|
|
<DataTemplate>
|
|
<TextBlock Text='{CompiledBinding}' Name='textBlock' />
|
|
</DataTemplate>
|
|
</ItemsControl.ItemTemplate>
|
|
</ItemsControl>
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var target = window.GetControl<ItemsControl>("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 InfersDataTypeFromParentDataGridItemsTypeInCaseOfControlInheritance()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(@"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestItemsCollectionDataContext'>
|
|
<local:DataGridLikeControlInheritor Items='{CompiledBinding Items}' Name='target'>
|
|
<local:DataGridLikeControlInheritor.Columns>
|
|
<local:DataGridLikeColumn Binding='{CompiledBinding StringProperty}'>
|
|
</local:DataGridLikeColumn>
|
|
</local:DataGridLikeControlInheritor.Columns>
|
|
</local:DataGridLikeControlInheritor>
|
|
</Window>");
|
|
var target = window.GetControl<DataGridLikeControl>("target");
|
|
var column = target.Columns.Single();
|
|
|
|
var dataContext = new TestItemsCollectionDataContext();
|
|
|
|
dataContext.Items.Add(new TestData() { StringProperty = "Test" });
|
|
|
|
window.DataContext = dataContext;
|
|
|
|
window.ApplyTemplate();
|
|
target.ApplyTemplate();
|
|
|
|
// Assert DataGridLikeColumn.Binding data type.
|
|
var compiledPath = ((CompiledBinding)column.Binding!).Path;
|
|
var node = Assert.IsAssignableFrom<PropertyElement>(Assert.Single(compiledPath!.Elements));
|
|
|
|
Assert.Equal(typeof(string), node.Property.PropertyType);
|
|
Assert.Equal(nameof(TestData.StringProperty), node.Property.Name);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void InfersDataTemplateTypeFromParentDataGridItemsType()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(@"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<local:DataGridLikeControl Items='{CompiledBinding ListProperty}' Name='target'>
|
|
<local:DataGridLikeControl.Columns>
|
|
<local:DataGridLikeColumn Binding='{CompiledBinding Length}'>
|
|
<local:DataGridLikeColumn.Template>
|
|
<DataTemplate>
|
|
<TextBlock Text='{CompiledBinding Length}' />
|
|
</DataTemplate>
|
|
</local:DataGridLikeColumn.Template>
|
|
</local:DataGridLikeColumn>
|
|
</local:DataGridLikeControl.Columns>
|
|
</local:DataGridLikeControl>
|
|
</Window>");
|
|
var target = window.GetControl<DataGridLikeControl>("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 = ((CompiledBinding)column.Binding!).Path;
|
|
var node = Assert.IsAssignableFrom<PropertyElement>(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(@"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<local:DataGridLikeControl Name='target'>
|
|
<local:DataGridLikeControl.Columns>
|
|
<local:DataGridLikeColumn Binding='{CompiledBinding Length}' x:DataType='x:String'>
|
|
<local:DataGridLikeColumn.Template>
|
|
<DataTemplate x:DataType='x:String'>
|
|
<TextBlock Text='{CompiledBinding Length}' />
|
|
</DataTemplate>
|
|
</local:DataGridLikeColumn.Template>
|
|
</local:DataGridLikeColumn>
|
|
</local:DataGridLikeControl.Columns>
|
|
</local:DataGridLikeControl>
|
|
</Window>");
|
|
var target = window.GetControl<DataGridLikeControl>("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 = ((CompiledBinding)column.Binding!).Path;
|
|
var node = Assert.IsAssignableFrom<PropertyElement>(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 = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<ItemsControl Name='target'>
|
|
<ItemsControl.DataTemplates>
|
|
<DataTemplate>
|
|
<TextBlock Text='{CompiledBinding Property}' Name='textBlock' />
|
|
</DataTemplate>
|
|
</ItemsControl.DataTemplates>
|
|
</ItemsControl>
|
|
</Window>";
|
|
Assert.ThrowsAny<XmlException>(() => AvaloniaRuntimeXamlLoader.Load(xaml));
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void IgnoresDataTemplateTypeFromDataTypePropertyIfXDataTypeDefined()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'>
|
|
<Window.DataTemplates>
|
|
<DataTemplate DataType='local:TestDataContextBaseClass' x:DataType='local:TestDataContext'>
|
|
<TextBlock Text='{CompiledBinding StringProperty}' Name='textBlock' />
|
|
</DataTemplate>
|
|
</Window.DataTemplates>
|
|
<ContentControl x:DataType='local:TestDataContext' Name='target' Content='{CompiledBinding}' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var target = window.GetControl<ContentControl>("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 = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'>
|
|
<Window.DataTemplates>
|
|
<local:CustomDataTemplate FancyDataType='local:TestDataContext'>
|
|
<TextBlock Text='{CompiledBinding StringProperty}' Name='textBlock' />
|
|
</local:CustomDataTemplate>
|
|
</Window.DataTemplates>
|
|
<ContentControl x:DataType='local:TestDataContext' Name='target' Content='{CompiledBinding}' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var target = window.GetControl<ContentControl>("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 = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'>
|
|
<Window.DataTemplates>
|
|
<local:CustomDataTemplateInherit FancyDataType='local:TestDataContext'>
|
|
<TextBlock Text='{CompiledBinding StringProperty}' Name='textBlock' />
|
|
</local:CustomDataTemplateInherit>
|
|
</Window.DataTemplates>
|
|
<ContentControl x:DataType='local:TestDataContext' Name='target' Content='{CompiledBinding}' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var target = window.GetControl<ContentControl>("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 = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<StackPanel>
|
|
<TextBlock Text='{CompiledBinding StringProperty}' x:Name='text' />
|
|
<TextBlock Text='{CompiledBinding #text.Text}' x:Name='text2' />
|
|
</StackPanel>
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("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 = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<StackPanel>
|
|
<TextBlock Text='{CompiledBinding StringProperty}' x:Name='text' />
|
|
<TextBlock Text='{CompiledBinding Text, ElementName=text}' x:Name='text2' />
|
|
</StackPanel>
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("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 = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<StackPanel>
|
|
<TextBlock Text='{CompiledBinding StringProperty}' x:Name='text' />
|
|
<TextBlock Text='{CompiledBinding ElementName=text}' x:Name='text2' />
|
|
</StackPanel>
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("text2");
|
|
|
|
Assert.Equal("Avalonia.Controls.TextBlock", textBlock.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void ResolvesRelativeSourceBindingLongForm()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'
|
|
Title='test'>
|
|
<TextBlock Text='{CompiledBinding Title, RelativeSource={RelativeSource AncestorType=Window}}' x:Name='text'/>
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var target = window.GetControl<TextBlock>("text");
|
|
|
|
window.ApplyTemplate();
|
|
window.Presenter!.ApplyTemplate();
|
|
target.ApplyTemplate();
|
|
|
|
Assert.Equal("test", target.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void ResolvesRelativeSourceBindingEvenLongerForm()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'
|
|
Title='test'>
|
|
<TextBlock Text='{CompiledBinding Title, RelativeSource={RelativeSource AncestorType={x:Type Window}}}' x:Name='text'/>
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var target = window.GetControl<TextBlock>("text");
|
|
|
|
window.ApplyTemplate();
|
|
window.Presenter!.ApplyTemplate();
|
|
target.ApplyTemplate();
|
|
|
|
//Assert.Equal("test", target.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void ResolvesRelativeSourceBindingFromTemplate()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var xaml = @"
|
|
<ContentControl xmlns='https://github.com/avaloniaui'
|
|
Focusable='True'>
|
|
<ContentControl.Styles>
|
|
<Style Selector='ContentControl'>
|
|
<Setter Property='Template'>
|
|
<ControlTemplate>
|
|
<ContentPresenter Focusable='{CompiledBinding !Focusable, RelativeSource={RelativeSource TemplatedParent}}' />
|
|
</ControlTemplate>
|
|
</Setter>
|
|
</Style>
|
|
</ContentControl.Styles>
|
|
</ContentControl>";
|
|
|
|
var contentControl = AvaloniaRuntimeXamlLoader.Parse<ContentControl>(xaml);
|
|
contentControl.DataContext = new TestDataContext(); // should be ignored
|
|
contentControl.Measure(new Size(10, 10));
|
|
|
|
var result = contentControl.GetTemplateDescendants().OfType<ContentPresenter>().First();
|
|
Assert.Equal(false, result.Focusable);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void ResolvesRelativeSourceBindingFromStyleSelector()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var xaml = @"
|
|
<TextBox xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
InnerLeftContent='Hello'>
|
|
<TextBox.Styles>
|
|
<Style Selector='TextBox'>
|
|
<Setter Property='Template'>
|
|
<ControlTemplate>
|
|
<StackPanel>
|
|
<ContentPresenter x:Name='Content' />
|
|
<TextPresenter x:Name='PART_TextPresenter' />
|
|
</StackPanel>
|
|
</ControlTemplate>
|
|
</Setter>
|
|
<Style Selector='^ /template/ ContentPresenter#Content'>
|
|
<Setter Property='Content' Value='{CompiledBinding InnerLeftContent, RelativeSource={RelativeSource TemplatedParent}}' />
|
|
</Style>
|
|
</Style>
|
|
</TextBox.Styles>
|
|
</TextBox>";
|
|
|
|
var textBox = AvaloniaRuntimeXamlLoader.Parse<TextBox>(xaml);
|
|
textBox.DataContext = new TestDataContext(); // should be ignored
|
|
textBox.Measure(new Size(10, 10));
|
|
|
|
var result = textBox.GetTemplateDescendants().OfType<ContentPresenter>().First();
|
|
Assert.Equal(textBox.InnerLeftContent, result.Content);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Binds_To_TemplatedParent_From_Non_Control()
|
|
{
|
|
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'>
|
|
<Button.Template>
|
|
<ControlTemplate>
|
|
<Grid>
|
|
<Grid.ColumnDefinitions>
|
|
<ColumnDefinition Width='{CompiledBinding RelativeSource={RelativeSource TemplatedParent}, Path=Tag}'/>
|
|
</Grid.ColumnDefinitions>
|
|
</Grid>
|
|
</ControlTemplate>
|
|
</Button.Template>
|
|
</Button>
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var button = window.GetControl<Button>("button");
|
|
|
|
button.Tag = new GridLength(5, GridUnitType.Star);
|
|
|
|
window.ApplyTemplate();
|
|
button.ApplyTemplate();
|
|
|
|
Assert.Equal(button.Tag, button.GetTemplateDescendants().OfType<Grid>().First().ColumnDefinitions[0].Width);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void ResolvesElementNameInTemplate()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var xaml = @"
|
|
<ContentControl xmlns='https://github.com/avaloniaui'
|
|
Content='Hello'>
|
|
<ContentControl.Styles>
|
|
<Style Selector='ContentControl'>
|
|
<Setter Property='Template'>
|
|
<ControlTemplate>
|
|
<Panel>
|
|
<TextBox Name='InnerTextBox' Text='Hello' />
|
|
<ContentPresenter Content='{CompiledBinding Text, ElementName=InnerTextBox}' />
|
|
</Panel>
|
|
</ControlTemplate>
|
|
</Setter>
|
|
</Style>
|
|
</ContentControl.Styles>
|
|
</ContentControl>";
|
|
|
|
var contentControl = AvaloniaRuntimeXamlLoader.Parse<ContentControl>(xaml);
|
|
contentControl.Measure(new Size(10, 10));
|
|
|
|
var result = contentControl.GetTemplateDescendants().OfType<ContentPresenter>().First();
|
|
|
|
Assert.Equal("Hello", result.Content);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Binds_To_Source()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'
|
|
Title='test'>
|
|
<TextBlock Text='{CompiledBinding Length, Source=Test}' x:Name='text'/>
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var target = window.GetControl<TextBlock>("text");
|
|
|
|
window.ApplyTemplate();
|
|
window.Presenter!.ApplyTemplate();
|
|
target.ApplyTemplate();
|
|
|
|
Assert.Equal("Test".Length.ToString(), target.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Binds_To_Source_StaticResource()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var xaml = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='using:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions'
|
|
x:CompileBindings='True'>
|
|
<Window.Resources>
|
|
<local:TestDataContext x:Key='dataKey' StringProperty='foobar'/>
|
|
</Window.Resources>
|
|
<TextBlock Name='textBlock' Text='{Binding StringProperty, Source={StaticResource dataKey}}'/>
|
|
</Window>";
|
|
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
Assert.Equal("foobar", textBlock.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Binds_To_Source_StaticResource1()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var xaml = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='using:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions'
|
|
x:CompileBindings='True'>
|
|
<Window.Resources>
|
|
<local:TestDataContext x:Key='dataKey' StringProperty='foobar'/>
|
|
<x:String x:Key='otherObjectKey'>test</x:String>
|
|
</Window.Resources>
|
|
<TextBlock Name='textBlock' Text='{Binding StringProperty, Source={StaticResource dataKey}}'/>
|
|
</Window>";
|
|
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
Assert.Equal("foobar", textBlock.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Binds_To_Source_StaticResource_In_ResourceDictionary()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var xaml = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='using:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions'
|
|
x:DataType='local:TestDataContext' x:CompileBindings='True'>
|
|
<Window.Resources>
|
|
<ResourceDictionary>
|
|
<local:TestDataContext x:Key='dataKey' StringProperty='foobar'/>
|
|
</ResourceDictionary>
|
|
</Window.Resources>
|
|
<TextBlock Name='textBlock' Text='{Binding StringProperty, Source={StaticResource dataKey}}'/>
|
|
</Window>";
|
|
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
Assert.Equal("foobar", textBlock.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Binds_To_Source_StaticResource_In_ResourceDictionary1()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var xaml = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='using:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions'
|
|
x:DataType='local:TestDataContext' x:CompileBindings='True'>
|
|
<Window.Resources>
|
|
<ResourceDictionary>
|
|
<local:TestDataContext x:Key='dataKey' StringProperty='foobar'/>
|
|
<x:String x:Key='otherObjectKey'>test</x:String>
|
|
</ResourceDictionary>
|
|
</Window.Resources>
|
|
<TextBlock Name='textBlock' Text='{Binding StringProperty, Source={StaticResource dataKey}}'/>
|
|
</Window>";
|
|
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
Assert.Equal("foobar", textBlock.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Binds_To_Source_xStatic()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var xaml = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='using:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions'
|
|
x:CompileBindings='True'>
|
|
<ContentControl Name='contentControl' Content='{Binding Color, Source={x:Static Brushes.Red}}'/>
|
|
</Window>";
|
|
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var contentControl = window.GetControl<ContentControl>("contentControl");
|
|
|
|
Assert.Equal(Brushes.Red.Color, contentControl.Content);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void CompilesBindingWhenRequested()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'
|
|
x:CompileBindings='true'>
|
|
<TextBlock Text='{Binding StringProperty}' Name='textBlock' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
var dataContext = new TestDataContext
|
|
{
|
|
StringProperty = "foobar"
|
|
};
|
|
|
|
window.DataContext = dataContext;
|
|
|
|
Assert.Equal(dataContext.StringProperty, textBlock.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void BoolPropertyGetterUsesCachedBoxes()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<TextBlock Tag='{CompiledBinding BoolProperty}' Name='textBlock' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
window.DataContext = new TestDataContext { BoolProperty = true };
|
|
var boxedTrue = textBlock.Tag;
|
|
window.DataContext = new TestDataContext { BoolProperty = false };
|
|
var boxedFalse = textBlock.Tag;
|
|
|
|
Assert.Equal(true, boxedTrue);
|
|
Assert.Equal(false, boxedFalse);
|
|
|
|
// The getter must return the cached boxes instead of allocating a new box per read.
|
|
window.DataContext = new TestDataContext { BoolProperty = true };
|
|
Assert.Same(boxedTrue, textBlock.Tag);
|
|
window.DataContext = new TestDataContext { BoolProperty = false };
|
|
Assert.Same(boxedFalse, textBlock.Tag);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void ThrowsOnInvalidBindingPathOnCompiledBindingEnabledViaDirective()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'
|
|
x:CompileBindings='true'>
|
|
<TextBlock Text='{Binding InvalidPath}' Name='textBlock' />
|
|
</Window>";
|
|
Assert.ThrowsAny<XmlException>(() => AvaloniaRuntimeXamlLoader.Load(xaml));
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void SupportParentInPath()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
Title='foo'>
|
|
<ContentControl Content='{CompiledBinding $parent.Title}' Name='contentControl' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var contentControl = window.GetControl<ContentControl>("contentControl");
|
|
|
|
Assert.Equal("foo", contentControl.Content);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void SupportsParentInPathWithTypeAndLevelFilter()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(@"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
|
|
<Border x:Name='p2'>
|
|
<Border x:Name='p1'>
|
|
<Button x:Name='p0'>
|
|
<TextBlock x:Name='textBlock' Text='{CompiledBinding $parent[Control;1].Name}' />
|
|
</Button>
|
|
</Border>
|
|
</Border>
|
|
</Window>");
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
Assert.Equal("p1", textBlock.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void SupportConverterWithParameter()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext' x:CompileBindings='True'>
|
|
<TextBlock Name='textBlock' Text='{Binding StringProperty, Converter={x:Static local:AppendConverter.Instance}, ConverterParameter=Bar}'/>
|
|
</Window>";
|
|
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
window.DataContext = new TestDataContext() { StringProperty = "Foo" };
|
|
|
|
Assert.Equal($"Foo+Bar+{CultureInfo.CurrentCulture}", textBlock.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void SupportConverterWithCulture()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext' x:CompileBindings='True'>
|
|
<TextBlock Name='textBlock' Text='{Binding StringProperty, Converter={x:Static local:AppendConverter.Instance}, ConverterCulture=ar-SA}'/>
|
|
</Window>";
|
|
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
window.DataContext = new TestDataContext() { StringProperty = "Foo" };
|
|
|
|
Assert.Equal($"Foo++ar-SA", textBlock.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void ThrowsOnInvalidCompileBindingsDirective()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'
|
|
x:CompileBindings='notabool'>
|
|
</Window>";
|
|
Assert.ThrowsAny<XmlException>(() => AvaloniaRuntimeXamlLoader.Load(xaml));
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void SupportCastToTypeInExpression()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var xaml = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='using:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions'
|
|
x:DataType='local:TestDataContext'>
|
|
<ContentControl Content='{CompiledBinding $parent.((local:TestDataContext)DataContext)}' Name='contentControl' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var contentControl = window.GetControl<ContentControl>("contentControl");
|
|
|
|
var dataContext = new TestDataContext();
|
|
|
|
window.DataContext = dataContext;
|
|
|
|
Assert.Equal(dataContext, contentControl.Content);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void SupportCastToNestedTypeInExpression()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var xaml = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='using:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions'>
|
|
<ContentControl Content='{CompiledBinding $parent.((local:OuterClass+NestedClass)DataContext).NestedProperty}' Name='contentControl' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var contentControl = window.GetControl<ContentControl>("contentControl");
|
|
|
|
window.DataContext = new OuterClass.NestedClass { NestedProperty = "hello" };
|
|
|
|
Assert.Equal("hello", contentControl.Content);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void SupportCastToTypeInExpression_DifferentTypeEvaluatesToNull()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var xaml = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='using:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions'
|
|
x:DataType='local:TestDataContext'>
|
|
<ContentControl Content='{CompiledBinding $parent.((local:TestDataContext)DataContext)}' Name='contentControl' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var contentControl = window.GetControl<ContentControl>("contentControl");
|
|
|
|
var dataContext = "foo";
|
|
|
|
window.DataContext = dataContext;
|
|
|
|
Assert.Equal(null, contentControl.Content);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void SupportCastToTypeInExpressionWithProperty()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var xaml = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='using:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions'
|
|
x:DataType='local:TestDataContext'>
|
|
<ContentControl Content='{CompiledBinding $parent.((local:TestDataContext)DataContext).StringProperty}' Name='contentControl' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var contentControl = window.GetControl<ContentControl>("contentControl");
|
|
|
|
var dataContext = new TestDataContext
|
|
{
|
|
StringProperty = "foobar"
|
|
};
|
|
|
|
window.DataContext = dataContext;
|
|
|
|
Assert.Equal(dataContext.StringProperty, contentControl.Content);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void SupportCastToTypeInExpressionWithProperty1()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var xaml = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='using:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions'
|
|
x:DataType='local:TestDataContext'>
|
|
<ContentControl Content='{CompiledBinding $parent.DataContext(local:TestDataContext).StringProperty}' Name='contentControl' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var contentControl = window.GetControl<ContentControl>("contentControl");
|
|
|
|
var dataContext = new TestDataContext
|
|
{
|
|
StringProperty = "foobar"
|
|
};
|
|
|
|
window.DataContext = dataContext;
|
|
|
|
Assert.Equal(dataContext.StringProperty, contentControl.Content);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void SupportCastToTypeInExpressionWithPropertyIndexer()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var xaml = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='using:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions'
|
|
x:DataType='local:TestDataContext'>
|
|
<ContentControl Content='{CompiledBinding ((local:TestData)ObjectsArrayProperty[0]).StringProperty}' Name='contentControl' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var contentControl = window.GetControl<ContentControl>("contentControl");
|
|
|
|
var data = new TestData()
|
|
{
|
|
StringProperty = "Foo"
|
|
};
|
|
var dataContext = new TestDataContext
|
|
{
|
|
ObjectsArrayProperty = new object[] { data }
|
|
};
|
|
|
|
window.DataContext = dataContext;
|
|
|
|
Assert.Equal(data.StringProperty, contentControl.Content);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void SupportCastToTypeInExpressionWithProperty_DifferentTypeEvaluatesToNull()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var xaml = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='using:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions'
|
|
x:DataType='local:TestDataContext'>
|
|
<ContentControl Content='{CompiledBinding $parent.((local:TestDataContext)DataContext).StringProperty}' Name='contentControl' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var contentControl = window.GetControl<ContentControl>("contentControl");
|
|
|
|
var dataContext = new TestDataContext
|
|
{
|
|
StringProperty = "foobar"
|
|
};
|
|
|
|
window.DataContext = dataContext;
|
|
|
|
Assert.Equal(dataContext.StringProperty, contentControl.Content);
|
|
|
|
window.DataContext = "foo";
|
|
|
|
Assert.Equal(null, contentControl.Content);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void SupportsEmptyPath()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<TextBlock Text='{CompiledBinding}' Name='textBlock' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
var dataContext = new TestDataContext
|
|
{
|
|
StringProperty = "foobar"
|
|
};
|
|
|
|
window.DataContext = dataContext;
|
|
|
|
Assert.Equal(typeof(TestDataContext).FullName, textBlock.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void SupportsEmptyPathWithStringFormat()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<TextBlock Text='{CompiledBinding StringFormat=bar-\{0\}}' Name='textBlock' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
var dataContext = new TestDataContext
|
|
{
|
|
StringProperty = "foobar"
|
|
};
|
|
|
|
window.DataContext = dataContext;
|
|
|
|
Assert.Equal("bar-" + typeof(TestDataContext).FullName, textBlock.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void SupportsDotPath()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<TextBlock Text='{CompiledBinding .}' Name='textBlock' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
var dataContext = new TestDataContext
|
|
{
|
|
StringProperty = "foobar"
|
|
};
|
|
|
|
window.DataContext = dataContext;
|
|
|
|
Assert.Equal(typeof(TestDataContext).FullName, textBlock.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void SupportsExplicitDotPathWithStringFormat()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<TextBlock Text='{CompiledBinding Path=., StringFormat=bar-\{0\}}' Name='textBlock' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
var dataContext = new TestDataContext
|
|
{
|
|
StringProperty = "foobar"
|
|
};
|
|
|
|
window.DataContext = dataContext;
|
|
|
|
Assert.Equal("bar-" + typeof(TestDataContext).FullName, textBlock.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void SupportCastToTypeInExpressionWithProperty_ExplicitPropertyCast()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var xaml = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='using:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions'>
|
|
<ContentControl Content='{CompiledBinding $parent.((local:IHasExplicitProperty)DataContext).ExplicitProperty}' Name='contentControl' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var contentControl = window.GetControl<ContentControl>("contentControl");
|
|
|
|
var dataContext = new TestDataContext();
|
|
|
|
window.DataContext = dataContext;
|
|
|
|
Assert.Equal(((IHasExplicitProperty)dataContext).ExplicitProperty, contentControl.Content);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Binds_To_Self()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<TextBlock Name='textBlock' Text='{CompiledBinding $self}' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
window.ApplyTemplate();
|
|
window.Presenter!.ApplyTemplate();
|
|
|
|
Assert.Equal("Avalonia.Controls.TextBlock", textBlock.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Binds_To_Self_Without_DataType()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'>
|
|
<TextBlock Name='textBlock' Text='{CompiledBinding $self.Name}' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
window.ApplyTemplate();
|
|
window.Presenter!.ApplyTemplate();
|
|
|
|
Assert.Equal(textBlock.Name, textBlock.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Binds_To_Self_In_Style()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var xaml = @"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
|
|
|
|
<Window.Styles>
|
|
<Style Selector='Button'>
|
|
<Setter Property='IsVisible' Value='{CompiledBinding $self.IsEnabled}' />
|
|
</Style>
|
|
</Window.Styles>
|
|
|
|
<Button Name='button' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var button = window.GetControl<Button>("button");
|
|
|
|
window.ApplyTemplate();
|
|
window.Presenter!.ApplyTemplate();
|
|
|
|
Assert.True(button.IsVisible);
|
|
|
|
button.IsEnabled = false;
|
|
|
|
Assert.False(button.IsVisible);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Binds_To_RelativeSource_Self()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<TextBlock Name='textBlock' Text='{CompiledBinding RelativeSource={RelativeSource Self}}' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
window.ApplyTemplate();
|
|
window.Presenter!.ApplyTemplate();
|
|
|
|
Assert.Equal("Avalonia.Controls.TextBlock", textBlock.Text);
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(false)]
|
|
[InlineData(true)]
|
|
public void Binds_To_RelativeSource_Self_In_MultiBinding(bool compileBindings)
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var xaml = $@"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
x:CompileBindings='{compileBindings}'>
|
|
<StackPanel>
|
|
<TextBlock Name='textBlock'>
|
|
<TextBlock.Text>
|
|
<MultiBinding StringFormat=""{{}} $self = {{0}}, $parent = {{1}}"">
|
|
<Binding Path=""$self.FontStyle""/>
|
|
<Binding Path=""$parent.Orientation""/>
|
|
</MultiBinding>
|
|
</TextBlock.Text>
|
|
</TextBlock>
|
|
</StackPanel>
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
var dataContext = new TestDataContext();
|
|
window.DataContext = dataContext;
|
|
|
|
Assert.Equal(" $self = Normal, $parent = Vertical"
|
|
, textBlock.GetValue(TextBlock.TextProperty));
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(false)]
|
|
[InlineData(true)]
|
|
public void Binds_To_RelativeSource_Self_In_MultiBinding_In_Style(bool compileBindings)
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var xaml = $@"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
x:CompileBindings='{compileBindings}'>
|
|
<Window.Styles>
|
|
<Style Selector='TextBlock'>
|
|
<Setter Property='Text'>
|
|
<MultiBinding StringFormat=""{{}} $self = {{0}}"">
|
|
<Binding Path=""$self.FontStyle""/>
|
|
</MultiBinding>
|
|
</Setter>
|
|
</Style>
|
|
</Window.Styles>
|
|
<StackPanel>
|
|
<TextBlock Name='textBlock'/>
|
|
</StackPanel>
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
var dataContext = new TestDataContext();
|
|
window.DataContext = dataContext;
|
|
|
|
Assert.Equal(" $self = Normal"
|
|
, textBlock.GetValue(TextBlock.TextProperty));
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void SupportsMethodBindingAsDelegate()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:MethodDataContext'>
|
|
<StackPanel>
|
|
<ContentControl Content='{CompiledBinding Action}' Name='action' />
|
|
<ContentControl Content='{CompiledBinding Func}' Name='func' />
|
|
<ContentControl Content='{CompiledBinding Func2}' Name='func2' />
|
|
<ContentControl Content='{CompiledBinding CustomDelegateTypeVoid}' Name='customvoid' />
|
|
<ContentControl Content='{CompiledBinding CustomDelegateTypeInt}' Name='customint' />
|
|
</StackPanel>
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
window.DataContext = new MethodDataContext();
|
|
|
|
Assert.IsAssignableFrom(typeof(Action), window.GetControl<ContentControl>("action").Content);
|
|
Assert.IsAssignableFrom(typeof(Func<object>), window.GetControl<ContentControl>("func").Content);
|
|
Assert.IsAssignableFrom(typeof(Func<object, object>), window.GetControl<ContentControl>("func2").Content);
|
|
Assert.True(typeof(Delegate).IsAssignableFrom(window.GetControl<ContentControl>("customvoid").Content!.GetType()));
|
|
Assert.True(typeof(Delegate).IsAssignableFrom(window.GetControl<ContentControl>("customint").Content!.GetType()));
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Binding_Method_To_Command_Works()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:MethodAsCommandDataContext'>
|
|
<Button Name='button' Command='{CompiledBinding Method}'/>
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var button = window.GetControl<Button>("button");
|
|
var vm = new MethodAsCommandDataContext();
|
|
|
|
button.DataContext = vm;
|
|
window.ApplyTemplate();
|
|
|
|
Assert.NotNull(button.Command);
|
|
PerformClick(button);
|
|
Assert.Equal("Called", vm.Value);
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("ObjectMethod", "<x:String>hello</x:String>", "Called ObjectMethod with hello")]
|
|
[InlineData("StringMethod", "<x:String>hello</x:String>", "Called StringMethod with hello")]
|
|
[InlineData("StringMethod", "<x:Null />", "Called StringMethod with ")]
|
|
[InlineData("Int32Method", "<x:Int32>42</x:Int32>", "Called Int32Method with 42")]
|
|
[InlineData("VirtualObjectMethod", "<x:String>hello</x:String>", "Called VirtualObjectMethod with hello")]
|
|
[InlineData("VirtualStringMethod", "<x:String>hello</x:String>", "Called VirtualStringMethod with hello")]
|
|
[InlineData("VirtualStringMethod", "<x:Null />", "Called VirtualStringMethod with ")]
|
|
[InlineData("VirtualInt32Method", "<x:Int32>42</x:Int32>", "Called VirtualInt32Method with 42")]
|
|
[InlineData("MethodWithNewSlot", "<x:Int32>42</x:Int32>", "Called MethodWithNewSlot with 42")]
|
|
public void Binding_Method_With_Parameter_To_Command_Uses_Single_Parameter_Overload(
|
|
string methodName,
|
|
string xamlParameter,
|
|
string expected)
|
|
{
|
|
using var app = UnitTestApplication.Start(TestServices.StyledWindow);
|
|
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(
|
|
$$"""
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:MethodAsCommandDataContext'>
|
|
<Button Name='button' Command='{CompiledBinding {{methodName}}}'>
|
|
<Button.CommandParameter>
|
|
{{xamlParameter}}
|
|
</Button.CommandParameter>
|
|
</Button>
|
|
</Window>
|
|
""");
|
|
var button = window.GetControl<Button>("button");
|
|
var vm = new MethodAsCommandDataContext();
|
|
|
|
button.DataContext = vm;
|
|
window.ApplyTemplate();
|
|
|
|
Assert.NotNull(button.Command);
|
|
PerformClick(button);
|
|
Assert.Equal(expected, vm.Value);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("Int32Method", "<x:String>hello</x:String>", typeof(InvalidCastException))]
|
|
[InlineData("Int32Method", "<x:Null />", typeof(NullReferenceException))]
|
|
[InlineData("StringMethod", "<x:Int32>42</x:Int32>", typeof(InvalidCastException))]
|
|
public void Binding_Method_With_Parameter_To_Command_With_Single_Parameter_Overload_Throws_At_Runtime_If_Mismatched_Types(
|
|
string methodName,
|
|
string xamlParameter,
|
|
Type exceptionType)
|
|
{
|
|
using var app = UnitTestApplication.Start(TestServices.StyledWindow);
|
|
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(
|
|
$$"""
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:MethodAsCommandDataContext'>
|
|
<Button Name='button' Command='{CompiledBinding {{methodName}}}'>
|
|
<Button.CommandParameter>
|
|
{{xamlParameter}}
|
|
</Button.CommandParameter>
|
|
</Button>
|
|
</Window>
|
|
""");
|
|
var button = window.GetControl<Button>("button");
|
|
var vm = new MethodAsCommandDataContext();
|
|
|
|
button.DataContext = vm;
|
|
window.ApplyTemplate();
|
|
|
|
Assert.NotNull(button.Command);
|
|
Assert.Throws(exceptionType, () => PerformClick(button));
|
|
}
|
|
|
|
[Fact]
|
|
public void Binding_Method_With_Parameter_To_Command_Prefers_Object_Overload()
|
|
{
|
|
using var app = UnitTestApplication.Start(TestServices.StyledWindow);
|
|
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(
|
|
"""
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:MethodAsCommandDataContext'>
|
|
<Button Name='button' Command='{CompiledBinding MethodWithOverloads}' CommandParameter="foo" />
|
|
</Window>
|
|
""");
|
|
var button = window.GetControl<Button>("button");
|
|
var vm = new MethodAsCommandDataContext();
|
|
|
|
button.DataContext = vm;
|
|
window.ApplyTemplate();
|
|
|
|
Assert.NotNull(button.Command);
|
|
PerformClick(button);
|
|
Assert.Equal("Called MethodWithOverloads with Object foo", vm.Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void Binding_Method_With_Parameter_To_Command_Fails_With_Multiple_Single_Parameter_Overloads_Without_Object()
|
|
{
|
|
using var app = UnitTestApplication.Start(TestServices.StyledWindow);
|
|
|
|
var exception = Assert.ThrowsAny<XmlException>(() => (Window)AvaloniaRuntimeXamlLoader.Load(
|
|
"""
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:MethodAsCommandDataContext'>
|
|
<Button Name='button' Command='{CompiledBinding MethodWithOverloads2}' CommandParameter="foo" />
|
|
</Window>
|
|
"""));
|
|
|
|
Assert.StartsWith(
|
|
"Unable to resolve method of name 'MethodWithOverloads2' on type 'Avalonia.Markup.Xaml.UnitTests.MarkupExtensions.MethodAsCommandDataContext'. " +
|
|
"Found 2 overloads accepting one parameter: 'System.Int32', 'System.String'. " +
|
|
"Expected either a single overload with one parameter, or an overload accepting System.Object.",
|
|
exception.Message);
|
|
}
|
|
|
|
[Fact]
|
|
public void Binding_Method_With_Parameter_To_Command_Uses_Parameterless_Overload_When_No_Overloads_With_Parameter_Exist()
|
|
{
|
|
using var app = UnitTestApplication.Start(TestServices.StyledWindow);
|
|
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(
|
|
"""
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:MethodAsCommandDataContext'>
|
|
<Button Name='button' Command='{CompiledBinding MethodWithOverloads3}' CommandParameter="foo" />
|
|
</Window>
|
|
""");
|
|
var button = window.GetControl<Button>("button");
|
|
var vm = new MethodAsCommandDataContext();
|
|
|
|
button.DataContext = vm;
|
|
window.ApplyTemplate();
|
|
|
|
Assert.NotNull(button.Command);
|
|
PerformClick(button);
|
|
Assert.Equal("Called MethodWithOverloads3 without parameter", vm.Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void Binding_Method_With_Parameter_To_Command_Fails_Without_Valid_Overloads()
|
|
{
|
|
using var app = UnitTestApplication.Start(TestServices.StyledWindow);
|
|
|
|
var exception = Assert.ThrowsAny<XmlException>(() => (Window)AvaloniaRuntimeXamlLoader.Load(
|
|
"""
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:MethodAsCommandDataContext'>
|
|
<Button Name='button' Command='{CompiledBinding MethodWithOverloads4}' CommandParameter="foo" />
|
|
</Window>
|
|
"""));
|
|
|
|
Assert.StartsWith(
|
|
"Unable to resolve method of name 'MethodWithOverloads4' on type 'Avalonia.Markup.Xaml.UnitTests.MarkupExtensions.MethodAsCommandDataContext'. " +
|
|
"Found 2 overloads accepting more than one parameter. " +
|
|
"Expected a method with zero or one parameter. ",
|
|
exception.Message);
|
|
}
|
|
|
|
[Fact]
|
|
public void Binding_Method_To_TextBlock_Text_Works()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:MethodAsCommandDataContext'>
|
|
<TextBlock Name='textBlock' Text='{CompiledBinding Method}'/>
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
var vm = new MethodAsCommandDataContext();
|
|
|
|
textBlock.DataContext = vm;
|
|
window.ApplyTemplate();
|
|
|
|
Assert.NotNull(textBlock.Text);
|
|
}
|
|
}
|
|
|
|
|
|
[Theory]
|
|
[InlineData(null, "Not called")]
|
|
[InlineData("A", "Do A")]
|
|
public void Binding_Method_With_Parameter_To_Command_CanExecute(object? commandParameter, string result)
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:MethodAsCommandDataContext'>
|
|
<Button Name='button' Command='{CompiledBinding Do}' CommandParameter='{CompiledBinding Parameter, Mode=OneTime}'/>
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var button = window.GetControl<Button>("button");
|
|
var vm = new MethodAsCommandDataContext()
|
|
{
|
|
Parameter = commandParameter
|
|
};
|
|
|
|
button.DataContext = vm;
|
|
window.ApplyTemplate();
|
|
|
|
Assert.NotNull(button.Command);
|
|
PerformClick(button);
|
|
Assert.Equal(vm.Value, result);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Binding_Method_With_Parameter_To_Command_CanExecute_DependsOn()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:MethodAsCommandDataContext'>
|
|
<Button Name='button' Command='{CompiledBinding Do}'/>
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var button = window.GetControl<Button>("button");
|
|
var vm = new MethodAsCommandDataContext()
|
|
{
|
|
Parameter = null,
|
|
};
|
|
|
|
button.DataContext = vm;
|
|
window.ApplyTemplate();
|
|
|
|
Assert.NotNull(button.Command);
|
|
|
|
Assert.Equal(button.IsEffectivelyEnabled, false);
|
|
|
|
vm.Parameter = true;
|
|
Threading.Dispatcher.UIThread.RunJobs(null, TestContext.Current.CancellationToken);
|
|
|
|
Assert.Equal(button.IsEffectivelyEnabled, true);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Binding_Method_To_Command_In_Style_Works()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:MethodAsCommandDataContext'>
|
|
<Window.Styles>
|
|
<Style Selector='Button'>
|
|
<Setter Property='Command' Value='{CompiledBinding Method}'/>
|
|
</Style>
|
|
</Window.Styles>
|
|
<Button Name='button'/>
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var button = window.GetControl<Button>("button");
|
|
var vm = new MethodAsCommandDataContext();
|
|
|
|
button.DataContext = vm;
|
|
window.ApplyTemplate();
|
|
|
|
Assert.NotNull(button.Command);
|
|
PerformClick(button);
|
|
Assert.Equal("Called", vm.Value);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void ResolvesDataTypeForAssignBinding()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var xaml = @"
|
|
<local:AssignBindingControl xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'
|
|
X='{CompiledBinding StringProperty}' />";
|
|
var control = (AssignBindingControl)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var compiledPath = ((CompiledBinding)control.X!).Path;
|
|
|
|
var node = Assert.IsAssignableFrom<PropertyElement>(Assert.Single(compiledPath!.Elements));
|
|
Assert.Equal(typeof(string), node.Property.PropertyType);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void ResolvesDataTypeForAssignBinding_FromBindingProperty()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var xaml = @"
|
|
<local:AssignBindingControl xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
X='{CompiledBinding StringProperty, DataType=local:TestDataContext}' />";
|
|
var control = (AssignBindingControl)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var compiledPath = ((CompiledBinding)control.X!).Path;
|
|
|
|
var node = Assert.IsAssignableFrom<PropertyElement>(Assert.Single(compiledPath!.Elements));
|
|
Assert.Equal(typeof(string), node.Property.PropertyType);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Uses_RuntimeLoader_Configuration_To_Enabled_Compiled()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var xaml = @"
|
|
<local:AssignBindingControl xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
X='{CompiledBinding StringProperty, DataType=local:TestDataContext}' />";
|
|
var control = (AssignBindingControl)AvaloniaRuntimeXamlLoader.Load(new RuntimeXamlLoaderDocument(xaml),
|
|
new RuntimeXamlLoaderConfiguration { UseCompiledBindingsByDefault = true });
|
|
var compiledPath = ((CompiledBinding)control.X!).Path;
|
|
|
|
var node = Assert.IsAssignableFrom<PropertyElement>(Assert.Single(compiledPath!.Elements));
|
|
Assert.Equal(typeof(string), node.Property.PropertyType);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Should_Bind_To_Nested_Generic_Property()
|
|
{
|
|
// See https://github.com/AvaloniaUI/Avalonia/issues/10485
|
|
// This code works fine with SRE, and test is passing, but it fails on Cecil.
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'
|
|
x:CompileBindings='True'>
|
|
<ComboBox x:Name='comboBox' ItemsSource='{Binding GenericProperty}' SelectedItem='{Binding GenericProperty.CurrentItem}' />
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var comboBox = window.GetControl<ComboBox>("comboBox");
|
|
|
|
var dataContext = new TestDataContext();
|
|
dataContext.GenericProperty.Add(123);
|
|
dataContext.GenericProperty.CurrentItem = 123;
|
|
window.DataContext = dataContext;
|
|
|
|
Assert.Equal(123, comboBox.SelectedItem);
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(false)]
|
|
[InlineData(true)]
|
|
public void Should_Use_StringFormat_Without_Braces(bool compileBindings)
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'
|
|
x:CompileBindings='{compileBindings}'>
|
|
<TextBlock Name='textBlock' Text='{{Binding DecimalValue, StringFormat=c2}}'/>
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
var dataContext = new TestDataContext();
|
|
window.DataContext = dataContext;
|
|
|
|
Assert.Equal(string.Format("{0:c2}", TestDataContext.ExpectedDecimal)
|
|
, textBlock.GetValue(TextBlock.TextProperty));
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(true)]
|
|
[InlineData(false)]
|
|
public void Should_Negate_Boolean_Value(bool value)
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'
|
|
x:CompileBindings='True'>
|
|
<TextBlock Name='textBlock' Tag='{{Binding !BoolProperty}}'/>
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
var dataContext = new TestDataContext { BoolProperty = value };
|
|
window.DataContext = dataContext;
|
|
|
|
var result = Assert.IsType<bool>(textBlock.Tag);
|
|
Assert.Equal(!value, result);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Can_Use_Implicit_Conversions()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:ImplicitConvertible'
|
|
x:CompileBindings='True'>
|
|
<TextBlock Name='textBlock'>
|
|
<TextBlock.Background>
|
|
<SolidColorBrush Color='{{Binding}}'/>
|
|
</TextBlock.Background>
|
|
</TextBlock>
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
var dataContext = new ImplicitConvertible("Green");
|
|
window.DataContext = dataContext;
|
|
|
|
var brush = Assert.IsType<SolidColorBrush>(textBlock.Background);
|
|
Assert.Equal(Colors.Green, brush.Color);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Can_Bind_Brush_To_Hex_String()
|
|
{
|
|
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.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestData'
|
|
x:CompileBindings='True'>
|
|
<TextBlock Name='textBlock' Background='{{Binding StringProperty}}'/>
|
|
</Window>";
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
|
|
var textBlock = window.FindControl<TextBlock>("textBlock");
|
|
|
|
var dataContext = new TestData { StringProperty = "#ff0000" };
|
|
window.DataContext = dataContext;
|
|
|
|
var brush = Assert.IsType<ImmutableSolidColorBrush>(textBlock!.Background);
|
|
Assert.Equal(Colors.Red, brush.Color);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void ResolvesElementNameDataContextTypeBasedOnContext()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(@"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'
|
|
x:Name='MyWindow'>
|
|
<TextBlock Text='{CompiledBinding ElementName=MyWindow, Path=DataContext.StringProperty}' Name='textBlock' />
|
|
</Window>");
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
var dataContext = new TestDataContext
|
|
{
|
|
StringProperty = "foobar"
|
|
};
|
|
|
|
window.DataContext = dataContext;
|
|
|
|
Assert.Equal(dataContext.StringProperty, textBlock.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void ResolvesElementNameDataContextTypeBasedOnContextShortSyntax()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(@"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'
|
|
x:Name='MyWindow'>
|
|
<TextBlock Text='{CompiledBinding #MyWindow.DataContext.StringProperty}' Name='textBlock' />
|
|
</Window>");
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
var dataContext = new TestDataContext
|
|
{
|
|
StringProperty = "foobar"
|
|
};
|
|
|
|
window.DataContext = dataContext;
|
|
|
|
Assert.Equal(dataContext.StringProperty, textBlock.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void TypeCastWorksWithElementNameDataContext()
|
|
{
|
|
// By default, DataContext will infer DataType from the XAML context, which will be local:TestDataContext here.
|
|
// But developer should be able to re-define this type via type casing, if they know better.
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(@"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'
|
|
x:Name='MyWindow'>
|
|
<Panel>
|
|
<TextBlock Text='{CompiledBinding $parent.((Button)DataContext).Tag}' Name='textBlock' />
|
|
</Panel>
|
|
</Window>");
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
var panelDataContext = new Button { Tag = "foo" };
|
|
((Panel)window.Content!).DataContext = panelDataContext;
|
|
|
|
Assert.Equal(panelDataContext.Tag, textBlock.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void ResolvesParentDataContextTypeBasedOnContext()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(@"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'
|
|
x:Name='MyWindow'>
|
|
<Panel>
|
|
<TextBlock Text='{CompiledBinding $parent[Panel].DataContext.StringProperty}' Name='textBlock' />
|
|
</Panel>
|
|
</Window>");
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
var dataContext = new TestDataContext
|
|
{
|
|
StringProperty = "foobar"
|
|
};
|
|
|
|
window.DataContext = dataContext;
|
|
|
|
Assert.Equal(dataContext.StringProperty, textBlock.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void ResolvesParentDataContextTypeBasedOnContextShortSyntax()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(@"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'
|
|
x:Name='MyWindow'>
|
|
<Panel>
|
|
<TextBlock Text='{CompiledBinding $parent.DataContext.StringProperty}' Name='textBlock' />
|
|
</Panel>
|
|
</Window>");
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
var dataContext = new TestDataContext
|
|
{
|
|
StringProperty = "foobar"
|
|
};
|
|
|
|
window.DataContext = dataContext;
|
|
|
|
Assert.Equal(dataContext.StringProperty, textBlock.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Resolves_Nested_Generic_DataTypes()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(@"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='{x:Type local:TestDataContext+NestedGeneric, x:TypeArguments=x:String}'
|
|
x:Name='MyWindow'>
|
|
<Panel>
|
|
<TextBlock Text='{CompiledBinding Value}' Name='textBlock' />
|
|
</Panel>
|
|
</Window>");
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
|
|
var dataContext = new TestDataContext
|
|
{
|
|
NestedGenericString = new TestDataContext.NestedGeneric<string>
|
|
{
|
|
Value = "10"
|
|
}
|
|
};
|
|
|
|
window.DataContext = dataContext.NestedGenericString;
|
|
|
|
Assert.Equal(dataContext.NestedGenericString.Value, textBlock.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Emits_TypedBindingExpression_For_Simple_DataContext_Binding()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(@"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<TextBlock Text='{CompiledBinding StringProperty}' Name='textBlock' />
|
|
</Window>");
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
window.DataContext = new TestDataContext { StringProperty = "hello" };
|
|
|
|
var expression = BindingOperations.GetBindingExpressionBase(textBlock, TextBlock.TextProperty);
|
|
Assert.IsType<TypedBindingExpression<TestDataContext, string>>(expression);
|
|
Assert.Equal("hello", textBlock.Text);
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("OneWay")]
|
|
[InlineData("TwoWay")]
|
|
[InlineData("OneWayToSource")]
|
|
[InlineData("OneTime")]
|
|
public void Emits_TypedBindingExpression_For_All_Standard_Modes(string mode)
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load($@"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<TextBlock Text='{{CompiledBinding StringProperty, Mode={mode}}}' Name='textBlock' />
|
|
</Window>");
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
window.DataContext = new TestDataContext { StringProperty = "x" };
|
|
|
|
var expression = BindingOperations.GetBindingExpressionBase(textBlock, TextBlock.TextProperty);
|
|
Assert.IsType<TypedBindingExpression<TestDataContext, string>>(expression);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Emits_TypedBindingExpression_For_Binding_With_CompileBindings_True()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(@"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'
|
|
x:CompileBindings='True'>
|
|
<TextBlock Text='{Binding StringProperty}' Name='textBlock' />
|
|
</Window>");
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
window.DataContext = new TestDataContext { StringProperty = "hi" };
|
|
|
|
var expression = BindingOperations.GetBindingExpressionBase(textBlock, TextBlock.TextProperty);
|
|
Assert.IsType<TypedBindingExpression<TestDataContext, string>>(expression);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Falls_Back_To_BindingExpression_For_Nested_Path()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(@"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<TextBlock Text='{CompiledBinding NestedGenericString.Value}' Name='textBlock' />
|
|
</Window>");
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
window.DataContext = new TestDataContext { NestedGenericString = new TestDataContext.NestedGeneric<string> { Value = "v" } };
|
|
|
|
var expression = BindingOperations.GetBindingExpressionBase(textBlock, TextBlock.TextProperty);
|
|
Assert.IsType<BindingExpression>(expression);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Falls_Back_To_BindingExpression_When_Converter_Set()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(@"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<TextBlock Text='{CompiledBinding StringProperty, Converter={x:Static local:AppendConverter.Instance}, ConverterParameter=suffix}' Name='textBlock' />
|
|
</Window>");
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
window.DataContext = new TestDataContext { StringProperty = "x" };
|
|
|
|
var expression = BindingOperations.GetBindingExpressionBase(textBlock, TextBlock.TextProperty);
|
|
Assert.IsType<BindingExpression>(expression);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Falls_Back_To_BindingExpression_For_DataValidation_Enabled_Property()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
// TextBox.Text enables data validation, which TypedBindingExpression does not
|
|
// support, so the binding must fall back to the untyped BindingExpression even
|
|
// though it is otherwise eligible for the typed path.
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(@"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<TextBox Text='{CompiledBinding StringProperty}' Name='textBox' />
|
|
</Window>");
|
|
var textBox = window.GetControl<TextBox>("textBox");
|
|
window.DataContext = new TestDataContext { StringProperty = "hello" };
|
|
|
|
var expression = BindingOperations.GetBindingExpressionBase(textBox, TextBox.TextProperty);
|
|
Assert.IsType<BindingExpression>(expression);
|
|
Assert.Equal("hello", textBox.Text);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Falls_Back_To_BindingExpression_When_StringFormat_Set()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(@"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<TextBlock Text='{CompiledBinding DecimalValue, StringFormat=c2}' Name='textBlock' />
|
|
</Window>");
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
window.DataContext = new TestDataContext();
|
|
|
|
var expression = BindingOperations.GetBindingExpressionBase(textBlock, TextBlock.TextProperty);
|
|
Assert.IsType<BindingExpression>(expression);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Falls_Back_To_BindingExpression_For_Negated_Binding()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(@"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<TextBlock Tag='{CompiledBinding !BoolProperty}' Name='textBlock' />
|
|
</Window>");
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
window.DataContext = new TestDataContext { BoolProperty = true };
|
|
|
|
var expression = BindingOperations.GetBindingExpressionBase(textBlock, TextBlock.TagProperty);
|
|
Assert.IsType<BindingExpression>(expression);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void Falls_Back_To_BindingExpression_For_DataContext_Target()
|
|
{
|
|
using (UnitTestApplication.Start(TestServices.StyledWindow))
|
|
{
|
|
var window = (Window)AvaloniaRuntimeXamlLoader.Load(@"
|
|
<Window xmlns='https://github.com/avaloniaui'
|
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
|
|
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions;assembly=Avalonia.Markup.Xaml.UnitTests'
|
|
x:DataType='local:TestDataContext'>
|
|
<TextBlock DataContext='{CompiledBinding StringProperty}' Name='textBlock' />
|
|
</Window>");
|
|
var textBlock = window.GetControl<TextBlock>("textBlock");
|
|
window.DataContext = new TestDataContext { StringProperty = "x" };
|
|
|
|
var expression = BindingOperations.GetBindingExpressionBase(textBlock, StyledElement.DataContextProperty);
|
|
Assert.IsType<BindingExpression>(expression);
|
|
}
|
|
}
|
|
|
|
static void Throws(string type, Action cb)
|
|
{
|
|
try
|
|
{
|
|
cb();
|
|
}
|
|
catch (Exception e) when (e.GetType().Name == type)
|
|
{
|
|
return;
|
|
}
|
|
|
|
throw new Exception("Expected " + type);
|
|
}
|
|
|
|
static void PerformClick(Button button)
|
|
{
|
|
button.RaiseEvent(new KeyEventArgs
|
|
{
|
|
RoutedEvent = InputElement.KeyDownEvent,
|
|
Key = Key.Enter,
|
|
});
|
|
}
|
|
}
|
|
|
|
public interface INonIntegerIndexer
|
|
{
|
|
string this[string key] { get; set; }
|
|
}
|
|
|
|
public interface INonIntegerIndexerDerived : INonIntegerIndexer
|
|
{ }
|
|
|
|
public interface IHasProperty
|
|
{
|
|
string? StringProperty { get; set; }
|
|
}
|
|
|
|
public interface IHasPropertyDerived : IHasProperty
|
|
{ }
|
|
|
|
public interface IHasExplicitProperty
|
|
{
|
|
string ExplicitProperty { get; }
|
|
}
|
|
|
|
public class AppendConverter : IValueConverter
|
|
{
|
|
public static IValueConverter Instance { get; } = new AppendConverter();
|
|
|
|
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
|
=> string.Format("{0}+{1}+{2}", value, parameter, culture);
|
|
|
|
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
|
=> throw new NotImplementedException();
|
|
|
|
}
|
|
|
|
public class TestData
|
|
{
|
|
public string? StringProperty { get; set; }
|
|
}
|
|
|
|
public class OuterClass
|
|
{
|
|
public class NestedClass
|
|
{
|
|
public string NestedProperty { get; set; } = "nested value";
|
|
}
|
|
}
|
|
|
|
public class TestDataContextBaseClass {}
|
|
|
|
public class TestItemsCollectionDataContext : TestDataContextBaseClass
|
|
{
|
|
public ObservableCollection<TestData> Items { get; } = new ObservableCollection<TestData>();
|
|
}
|
|
|
|
public class TestDataContext : TestDataContextBaseClass, IHasPropertyDerived, IHasExplicitProperty
|
|
{
|
|
public bool BoolProperty { get; set; }
|
|
public string? StringProperty { get; set; }
|
|
|
|
public Task<string>? TaskProperty { get; set; }
|
|
|
|
public IObservable<string>? ObservableProperty { get; set; }
|
|
|
|
public ObservableCollection<string> ObservableCollectionProperty { get; set; } = new ObservableCollection<string>();
|
|
|
|
public string[]? ArrayProperty { get; set; }
|
|
|
|
public object[]? ObjectsArrayProperty { get; set; }
|
|
|
|
public List<string> ListProperty { get; set; } = new List<string>();
|
|
|
|
public NonIntegerIndexer NonIntegerIndexerProperty { get; set; } = new NonIntegerIndexer();
|
|
|
|
public INonIntegerIndexerDerived NonIntegerIndexerInterfaceProperty => NonIntegerIndexerProperty;
|
|
|
|
public NestedGeneric<string>? NestedGenericString { get; init; }
|
|
|
|
string IHasExplicitProperty.ExplicitProperty => "Hello";
|
|
|
|
public string ExplicitProperty => "Bye";
|
|
|
|
public static string StaticProperty => "World";
|
|
|
|
public ListItemCollectionView<int> GenericProperty { get; } = new();
|
|
|
|
public const decimal ExpectedDecimal = 15.756m;
|
|
public decimal DecimalValue { get; set; } = ExpectedDecimal;
|
|
|
|
public class NonIntegerIndexer : NotifyingBase, INonIntegerIndexerDerived
|
|
{
|
|
private readonly Dictionary<string, string> _storage = new Dictionary<string, string>();
|
|
|
|
public string this[string key]
|
|
{
|
|
get => _storage[key];
|
|
set
|
|
{
|
|
_storage[key] = value;
|
|
RaisePropertyChanged(CommonPropertyNames.IndexerName);
|
|
}
|
|
}
|
|
}
|
|
|
|
public class NestedGeneric<T>
|
|
{
|
|
public T? Value { get; set; }
|
|
}
|
|
}
|
|
|
|
public class ListItemCollectionView<T> : List<T>
|
|
{
|
|
public T? CurrentItem { get; set; }
|
|
}
|
|
|
|
public class MethodDataContext
|
|
{
|
|
public void Action() { }
|
|
|
|
public object Func() => 1;
|
|
public object Func2(object i) => i;
|
|
|
|
public void CustomDelegateTypeVoid(object i) { }
|
|
public object CustomDelegateTypeInt(object i) => i;
|
|
}
|
|
|
|
public class MethodAsCommandDataContextBase
|
|
{
|
|
public virtual void VirtualObjectMethod(object? i) { }
|
|
|
|
public virtual void VirtualInt32Method(int i) { }
|
|
|
|
public virtual void VirtualStringMethod(string i) { }
|
|
|
|
public void MethodWithNewSlot(int i) { }
|
|
}
|
|
|
|
public class MethodAsCommandDataContext : MethodAsCommandDataContextBase, INotifyPropertyChanged
|
|
{
|
|
public event PropertyChangedEventHandler? PropertyChanged;
|
|
|
|
public void Method() => Value = "Called";
|
|
|
|
public void ObjectMethod(object i) => Value = $"Called ObjectMethod with {i}";
|
|
|
|
public void Int32Method(int i) => Value = $"Called Int32Method with {i}";
|
|
|
|
public void StringMethod(string i) => Value = $"Called StringMethod with {i}";
|
|
|
|
public void MethodWithOverloads() => Value = "Called MethodWithOverloads without parameter";
|
|
public void MethodWithOverloads(int i) => Value = $"Called MethodWithOverloads with Int32 {i}";
|
|
public void MethodWithOverloads(string i) => Value = $"Called MethodWithOverloads with String {i}";
|
|
public void MethodWithOverloads(object i) => Value = $"Called MethodWithOverloads with Object {i}";
|
|
|
|
public void MethodWithOverloads2() => Value = "Called MethodWithOverloads2 without parameter";
|
|
public void MethodWithOverloads2(int i) => Value = $"Called MethodWithOverloads2 with Int32 {i}";
|
|
public void MethodWithOverloads2(string i) => Value = $"Called MethodWithOverloads2 with String {i}";
|
|
|
|
public void MethodWithOverloads3() => Value = "Called MethodWithOverloads3 without parameter";
|
|
public void MethodWithOverloads3(int a, int b) => throw new InvalidOperationException("MethodWithOverloads3 should not be called");
|
|
public void MethodWithOverloads3(string a, string b) => throw new InvalidOperationException("MethodWithOverloads3 should not be called");
|
|
|
|
public void MethodWithOverloads4(int a, int b) => throw new InvalidOperationException("MethodWithOverloads4 should not be called");
|
|
public void MethodWithOverloads4(string a, string b) => throw new InvalidOperationException("MethodWithOverloads4 should not be called");
|
|
|
|
public override void VirtualObjectMethod(object? i)
|
|
=> Value = $"Called VirtualObjectMethod with {i}";
|
|
|
|
public override void VirtualInt32Method(int i)
|
|
=> Value = $"Called VirtualInt32Method with {i}";
|
|
|
|
public override void VirtualStringMethod(string i)
|
|
=> Value = $"Called VirtualStringMethod with {i}";
|
|
|
|
public new void MethodWithNewSlot(int i)
|
|
=> Value = $"Called MethodWithNewSlot with {i}";
|
|
|
|
public string Value { get; private set; } = "Not called";
|
|
|
|
private object? _parameter;
|
|
|
|
public object? Parameter
|
|
{
|
|
get => _parameter;
|
|
set
|
|
{
|
|
if (_parameter == value)
|
|
{
|
|
return;
|
|
}
|
|
_parameter = value;
|
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Parameter)));
|
|
}
|
|
}
|
|
|
|
public void Do(object parameter)
|
|
{
|
|
Value = $"Do {parameter}";
|
|
}
|
|
|
|
[DependsOn(nameof(Parameter))]
|
|
public bool CanDo(object parameter)
|
|
{
|
|
return ReferenceEquals(null, Parameter) == false;
|
|
}
|
|
}
|
|
|
|
public class CustomDataTemplate : IDataTemplate
|
|
{
|
|
[DataType]
|
|
public Type? FancyDataType { get; set; }
|
|
|
|
[Content]
|
|
[TemplateContent]
|
|
public object? Content { get; set; }
|
|
|
|
public bool Match(object? data) => FancyDataType?.IsInstanceOfType(data) ?? true;
|
|
|
|
public Control? Build(object? data) => TemplateContent.Load(Content)?.Result;
|
|
}
|
|
|
|
public class CustomDataTemplateInherit : CustomDataTemplate { }
|
|
|
|
public class AssignBindingControl : Control
|
|
{
|
|
[AssignBinding] public BindingBase? X { get; set; }
|
|
}
|
|
|
|
public class DataGridLikeControl : Control
|
|
{
|
|
public static readonly DirectProperty<DataGridLikeControl, IEnumerable?> ItemsProperty =
|
|
AvaloniaProperty.RegisterDirect<DataGridLikeControl, IEnumerable?>(
|
|
nameof(Items),
|
|
x => x.Items,
|
|
(x, v) => x.Items = v);
|
|
|
|
private IEnumerable? _items;
|
|
|
|
public IEnumerable? Items
|
|
{
|
|
get => _items;
|
|
set => SetAndRaise(ItemsProperty, ref _items, value);
|
|
}
|
|
|
|
public AvaloniaList<DataGridLikeColumn> Columns { get; } = new();
|
|
}
|
|
|
|
public class DataGridLikeColumn
|
|
{
|
|
[AssignBinding]
|
|
[InheritDataTypeFromItems(nameof(DataGridLikeControl.Items), AncestorType = typeof(DataGridLikeControl))]
|
|
public BindingBase? Binding { get; set; }
|
|
|
|
[InheritDataTypeFromItems(nameof(DataGridLikeControl.Items), AncestorType = typeof(DataGridLikeControl))]
|
|
public IDataTemplate? Template { get; set; }
|
|
}
|
|
|
|
public class DataGridLikeControlInheritor : DataGridLikeControl
|
|
{ }
|
|
|
|
public class ImplicitConvertible
|
|
{
|
|
public ImplicitConvertible(string value) => Value = value;
|
|
|
|
public string Value { get; }
|
|
|
|
public static implicit operator Avalonia.Media.Color(ImplicitConvertible value)
|
|
{
|
|
return Color.Parse(value.Value);
|
|
}
|
|
}
|
|
}
|
|
|