using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Controls;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Templates;
using Avalonia.Markup.Data;
using Avalonia.Media;
using Avalonia.Styling;
using Avalonia.UnitTests;
using Avalonia.VisualTree;
using Xunit;
namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
{
public class DynamicResourceExtensionTests : XamlTestBase
{
[Fact]
public void DynamicResource_Can_Be_Assigned_To_Property()
{
var xaml = @"
#ff506070
";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var border = userControl.FindControl("border");
DelayedBinding.ApplyBindings(border);
var brush = (ISolidColorBrush)border.Background;
Assert.Equal(0xff506070, brush.Color.ToUInt32());
}
[Fact]
public void DynamicResource_Can_Be_Assigned_To_Attached_Property()
{
var xaml = @"
5
";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var border = userControl.FindControl("border");
DelayedBinding.ApplyBindings(border);
Assert.Equal(5, Grid.GetColumn(border));
}
[Fact]
public void DynamicResource_From_Style_Can_Be_Assigned_To_Property()
{
var xaml = @"
";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var border = userControl.FindControl("border");
DelayedBinding.ApplyBindings(border);
var brush = (ISolidColorBrush)border.Background;
Assert.Equal(0xff506070, brush.Color.ToUInt32());
}
[Fact]
public void DynamicResource_From_MergedDictionary_Can_Be_Assigned_To_Property()
{
var xaml = @"
#ff506070
";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var border = userControl.FindControl("border");
DelayedBinding.ApplyBindings(border);
var brush = (ISolidColorBrush)border.Background;
Assert.Equal(0xff506070, brush.Color.ToUInt32());
}
[Fact]
public void DynamicResource_From_MergedDictionary_In_Style_Can_Be_Assigned_To_Property()
{
var xaml = @"
";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var border = userControl.FindControl("border");
DelayedBinding.ApplyBindings(border);
var brush = (ISolidColorBrush)border.Background;
Assert.Equal(0xff506070, brush.Color.ToUInt32());
}
[Fact]
public void DynamicResource_From_Application_Can_Be_Assigned_To_Property_In_Window()
{
using (StyledWindow())
{
Application.Current.Resources.Add("brush", new SolidColorBrush(0xff506070));
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var border = window.FindControl("border");
var brush = (SolidColorBrush)border.Background;
Assert.Equal(0xff506070, brush.Color.ToUInt32());
}
}
[Fact]
public void DynamicResource_From_Application_Can_Be_Assigned_To_Property_In_UserControl()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
Application.Current.Resources.Add("brush", new SolidColorBrush(0xff506070));
var xaml = @"
";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var border = userControl.FindControl("border");
// We don't actually know where the global styles are until we attach the control
// to a window, as Window has StylingParent set to Application.
var window = new Window { Content = userControl };
window.Show();
var brush = (SolidColorBrush)border.Background;
Assert.Equal(0xff506070, brush.Color.ToUInt32());
}
}
[Fact]
public void DynamicResource_Can_Be_Assigned_To_Setter()
{
using (StyledWindow())
{
var xaml = @"
#ff506070
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var button = window.FindControl("button");
var brush = (ISolidColorBrush)button.Background;
Assert.Equal(0xff506070, brush.Color.ToUInt32());
}
}
[Fact]
public void DynamicResource_From_Style_Can_Be_Assigned_To_Setter()
{
using (StyledWindow())
{
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var button = window.FindControl("button");
var brush = (ISolidColorBrush)button.Background;
Assert.Equal(0xff506070, brush.Color.ToUInt32());
}
}
[Fact]
public void DynamicResource_Can_Be_Assigned_To_Setter_In_Styles_File()
{
var documents = new[]
{
new RuntimeXamlLoaderDocument(new Uri("avares://Tests/Style.xaml"), @"
#ff506070
"),
new RuntimeXamlLoaderDocument(@"
")
};
using (StyledWindow())
{
var compiled = AvaloniaRuntimeXamlLoader.LoadGroup(documents);
var window = Assert.IsType(compiled[1]);
var border = window.FindControl("border");
var brush = (ISolidColorBrush)border.Background;
Assert.Equal(0xff506070, brush.Color.ToUInt32());
}
}
[Fact]
public void DynamicResource_Can_Be_Assigned_To_Property_In_ControlTemplate_In_Styles_File()
{
var documents = new[]
{
new RuntimeXamlLoaderDocument(new Uri("avares://Tests/Style.xaml"), @"
#ff506070
"),
new RuntimeXamlLoaderDocument(@"
")
};
using (StyledWindow())
{
var compiled = AvaloniaRuntimeXamlLoader.LoadGroup(documents);
var window = Assert.IsType(compiled[1]);
var button = window.FindControl("button");
window.Show();
var border = (Border)button.GetVisualChildren().Single();
var brush = (ISolidColorBrush)border.Background;
Assert.Equal(0xff506070, brush.Color.ToUInt32());
}
}
[Fact]
public void DynamicResource_Can_Be_Assigned_To_Resource_Property()
{
var xaml = @"
#ff506070
";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var border = userControl.FindControl("border");
DelayedBinding.ApplyBindings(border);
var brush = (SolidColorBrush)border.Background;
Assert.Equal(0xff506070, brush.Color.ToUInt32());
}
[Fact]
public void DynamicResource_Can_Be_Assigned_To_Resource_Property_In_Application()
{
var xaml = @"
#ff506070
";
var application = (Application)AvaloniaRuntimeXamlLoader.Load(xaml);
var brush = (SolidColorBrush)application.Resources["brush"];
Assert.Equal(0xff506070, brush.Color.ToUInt32());
}
[Fact]
public void DynamicResource_Can_Be_Assigned_To_ItemTemplate_Property()
{
var xaml = @"
";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var listBox = userControl.FindControl("listBox");
DelayedBinding.ApplyBindings(listBox);
Assert.NotNull(listBox.ItemTemplate);
}
[Fact]
public void DynamicResource_Tracks_Added_Resource()
{
var xaml = @"
";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var border = userControl.FindControl("border");
DelayedBinding.ApplyBindings(border);
Assert.Null(border.Background);
userControl.Resources.Add("brush", new SolidColorBrush(0xff506070));
var brush = (SolidColorBrush)border.Background;
Assert.NotNull(brush);
Assert.Equal(0xff506070, brush.Color.ToUInt32());
}
[Fact]
public void DynamicResource_Tracks_Added_Style_Resource()
{
var xaml = @"
";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var border = userControl.FindControl("border");
DelayedBinding.ApplyBindings(border);
Assert.Null(border.Background);
userControl.Styles.Resources.Add("brush", new SolidColorBrush(0xff506070));
var brush = (SolidColorBrush)border.Background;
Assert.NotNull(brush);
Assert.Equal(0xff506070, brush.Color.ToUInt32());
}
[Fact]
public void DynamicResource_Tracks_Added_Nested_Style_Resource()
{
var xaml = @"
";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var border = userControl.FindControl("border");
DelayedBinding.ApplyBindings(border);
Assert.Null(border.Background);
((Style)userControl.Styles[0]).Resources.Add("brush", new SolidColorBrush(0xff506070));
var brush = (SolidColorBrush)border.Background;
Assert.NotNull(brush);
Assert.Equal(0xff506070, brush.Color.ToUInt32());
}
[Fact]
public void DynamicResource_Tracks_Added_MergedResource()
{
var xaml = @"
";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var border = userControl.FindControl("border");
DelayedBinding.ApplyBindings(border);
Assert.Null(border.Background);
((IResourceDictionary)userControl.Resources.MergedDictionaries[0]).Add("brush", new SolidColorBrush(0xff506070));
var brush = (SolidColorBrush)border.Background;
Assert.NotNull(brush);
Assert.Equal(0xff506070, brush.Color.ToUInt32());
}
[Fact]
public void DynamicResource_Tracks_Added_MergedResource_Dictionary()
{
var xaml = @"
";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var border = userControl.FindControl("border");
DelayedBinding.ApplyBindings(border);
Assert.Null(border.Background);
var dictionary = new ResourceDictionary
{
{ "brush", new SolidColorBrush(0xff506070) },
};
userControl.Resources.MergedDictionaries.Add(dictionary);
var brush = (SolidColorBrush)border.Background;
Assert.NotNull(brush);
Assert.Equal(0xff506070, brush.Color.ToUInt32());
}
[Fact]
public void DynamicResource_Tracks_Added_Style_MergedResource_Dictionary()
{
var xaml = @"
";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var border = userControl.FindControl("border");
DelayedBinding.ApplyBindings(border);
Assert.Null(border.Background);
var dictionary = new ResourceDictionary
{
{ "brush", new SolidColorBrush(0xff506070) },
};
((Style)userControl.Styles[0]).Resources.MergedDictionaries.Add(dictionary);
var brush = (SolidColorBrush)border.Background;
Assert.NotNull(brush);
Assert.Equal(0xff506070, brush.Color.ToUInt32());
}
[Fact]
public void DynamicResource_Can_Be_Found_Across_Xaml_Style_Files()
{
var documents = new[]
{
new RuntimeXamlLoaderDocument(new Uri("avares://Tests/Style1.xaml"), @"
"),
new RuntimeXamlLoaderDocument(new Uri("avares://Tests/Style2.xaml"), @"
"),
new RuntimeXamlLoaderDocument(@"
")
};
using (StyledWindow())
{
var compiled = AvaloniaRuntimeXamlLoader.LoadGroup(documents);
var window = Assert.IsType(compiled[2]);
var border = window.FindControl("border");
var borderBrush = (ISolidColorBrush)border.Background;
Assert.NotNull(borderBrush);
Assert.Equal(0xffff0000, borderBrush.Color.ToUInt32());
}
}
[Fact]
public void DynamicResource_Can_Be_Found_In_Nested_Style_File()
{
var documents = new[]
{
new RuntimeXamlLoaderDocument(new Uri("avares://Tests/Style1.xaml"), @"
"),
new RuntimeXamlLoaderDocument(new Uri("avares://Tests/Style2.xaml"), @"
"),
new RuntimeXamlLoaderDocument(@"
")
};
using (StyledWindow())
{
var compiled = AvaloniaRuntimeXamlLoader.LoadGroup(documents);
var window = Assert.IsType(compiled[2]);
var border = window.FindControl("border");
var borderBrush = (ISolidColorBrush)border.Background;
Assert.NotNull(borderBrush);
Assert.Equal(0xffff0000, borderBrush.Color.ToUInt32());
}
}
[Fact]
public void Control_Property_Is_Updated_When_Parent_Is_Changed()
{
using (StyledWindow())
{
var xaml = @"
#ff506070
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var border = window.FindControl("border");
DelayedBinding.ApplyBindings(border);
var brush = (ISolidColorBrush)border.Background;
Assert.Equal(0xff506070, brush.Color.ToUInt32());
window.Content = null;
Assert.Null(border.Background);
window.Content = border;
brush = (ISolidColorBrush)border.Background;
Assert.Equal(0xff506070, brush.Color.ToUInt32());
}
}
[Fact]
public void Resource_With_DynamicResource_Is_Updated_When_Added_To_Parent()
{
var xaml = @"
";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var border = userControl.FindControl("border");
DelayedBinding.ApplyBindings(border);
var brush = (SolidColorBrush)border.Background;
Assert.Equal(0u, brush.Color.ToUInt32());
brush.GetObservable(SolidColorBrush.ColorProperty).Subscribe(_ => { });
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var window = new Window
{
Resources =
{
{ "color", Colors.Red }
},
Content = userControl,
};
window.Show();
Assert.Equal(Colors.Red, brush.Color);
}
}
[Fact]
public void MergedDictionary_Resource_With_DynamicResource_Is_Updated_When_Added_To_Parent()
{
var xaml = @"
";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var border = userControl.FindControl("border");
DelayedBinding.ApplyBindings(border);
var brush = (SolidColorBrush)border.Background;
Assert.Equal(0u, brush.Color.ToUInt32());
brush.GetObservable(SolidColorBrush.ColorProperty).Subscribe(_ => { });
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var window = new Window
{
Resources =
{
{ "color", Colors.Red }
},
Content = userControl,
};
window.Show();
Assert.Equal(Colors.Red, brush.Color);
}
}
[Fact]
public void Style_Resource_With_DynamicResource_Is_Updated_When_Added_To_Parent()
{
var xaml = @"
";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var border = userControl.FindControl("border");
DelayedBinding.ApplyBindings(border);
var brush = (SolidColorBrush)border.Background;
Assert.Equal(0u, brush.Color.ToUInt32());
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var window = new Window
{
Resources =
{
{ "color", Colors.Red }
},
Content = userControl,
};
window.Show();
Assert.Equal(Colors.Red, brush.Color);
}
}
[Fact]
public void Automatically_Converts_Color_To_SolidColorBrush()
{
var xaml = @"
#ff506070
";
var userControl = (UserControl)AvaloniaRuntimeXamlLoader.Load(xaml);
var border = userControl.FindControl("border");
var brush = (ISolidColorBrush)border.Background;
Assert.Equal(0xff506070, brush.Color.ToUInt32());
}
[Fact]
public void Resource_In_Non_Matching_Style_Is_Not_Resolved()
{
using var app = StyledWindow();
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var border = window.FindControl("border");
Assert.Equal("bar", border.Tag);
var resourceProvider = (TrackingResourceProvider)window.Resources.MergedDictionaries[0];
Assert.Contains("bar", resourceProvider.RequestedResources);
Assert.DoesNotContain("foo", resourceProvider.RequestedResources);
}
[Fact]
public void Resource_In_Non_Active_Style_Is_Not_Resolved()
{
using var app = StyledWindow();
var xaml = @"
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var border = window.FindControl("border");
Assert.Equal("bar", border.Tag);
var resourceProvider = (TrackingResourceProvider)window.Resources.MergedDictionaries[0];
Assert.Contains("bar", resourceProvider.RequestedResources);
Assert.DoesNotContain("foo", resourceProvider.RequestedResources);
}
[Fact]
public void Can_Detach_Control_With_DynamicResource_ControlTheme_That_Contains_DynamicResource()
{
using var app = UnitTestApplication.Start(TestServices.StyledWindow);
var xaml = $@"
Blue
";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var target = Assert.IsType(window.Content);
window.Show();
Assert.Equal(Colors.Blue, ((ISolidColorBrush)target.Background).Color);
window.Content = null;
}
[Fact]
public void Handles_Clearing_Resources_With_Dynamic_Theme_In_Dynamic_Template()
{
// Issue #14753
using var app = UnitTestApplication.Start(TestServices.StyledWindow);
var xaml = """
Blue
""";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
window.Show();
var button = Assert.IsType(window.Content);
var border = Assert.IsType(button.GetVisualChildren().Single());
var background = Assert.IsAssignableFrom(border.Background);
Assert.Equal(Colors.Blue, background.Color);
window.Resources.Clear();
}
private IDisposable StyledWindow(params (string, string)[] assets)
{
var services = TestServices.StyledWindow.With(
assetLoader: new MockAssetLoader(assets),
theme: () => new Styles
{
WindowStyle(),
});
return UnitTestApplication.Start(services);
}
private Style WindowStyle()
{
return new Style(x => x.OfType())
{
Setters =
{
new Setter(
Window.TemplateProperty,
new FuncControlTemplate((x, scope) =>
new ContentPresenter
{
Name = "PART_ContentPresenter",
[!ContentPresenter.ContentProperty] = x[!Window.ContentProperty],
}.RegisterInNameScope(scope)))
}
};
}
}
public class TrackingResourceProvider : ResourceProvider
{
public override bool HasResources => true;
public List RequestedResources { get; } = new List();
public override bool TryGetResource(object key, ThemeVariant themeVariant, out object value)
{
RequestedResources.Add(key);
value = key;
return true;
}
}
}