4 changed files with 328 additions and 1 deletions
@ -0,0 +1,41 @@ |
|||||
|
// Copyright (c) The Avalonia Project. All rights reserved.
|
||||
|
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
||||
|
|
||||
|
using System; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Data; |
||||
|
using Portable.Xaml.Markup; |
||||
|
|
||||
|
namespace Avalonia.Markup.Xaml.MarkupExtensions |
||||
|
{ |
||||
|
public class DynamicResourceExtension : MarkupExtension, IBinding |
||||
|
{ |
||||
|
public DynamicResourceExtension() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public DynamicResourceExtension(string resourceKey) |
||||
|
{ |
||||
|
ResourceKey = resourceKey; |
||||
|
} |
||||
|
|
||||
|
public string ResourceKey { get; set; } |
||||
|
|
||||
|
public override object ProvideValue(IServiceProvider serviceProvider) => this; |
||||
|
|
||||
|
InstancedBinding IBinding.Initiate( |
||||
|
IAvaloniaObject target, |
||||
|
AvaloniaProperty targetProperty, |
||||
|
object anchor, |
||||
|
bool enableDataValidation) |
||||
|
{ |
||||
|
if (target is IControl control) |
||||
|
{ |
||||
|
var resource = control.FindResource(ResourceKey); |
||||
|
return new InstancedBinding(resource); |
||||
|
} |
||||
|
|
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,285 @@ |
|||||
|
// Copyright (c) The Avalonia Project. All rights reserved.
|
||||
|
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Controls.Presenters; |
||||
|
using Avalonia.Controls.Templates; |
||||
|
using Avalonia.Markup.Xaml.Data; |
||||
|
using Avalonia.Media; |
||||
|
using Avalonia.Styling; |
||||
|
using Avalonia.UnitTests; |
||||
|
using Avalonia.VisualTree; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions |
||||
|
{ |
||||
|
public class DynamicResourceTests |
||||
|
{ |
||||
|
[Fact] |
||||
|
public void DynamicResource_Can_Be_Assigned_To_Property() |
||||
|
{ |
||||
|
var xaml = @"
|
||||
|
<UserControl xmlns='https://github.com/avaloniaui'
|
||||
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
|
||||
|
<UserControl.Resources> |
||||
|
<SolidColorBrush x:Key='brush'>#ff506070</SolidColorBrush> |
||||
|
</UserControl.Resources> |
||||
|
|
||||
|
<Border Name='border' Background='{DynamicResource brush}'/> |
||||
|
</UserControl>";
|
||||
|
|
||||
|
var loader = new AvaloniaXamlLoader(); |
||||
|
var userControl = (UserControl)loader.Load(xaml); |
||||
|
var border = userControl.FindControl<Border>("border"); |
||||
|
|
||||
|
DelayedBinding.ApplyBindings(border); |
||||
|
|
||||
|
var brush = (SolidColorBrush)border.Background; |
||||
|
Assert.Equal(0xff506070, brush.Color.ToUint32()); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void DynamicResource_From_Style_Can_Be_Assigned_To_Property() |
||||
|
{ |
||||
|
var xaml = @"
|
||||
|
<UserControl xmlns='https://github.com/avaloniaui'
|
||||
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
|
||||
|
<UserControl.Styles> |
||||
|
<Style> |
||||
|
<Style.Resources> |
||||
|
<SolidColorBrush x:Key='brush'>#ff506070</SolidColorBrush> |
||||
|
</Style.Resources> |
||||
|
</Style> |
||||
|
</UserControl.Styles> |
||||
|
|
||||
|
<Border Name='border' Background='{DynamicResource brush}'/> |
||||
|
</UserControl>";
|
||||
|
|
||||
|
var loader = new AvaloniaXamlLoader(); |
||||
|
var userControl = (UserControl)loader.Load(xaml); |
||||
|
var border = userControl.FindControl<Border>("border"); |
||||
|
|
||||
|
DelayedBinding.ApplyBindings(border); |
||||
|
|
||||
|
var brush = (SolidColorBrush)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 = @"
|
||||
|
<Window xmlns='https://github.com/avaloniaui'
|
||||
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
|
||||
|
<Border Name='border' Background='{DynamicResource brush}'/> |
||||
|
</Window>";
|
||||
|
|
||||
|
var loader = new AvaloniaXamlLoader(); |
||||
|
var window = (Window)loader.Load(xaml); |
||||
|
var border = window.FindControl<Border>("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 = @"
|
||||
|
<UserControl xmlns='https://github.com/avaloniaui'
|
||||
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
|
||||
|
<Border Name='border' Background='{DynamicResource brush}'/> |
||||
|
</UserControl>";
|
||||
|
|
||||
|
var loader = new AvaloniaXamlLoader(); |
||||
|
var userControl = (UserControl)loader.Load(xaml); |
||||
|
var border = userControl.FindControl<Border>("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 = @"
|
||||
|
<Window xmlns='https://github.com/avaloniaui'
|
||||
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
|
||||
|
<Window.Resources> |
||||
|
<SolidColorBrush x:Key='brush'>#ff506070</SolidColorBrush> |
||||
|
</Window.Resources> |
||||
|
<Window.Styles> |
||||
|
<Style Selector='Button'> |
||||
|
<Setter Property='Background' Value='{DynamicResource brush}'/> |
||||
|
</Style> |
||||
|
</Window.Styles> |
||||
|
<Button Name='button'/> |
||||
|
</Window>";
|
||||
|
|
||||
|
var loader = new AvaloniaXamlLoader(); |
||||
|
var window = (Window)loader.Load(xaml); |
||||
|
var button = window.FindControl<Button>("button"); |
||||
|
var brush = (SolidColorBrush)button.Background; |
||||
|
|
||||
|
Assert.Equal(0xff506070, brush.Color.ToUint32()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void DynamicResource_From_Style_Can_Be_Assigned_To_Setter() |
||||
|
{ |
||||
|
using (StyledWindow()) |
||||
|
{ |
||||
|
var xaml = @"
|
||||
|
<Window xmlns='https://github.com/avaloniaui'
|
||||
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
|
||||
|
<Window.Styles> |
||||
|
<Style> |
||||
|
<Style.Resources> |
||||
|
<SolidColorBrush x:Key='brush'>#ff506070</SolidColorBrush> |
||||
|
</Style.Resources> |
||||
|
</Style> |
||||
|
<Style Selector='Button'> |
||||
|
<Setter Property='Background' Value='{DynamicResource brush}'/> |
||||
|
</Style> |
||||
|
</Window.Styles> |
||||
|
<Button Name='button'/> |
||||
|
</Window>";
|
||||
|
|
||||
|
var loader = new AvaloniaXamlLoader(); |
||||
|
var window = (Window)loader.Load(xaml); |
||||
|
var button = window.FindControl<Button>("button"); |
||||
|
var brush = (SolidColorBrush)button.Background; |
||||
|
|
||||
|
Assert.Equal(0xff506070, brush.Color.ToUint32()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void DynamicResource_Can_Be_Assigned_To_Setter_In_Styles_File() |
||||
|
{ |
||||
|
var styleXaml = @"
|
||||
|
<Styles xmlns='https://github.com/avaloniaui'
|
||||
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
|
||||
|
<Styles.Resources> |
||||
|
<SolidColorBrush x:Key='brush'>#ff506070</SolidColorBrush> |
||||
|
</Styles.Resources> |
||||
|
|
||||
|
<Style Selector='Border'> |
||||
|
<Setter Property='Background' Value='{DynamicResource brush}'/> |
||||
|
</Style> |
||||
|
</Styles>";
|
||||
|
|
||||
|
using (StyledWindow(assets: ("test:style.xaml", styleXaml))) |
||||
|
{ |
||||
|
var xaml = @"
|
||||
|
<Window xmlns='https://github.com/avaloniaui'
|
||||
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
|
||||
|
<Window.Styles> |
||||
|
<StyleInclude Source='test:style.xaml'/> |
||||
|
</Window.Styles> |
||||
|
<Border Name='border'/> |
||||
|
</Window>";
|
||||
|
|
||||
|
var loader = new AvaloniaXamlLoader(); |
||||
|
var window = (Window)loader.Load(xaml); |
||||
|
var border = window.FindControl<Border>("border"); |
||||
|
var brush = (SolidColorBrush)border.Background; |
||||
|
|
||||
|
Assert.Equal(0xff506070, brush.Color.ToUint32()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void DynamicResource_Can_Be_Assigned_To_Property_In_ControlTemplate_In_Styles_File() |
||||
|
{ |
||||
|
var styleXaml = @"
|
||||
|
<Styles xmlns='https://github.com/avaloniaui'
|
||||
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
|
||||
|
<Styles.Resources> |
||||
|
<SolidColorBrush x:Key='brush'>#ff506070</SolidColorBrush> |
||||
|
</Styles.Resources> |
||||
|
|
||||
|
<Style Selector='Button'> |
||||
|
<Setter Property='Template'> |
||||
|
<ControlTemplate> |
||||
|
<Border Name='border' Background='{DynamicResource brush}'/> |
||||
|
</ControlTemplate> |
||||
|
</Setter> |
||||
|
</Style> |
||||
|
</Styles>";
|
||||
|
|
||||
|
using (StyledWindow(assets: ("test:style.xaml", styleXaml))) |
||||
|
{ |
||||
|
var xaml = @"
|
||||
|
<Window xmlns='https://github.com/avaloniaui'
|
||||
|
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
|
||||
|
<Window.Styles> |
||||
|
<StyleInclude Source='test:style.xaml'/> |
||||
|
</Window.Styles> |
||||
|
<Button Name='button'/> |
||||
|
</Window>";
|
||||
|
|
||||
|
var loader = new AvaloniaXamlLoader(); |
||||
|
var window = (Window)loader.Load(xaml); |
||||
|
var button = window.FindControl<Button>("button"); |
||||
|
|
||||
|
window.Show(); |
||||
|
|
||||
|
var border = (Border)button.GetVisualChildren().Single(); |
||||
|
var brush = (SolidColorBrush)border.Background; |
||||
|
|
||||
|
Assert.Equal(0xff506070, brush.Color.ToUint32()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
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<Window>()) |
||||
|
{ |
||||
|
Setters = |
||||
|
{ |
||||
|
new Setter( |
||||
|
Window.TemplateProperty, |
||||
|
new FuncControlTemplate<Window>(x => |
||||
|
new ContentPresenter |
||||
|
{ |
||||
|
Name = "PART_ContentPresenter", |
||||
|
[!ContentPresenter.ContentProperty] = x[!Window.ContentProperty], |
||||
|
})) |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue