Browse Source

More work on static resources.

Also found a scenario that Portable.Xaml can't seem to handle...
pull/1136/head
Steven Kirk 9 years ago
parent
commit
4a9302b61e
  1. 5
      src/Avalonia.Styling/Styling/Styles.cs
  2. 11
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs
  3. 24
      tests/Avalonia.Controls.UnitTests/ControlTests_Resources.cs
  4. 119
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StaticResourceTests.cs
  5. 36
      tests/Avalonia.UnitTests/MockAssetLoader.cs

5
src/Avalonia.Styling/Styling/Styles.cs

@ -48,6 +48,11 @@ namespace Avalonia.Styling
/// <inheritdoc/>
public bool TryGetResource(string key, out object value)
{
if (_resources != null && _resources.TryGetValue(key, out value))
{
return true;
}
for (var i = Count - 1; i >= 0; --i)
{
if (this[i].TryGetResource(key, out value))

11
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs

@ -34,8 +34,15 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
var resourceProviderType = schemaContext.GetXamlType(typeof(IResourceProvider));
var resourceProviders = ambientProvider.GetAllAmbientValues(resourceProviderType);
// Look up the ambient context for IResourceProviders which might be able to give us
// the resource.
// Look upwards though the ambient context for IResourceProviders which might be able
// to give us the resource.
//
// TODO: If we're in a template then only the ambient values since the root of the
// template wil be included here. We need some way to get hold of the parent ambient
// context and search that. See the test:
//
// StaticResource_Can_Be_Assigned_To_Property_In_ControlTemplate_In_Styles_File
//
foreach (IResourceProvider resourceProvider in resourceProviders)
{
if (resourceProvider is IControl control && control.StylingParent != null)

24
tests/Avalonia.Controls.UnitTests/ControlTests_Resources.cs

@ -87,6 +87,30 @@ namespace Avalonia.Controls.UnitTests
Assert.Equal("foo-value", target.FindResource("foo"));
}
[Fact]
public void FindResource_Should_Find_Styles_Resource()
{
var target = new Control
{
Styles =
{
new Styles
{
Resources =
{
{ "foo", "foo-value" },
}
}
},
Resources =
{
{ "bar", "bar-value" },
},
};
Assert.Equal("foo-value", target.FindResource("foo"));
}
[Fact]
public void FindResource_Should_Find_Application_Style_Resource()
{

119
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StaticResourceTests.cs

@ -2,11 +2,15 @@
// 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.Xaml
@ -62,7 +66,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
[Fact]
public void StaticResource_From_Application_Can_Be_Assigned_To_Property_In_Window()
{
using (StyledWindowNoTheme())
using (StyledWindow())
{
Application.Current.Resources.Add("brush", new SolidColorBrush(0xff506070));
@ -111,7 +115,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
[Fact]
public void StaticResource_Can_Be_Assigned_To_Setter()
{
using (StyledWindowNoTheme())
using (StyledWindow())
{
var xaml = @"
<Window xmlns='https://github.com/avaloniaui'
@ -139,7 +143,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
[Fact]
public void StaticResource_From_Style_Can_Be_Assigned_To_Setter()
{
using (StyledWindowNoTheme())
using (StyledWindow())
{
var xaml = @"
<Window xmlns='https://github.com/avaloniaui'
@ -166,9 +170,114 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
}
}
private IDisposable StyledWindowNoTheme()
[Fact]
public void StaticResource_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='{StaticResource 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(Skip = "Not yet supported by Portable.Xaml")]
public void StaticResource_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='{StaticResource 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;
// To make this work we somehow need to be able to get hold of the parent ambient
// context from Portable.Xaml. See TODO in StaticResourceExtension.
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 UnitTestApplication.Start(TestServices.StyledWindow.With(theme: () => new Styles()));
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],
}))
}
};
}
}
}

36
tests/Avalonia.UnitTests/MockAssetLoader.cs

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Platform;
namespace Avalonia.UnitTests
{
public class MockAssetLoader : IAssetLoader
{
private Dictionary<Uri, string> _assets;
public MockAssetLoader(params (string, string)[] assets)
{
_assets = assets.ToDictionary(x => new Uri(x.Item1, UriKind.RelativeOrAbsolute), x => x.Item2);
}
public bool Exists(Uri uri, Uri baseUri = null)
{
return _assets.ContainsKey(uri);
}
public Stream Open(Uri uri, Uri baseUri = null)
{
return new MemoryStream(Encoding.UTF8.GetBytes(_assets[uri]));
}
public void SetDefaultAssembly(Assembly asm)
{
throw new NotImplementedException();
}
}
}
Loading…
Cancel
Save