diff --git a/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/StyleResourceExtension.cs b/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/StyleResourceExtension.cs
new file mode 100644
index 0000000000..c1acd8cbff
--- /dev/null
+++ b/src/Markup/Perspex.Markup.Xaml/MarkupExtensions/StyleResourceExtension.cs
@@ -0,0 +1,33 @@
+// Copyright (c) The Perspex Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System;
+using OmniXaml;
+using Perspex.LogicalTree;
+using Perspex.Styling;
+
+namespace Perspex.Markup.Xaml.MarkupExtensions
+{
+ public class StyleResourceExtension : MarkupExtension
+ {
+ public StyleResourceExtension(string name)
+ {
+ Name = name;
+ }
+
+ public override object ProvideValue(MarkupExtensionContext extensionContext)
+ {
+ var styleHost = extensionContext.TargetObject as IStyleHost;
+
+ if (styleHost == null)
+ {
+ throw new ParseException(
+ $"StyleResource cannot be assigned to an object of type '{styleHost.GetType()}'.");
+ }
+
+ return styleHost.FindStyleResource(Name);
+ }
+
+ public string Name { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj b/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj
index 984762d50f..35aff8a3a2 100644
--- a/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj
+++ b/src/Markup/Perspex.Markup.Xaml/Perspex.Markup.Xaml.csproj
@@ -55,6 +55,7 @@
+
@@ -78,6 +79,7 @@
+
diff --git a/src/Markup/Perspex.Markup.Xaml/Styling/StyleInclude.cs b/src/Markup/Perspex.Markup.Xaml/Styling/StyleInclude.cs
index fee252de17..6991e48f16 100644
--- a/src/Markup/Perspex.Markup.Xaml/Styling/StyleInclude.cs
+++ b/src/Markup/Perspex.Markup.Xaml/Styling/StyleInclude.cs
@@ -35,5 +35,17 @@ namespace Perspex.Markup.Xaml.Styling
Loaded.Attach(control, container);
}
}
+
+ ///
+ /// Tries to find a named resource within the style.
+ ///
+ /// The resource name.
+ ///
+ /// The resource if found, otherwise .
+ ///
+ public object FindResource(string name)
+ {
+ return Loaded.FindResource(name);
+ }
}
}
diff --git a/src/Perspex.Styling/Perspex.Styling.csproj b/src/Perspex.Styling/Perspex.Styling.csproj
index 4ed57c90e3..92edaa3db6 100644
--- a/src/Perspex.Styling/Perspex.Styling.csproj
+++ b/src/Perspex.Styling/Perspex.Styling.csproj
@@ -63,6 +63,7 @@
+
diff --git a/src/Perspex.Styling/Styling/IStyle.cs b/src/Perspex.Styling/Styling/IStyle.cs
index 4404853bf0..5847aa5ee1 100644
--- a/src/Perspex.Styling/Styling/IStyle.cs
+++ b/src/Perspex.Styling/Styling/IStyle.cs
@@ -16,5 +16,14 @@ namespace Perspex.Styling
/// The control that contains this style. May be null.
///
void Attach(IStyleable control, IStyleHost container);
+
+ ///
+ /// Tries to find a named resource within the style.
+ ///
+ /// The resource name.
+ ///
+ /// The resource if found, otherwise .
+ ///
+ object FindResource(string name);
}
}
diff --git a/src/Perspex.Styling/Styling/Style.cs b/src/Perspex.Styling/Styling/Style.cs
index 0a10471f72..58fd2fa721 100644
--- a/src/Perspex.Styling/Styling/Style.cs
+++ b/src/Perspex.Styling/Styling/Style.cs
@@ -14,14 +14,13 @@ namespace Perspex.Styling
public class Style : IStyle
{
private static readonly IObservable True = Observable.Never().StartWith(true);
- private Lazy> _resources;
+ private Dictionary _resources;
///
/// Initializes a new instance of the class.
///
public Style()
{
- _resources = new Lazy>(() => new Dictionary());
}
///
@@ -34,9 +33,30 @@ namespace Perspex.Styling
}
///
- /// Gets a dictionary of style resources.
+ /// Gets or sets a dictionary of style resources.
///
- public IDictionary Resources => _resources.Value;
+ public IDictionary Resources
+ {
+ get
+ {
+ if (_resources == null)
+ {
+ _resources = new Dictionary();
+ }
+
+ return _resources;
+ }
+
+ set
+ {
+ var resources = Resources;
+
+ foreach (var i in value)
+ {
+ resources.Add(i);
+ }
+ }
+ }
///
/// Gets or sets style's selector.
@@ -83,6 +103,27 @@ namespace Perspex.Styling
}
}
+ ///
+ /// Tries to find a named resource within the style.
+ ///
+ /// The resource name.
+ ///
+ /// The resource if found, otherwise .
+ ///
+ public object FindResource(string name)
+ {
+ object result = null;
+
+ if (_resources?.TryGetValue(name, out result) == true)
+ {
+ return result;
+ }
+ else
+ {
+ return PerspexProperty.UnsetValue;
+ }
+ }
+
///
/// Returns a string representation of the style.
///
diff --git a/src/Perspex.Styling/Styling/StyleExtensions.cs b/src/Perspex.Styling/Styling/StyleExtensions.cs
new file mode 100644
index 0000000000..dc30041b49
--- /dev/null
+++ b/src/Perspex.Styling/Styling/StyleExtensions.cs
@@ -0,0 +1,39 @@
+// Copyright (c) The Perspex Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System;
+
+namespace Perspex.Styling
+{
+ public static class StyleExtensions
+ {
+ ///
+ /// Tries to find a named style resource.
+ ///
+ /// The control from which to find the resource.
+ /// The resource name.
+ ///
+ /// The resource if found, otherwise .
+ ///
+ public static object FindStyleResource(this IStyleHost control, string name)
+ {
+ Contract.Requires(control != null);
+ Contract.Requires(name != null);
+ Contract.Requires(!string.IsNullOrWhiteSpace(name));
+
+ while (control != null)
+ {
+ var result = control.Styles.FindResource(name);
+
+ if (result != PerspexProperty.UnsetValue)
+ {
+ return result;
+ }
+
+ control = control.StylingParent;
+ }
+
+ return PerspexProperty.UnsetValue;
+ }
+ }
+}
diff --git a/src/Perspex.Styling/Styling/Styles.cs b/src/Perspex.Styling/Styling/Styles.cs
index 877235a337..4806670369 100644
--- a/src/Perspex.Styling/Styling/Styles.cs
+++ b/src/Perspex.Styling/Styling/Styles.cs
@@ -1,6 +1,7 @@
// Copyright (c) The Perspex Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
+using System.Linq;
using Perspex.Collections;
namespace Perspex.Styling
@@ -24,5 +25,27 @@ namespace Perspex.Styling
style.Attach(control, container);
}
}
+
+ ///
+ /// Tries to find a named resource within the style.
+ ///
+ /// The resource name.
+ ///
+ /// The resource if found, otherwise .
+ ///
+ public object FindResource(string name)
+ {
+ foreach (var style in this.Reverse())
+ {
+ var result = style.FindResource(name);
+
+ if (result != PerspexProperty.UnsetValue)
+ {
+ return result;
+ }
+ }
+
+ return PerspexProperty.UnsetValue;
+ }
}
}
diff --git a/tests/Perspex.Markup.Xaml.UnitTests/StyleTests.cs b/tests/Perspex.Markup.Xaml.UnitTests/StyleTests.cs
index 5a9d9bbcef..9eb0309b42 100644
--- a/tests/Perspex.Markup.Xaml.UnitTests/StyleTests.cs
+++ b/tests/Perspex.Markup.Xaml.UnitTests/StyleTests.cs
@@ -19,7 +19,7 @@ namespace Perspex.Markup.Xaml.UnitTests
public void Color_Can_Be_Added_To_Style_Resources()
{
using (UnitTestApplication.Start(TestServices.MockPlatformWrapper))
- {
+ {
var xaml = @"
@@ -63,6 +63,31 @@ namespace Perspex.Markup.Xaml.UnitTests
}
}
+ [Fact]
+ public void StyleResource_Can_Be_Assigned_To_Property()
+ {
+ var xaml = @"
+
+
+
+
+
+
+";
+
+ var loader = new PerspexXamlLoader();
+ var userControl = (UserControl)loader.Load(xaml);
+ var border = userControl.FindControl("border");
+ var brush = (SolidColorBrush)border.Background;
+
+ Assert.Equal(0xff506070, brush.Color.ToUint32());
+ }
+
[Fact]
public void Binding_Should_Be_Assigned_To_Setter_Value_Instead_Of_Bound()
{
diff --git a/tests/Perspex.Styling.UnitTests/Perspex.Styling.UnitTests.csproj b/tests/Perspex.Styling.UnitTests/Perspex.Styling.UnitTests.csproj
index 574660616c..d775308d8d 100644
--- a/tests/Perspex.Styling.UnitTests/Perspex.Styling.UnitTests.csproj
+++ b/tests/Perspex.Styling.UnitTests/Perspex.Styling.UnitTests.csproj
@@ -97,6 +97,7 @@
+
diff --git a/tests/Perspex.Styling.UnitTests/ResourceTests.cs b/tests/Perspex.Styling.UnitTests/ResourceTests.cs
new file mode 100644
index 0000000000..bbfa119150
--- /dev/null
+++ b/tests/Perspex.Styling.UnitTests/ResourceTests.cs
@@ -0,0 +1,78 @@
+// Copyright (c) The Perspex Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System.Collections.Generic;
+using Perspex.Controls;
+using Xunit;
+
+namespace Perspex.Styling.UnitTests
+{
+ public class ResourceTests
+ {
+ [Fact]
+ public void FindStyleResource_Should_Find_Correct_Resource()
+ {
+ Border target;
+
+ var tree = new Decorator
+ {
+ Styles = new Styles
+ {
+ new Style
+ {
+ Resources = new Dictionary
+ {
+ { "Foo", "foo resource" },
+ { "Bar", "overridden" },
+ }
+ }
+ },
+ Child = target = new Border
+ {
+ Styles = new Styles
+ {
+ new Style
+ {
+ Resources = new Dictionary
+ {
+ { "Bar", "again overridden" },
+ }
+ },
+ new Style
+ {
+ Resources = new Dictionary
+ {
+ { "Bar", "bar resource" },
+ }
+ }
+ }
+ }
+ };
+
+ Assert.Equal("foo resource", target.FindStyleResource("Foo"));
+ Assert.Equal("bar resource", target.FindStyleResource("Bar"));
+ }
+
+ [Fact]
+ public void FindStyleResource_Should_Return_UnsetValue_For_Not_Found()
+ {
+ Border target;
+
+ var tree = target = new Border
+ {
+ Styles = new Styles
+ {
+ new Style
+ {
+ Resources = new Dictionary
+ {
+ { "Foo", "foo" },
+ }
+ },
+ }
+ };
+
+ Assert.Equal(PerspexProperty.UnsetValue, target.FindStyleResource("Baz"));
+ }
+ }
+}