diff --git a/Perspex.UnitTests/Controls/ControlTests.cs b/Perspex.UnitTests/Controls/ControlTests.cs
new file mode 100644
index 0000000000..1576610485
--- /dev/null
+++ b/Perspex.UnitTests/Controls/ControlTests.cs
@@ -0,0 +1,105 @@
+// -----------------------------------------------------------------------
+//
+// Copyright 2013 MIT Licence. See licence.md for more information.
+//
+// -----------------------------------------------------------------------
+
+namespace Perspex.UnitTests.Controls
+{
+ using System.Linq;
+ using Microsoft.VisualStudio.TestTools.UnitTesting;
+ using Moq;
+ using Perspex.Controls;
+ using Perspex.Layout;
+ using Perspex.Styling;
+ using Splat;
+
+ [TestClass]
+ public class ControlTests
+ {
+ [TestMethod]
+ public void Classes_Should_Initially_Be_Empty()
+ {
+ var target = new Control();
+
+ Assert.AreEqual(0, target.Classes.Count);
+ }
+
+ [TestMethod]
+ public void Setting_IsMouseOver_Should_Add_Mouseover_Class()
+ {
+ var target = new Control();
+
+ target.IsMouseOver = true;
+
+ CollectionAssert.AreEqual(new[] { ":mouseover" }, target.Classes.ToArray());
+ }
+
+ [TestMethod]
+ public void Clearing_IsMouseOver_Should_Remove_Mouseover_Class()
+ {
+ var target = new Control();
+
+ target.IsMouseOver = true;
+ target.IsMouseOver = false;
+
+ Assert.AreEqual(0, target.Classes.Count);
+ }
+
+ [TestMethod]
+ public void Adding_Control_To_ILayoutRoot_Should_Style_Control()
+ {
+ using (Locator.CurrentMutable.WithResolver())
+ {
+ var root = new TestRoot();
+ var target = new Control();
+ var styler = new Mock();
+
+ Locator.CurrentMutable.Register(() => styler.Object, typeof(IStyler));
+
+ root.Content = target;
+
+ styler.Verify(x => x.ApplyStyles(target), Times.Once());
+ }
+ }
+
+ [TestMethod]
+ public void Adding_Tree_To_ILayoutRoot_Should_Style_Controls()
+ {
+ using (Locator.CurrentMutable.WithResolver())
+ {
+ var root = new TestRoot();
+ var parent = new Border();
+ var child = new Border();
+ var grandchild = new Control();
+ var styler = new Mock();
+
+ Locator.CurrentMutable.Register(() => styler.Object, typeof(IStyler));
+
+ parent.Content = child;
+ child.Content = grandchild;
+
+ styler.Verify(x => x.ApplyStyles(It.IsAny()), Times.Never());
+
+ root.Content = parent;
+
+ styler.Verify(x => x.ApplyStyles(parent), Times.Once());
+ styler.Verify(x => x.ApplyStyles(child), Times.Once());
+ styler.Verify(x => x.ApplyStyles(grandchild), Times.Once());
+ }
+ }
+
+ private class TestRoot : Decorator, ILayoutRoot
+ {
+ public Size ClientSize
+ {
+ get { throw new System.NotImplementedException(); }
+ }
+
+ public ILayoutManager LayoutManager
+ {
+ get { throw new System.NotImplementedException(); }
+ }
+ }
+ }
+}
diff --git a/Perspex.UnitTests/Perspex.UnitTests.csproj b/Perspex.UnitTests/Perspex.UnitTests.csproj
index 854fcfd097..57b71a448d 100644
--- a/Perspex.UnitTests/Perspex.UnitTests.csproj
+++ b/Perspex.UnitTests/Perspex.UnitTests.csproj
@@ -68,6 +68,7 @@
+
diff --git a/Perspex/Controls/Control.cs b/Perspex/Controls/Control.cs
index a3df4f0684..e55f5e7cbd 100644
--- a/Perspex/Controls/Control.cs
+++ b/Perspex/Controls/Control.cs
@@ -15,6 +15,7 @@ namespace Perspex.Controls
using Perspex.Layout;
using Perspex.Media;
using Perspex.Styling;
+ using Splat;
public enum HorizontalAlignment
{
@@ -32,7 +33,7 @@ namespace Perspex.Controls
Bottom,
}
- public abstract class Control : Interactive, ILayoutable, IStyleable
+ public class Control : Interactive, ILayoutable, IStyleable, IStyled
{
public static readonly PerspexProperty BackgroundProperty =
PerspexProperty.Register("Background", inherits: true);
@@ -291,26 +292,16 @@ namespace Perspex.Controls
return finalSize;
}
- protected abstract Size MeasureContent(Size availableSize);
-
- protected override void AttachedToVisualTree()
+ protected virtual Size MeasureContent(Size availableSize)
{
- this.AttachStyles(this);
- base.AttachedToVisualTree();
+ return new Size();
}
- private void AttachStyles(Control styleContainer)
+ protected override void AttachedToVisualTree()
{
- if (styleContainer != null)
- {
- Control parent = styleContainer.Parent;
- this.AttachStyles(parent);
- styleContainer.Styles.Attach(this);
- }
- else
- {
- Application.Current.Styles.Attach(this);
- }
+ IStyler styler = Locator.Current.GetService();
+ styler.ApplyStyles(this);
+ base.AttachedToVisualTree();
}
}
}
diff --git a/Perspex/Perspex.csproj b/Perspex/Perspex.csproj
index 864390aea9..74353bce5c 100644
--- a/Perspex/Perspex.csproj
+++ b/Perspex/Perspex.csproj
@@ -86,6 +86,9 @@
+
+
+
diff --git a/Perspex/Styling/IStyled.cs b/Perspex/Styling/IStyled.cs
new file mode 100644
index 0000000000..5d48b22b57
--- /dev/null
+++ b/Perspex/Styling/IStyled.cs
@@ -0,0 +1,15 @@
+// -----------------------------------------------------------------------
+//
+// Copyright 2014 MIT Licence. See licence.md for more information.
+//
+// -----------------------------------------------------------------------
+
+namespace Perspex.Styling
+{
+ using Perspex.Controls;
+
+ public interface IStyled
+ {
+ Styles Styles { get; }
+ }
+}
diff --git a/Perspex/Styling/IStyler.cs b/Perspex/Styling/IStyler.cs
new file mode 100644
index 0000000000..cd296a0917
--- /dev/null
+++ b/Perspex/Styling/IStyler.cs
@@ -0,0 +1,15 @@
+// -----------------------------------------------------------------------
+//
+// Copyright 2014 MIT Licence. See licence.md for more information.
+//
+// -----------------------------------------------------------------------
+
+namespace Perspex.Styling
+{
+ using System;
+
+ public interface IStyler
+ {
+ void ApplyStyles(IStyleable control);
+ }
+}
diff --git a/Perspex/Styling/Styler.cs b/Perspex/Styling/Styler.cs
new file mode 100644
index 0000000000..671c8fe948
--- /dev/null
+++ b/Perspex/Styling/Styler.cs
@@ -0,0 +1,24 @@
+// -----------------------------------------------------------------------
+//
+// Copyright 2014 MIT Licence. See licence.md for more information.
+//
+// -----------------------------------------------------------------------
+
+namespace Perspex.Styling
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Text;
+ using System.Threading.Tasks;
+
+ public class Styler : IStyler
+ {
+ public void ApplyStyles(IStyleable control)
+ {
+ IVisual visual = control as IVisual;
+ IStyled styleContainer = visual.GetVisualAncestorOrSelf();
+ styleContainer.Styles.Attach(control);
+ }
+ }
+}
diff --git a/Perspex/VisualExtensions.cs b/Perspex/VisualExtensions.cs
index 4bb15eb501..29e9c1ca8f 100644
--- a/Perspex/VisualExtensions.cs
+++ b/Perspex/VisualExtensions.cs
@@ -32,6 +32,13 @@ namespace Perspex
return null;
}
+ public static T GetVisualAncestorOrSelf(this IVisual visual) where T : class
+ {
+ Contract.Requires(visual != null);
+
+ return (visual as T) ?? visual.GetVisualAncestor();
+ }
+
public static IVisual GetVisualAt(this IVisual visual, Point p)
{
Contract.Requires(visual != null);
diff --git a/TestApplication/Program.cs b/TestApplication/Program.cs
index 3f57bd0063..a70f29ef34 100644
--- a/TestApplication/Program.cs
+++ b/TestApplication/Program.cs
@@ -61,13 +61,13 @@ namespace TestApplication
new Setter(TestBorder.BackgroundProperty, new SolidColorBrush(0xff0000ff)),
}
},
- //new Style(new Selector().OfType().Class(":mouseover"))
- //{
- // Setters = new[]
- // {
- // new Setter(TestBorder.BackgroundProperty, new SolidColorBrush(0xffff0000)),
- // }
- //},
+ new Style(new Selector().OfType().Class(":mouseover"))
+ {
+ Setters = new[]
+ {
+ new Setter(TestBorder.BackgroundProperty, new SolidColorBrush(0xffff0000)),
+ }
+ },
}
},