Browse Source

Refactor Setter into Setter and ObservableSetter.

Both sharing a common ISetter interface.
Steven Kirk 10 years ago
parent
commit
7f6b198d02

+ 2 - 0
src/Perspex.Styling/Perspex.Styling.csproj

@@ -48,6 +48,7 @@
     <Compile Include="Styling\Classes.cs" />
     <Compile Include="Styling\IGlobalStyles.cs" />
     <Compile Include="Styling\INamed.cs" />
+    <Compile Include="Styling\ISetter.cs" />
     <Compile Include="Styling\IStyle.cs" />
     <Compile Include="Styling\IStyleable.cs" />
     <Compile Include="Styling\IStyleHost.cs" />
@@ -56,6 +57,7 @@
     <Compile Include="Styling\SelectorMatch.cs" />
     <Compile Include="Styling\Selector.cs" />
     <Compile Include="Styling\Selectors.cs" />
+    <Compile Include="Styling\ObservableSetter.cs" />
     <Compile Include="Styling\Setter.cs" />
     <Compile Include="Styling\Style.cs" />
     <Compile Include="Styling\StyleActivator.cs" />

+ 18 - 0
src/Perspex.Styling/Styling/ISetter.cs

@@ -0,0 +1,18 @@
+namespace Perspex.Styling
+{
+    using System;
+
+    /// <summary>
+    /// Represents a setter for a <see cref="Style"/>.
+    /// </summary>
+    public interface ISetter
+    {
+        /// <summary>
+        /// Applies the setter to the control.
+        /// </summary>
+        /// <param name="style">The style that is being applied.</param>
+        /// <param name="control">The control.</param>
+        /// <param name="activator">An optional activator.</param>
+        void Apply(IStyle style, IStyleable control, IObservable<bool> activator);
+    }
+}

+ 7 - 0
src/Perspex.Styling/Styling/IStyle.cs

@@ -6,8 +6,15 @@
 
 namespace Perspex.Styling
 {
+    /// <summary>
+    /// Defines the interface for styles.
+    /// </summary>
     public interface IStyle
     {
+        /// <summary>
+        /// Attaches the style to a control if the style matches.
+        /// </summary>
+        /// <param name="control">The control to attach to.</param>
         void Attach(IStyleable control);
     }
 }

+ 68 - 0
src/Perspex.Styling/Styling/ObservableSetter.cs

@@ -0,0 +1,68 @@
+// -----------------------------------------------------------------------
+// <copyright file="ObservableSetter.cs" company="Steven Kirk">
+// Copyright 2015 MIT Licence. See licence.md for more information.
+// </copyright>
+// -----------------------------------------------------------------------
+
+namespace Perspex.Styling
+{
+    using System;
+
+    /// <summary>
+    /// A setter for a <see cref="Style"/> whose source is an observable.
+    /// </summary>
+    /// <remarks>
+    /// A <see cref="Setter"/> is used to set a <see cref="PerspexProperty"/> value on a
+    /// <see cref="PerspexObject"/> depending on a condition.
+    /// </remarks>
+    public class ObservableSetter : ISetter
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="ObservableSetter"/> class.
+        /// </summary>
+        /// <param name="property">The property to set.</param>
+        /// <param name="source">An observable which produces the value for the property.</param>
+        public ObservableSetter(PerspexProperty property, IObservable<object> source)
+        {
+            this.Property = property;
+            this.Source = source;
+        }
+
+        /// <summary>
+        /// Gets or sets the property to set.
+        /// </summary>
+        public PerspexProperty Property
+        {
+            get;
+            set;
+        }
+
+        /// <summary>
+        /// Gets or sets an observable which produces the value for the property.
+        /// </summary>
+        public IObservable<object> Source
+        {
+            get;
+            set;
+        }
+
+        /// <summary>
+        /// Applies the setter to the control.
+        /// </summary>
+        /// <param name="style">The style that is being applied.</param>
+        /// <param name="control">The control.</param>
+        /// <param name="activator">An optional activator.</param>
+        public void Apply(IStyle style, IStyleable control, IObservable<bool> activator)
+        {
+            if (activator == null)
+            {
+                control.Bind(this.Property, this.Source, BindingPriority.Style);
+            }
+            else
+            {
+                var binding = new StyleBinding(activator, this.Source, style.ToString());
+                control.Bind(this.Property, binding, BindingPriority.StyleTrigger);
+            }
+        }
+    }
+}

+ 17 - 25
src/Perspex.Styling/Styling/Setter.cs

@@ -15,14 +15,13 @@ namespace Perspex.Styling
     /// A <see cref="Setter"/> is used to set a <see cref="PerspexProperty"/> value on a
     /// <see cref="PerspexObject"/> depending on a condition.
     /// </remarks>
-    public class Setter
+    public class Setter : ISetter
     {
         /// <summary>
         /// Initializes a new instance of the <see cref="Setter"/> class.
         /// </summary>
         public Setter()
         {
-
         }
 
         /// <summary>
@@ -36,17 +35,6 @@ namespace Perspex.Styling
             this.Value = value;
         }
 
-        /// <summary>
-        /// Initializes a new instance of the <see cref="Setter"/> class.
-        /// </summary>
-        /// <param name="property">The property to set.</param>
-        /// <param name="source">An observable which produces the value for the property.</param>
-        public Setter(PerspexProperty property, IObservable<object> source)
-        {
-            this.Property = property;
-            this.Source = source;
-        }
-
         /// <summary>
         /// Gets or sets the property to set.
         /// </summary>
@@ -57,27 +45,31 @@ namespace Perspex.Styling
         }
 
         /// <summary>
-        /// Gets or sets an observable which produces the value for the property.
+        /// Gets or sets the property value.
         /// </summary>
-        /// <remarks>
-        /// Only one of <see cref="Source"/> and <see cref="Value"/> should be set.
-        /// </remarks>
-        public IObservable<object> Source
+        public object Value
         {
             get;
             set;
         }
 
         /// <summary>
-        /// Gets or sets the property value.
+        /// Applies the setter to the control.
         /// </summary>
-        /// <remarks>
-        /// Only one of <see cref="Source"/> and <see cref="Value"/> should be set.
-        /// </remarks>
-        public object Value
+        /// <param name="style">The style that is being applied.</param>
+        /// <param name="control">The control.</param>
+        /// <param name="activator">An optional activator.</param>
+        public void Apply(IStyle style, IStyleable control, IObservable<bool> activator)
         {
-            get;
-            set;
+            if (activator == null)
+            {
+                control.SetValue(this.Property, this.Value, BindingPriority.Style);
+            }
+            else
+            {
+                var binding = new StyleBinding(activator, this.Value, style.ToString());
+                control.Bind(this.Property, binding, BindingPriority.StyleTrigger);
+            }
         }
     }
 }

+ 29 - 54
src/Perspex.Styling/Styling/Style.cs

@@ -8,85 +8,60 @@ namespace Perspex.Styling
 {
     using System;
     using System.Collections.Generic;
-    using System.Reactive.Linq;
 
+    /// <summary>
+    /// Defines a style.
+    /// </summary>
     public class Style : IStyle
     {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Style"/> class.
+        /// </summary>
         public Style()
         {
-            this.Setters = new List<Setter>();
         }
 
+        /// <summary>
+        /// Initializes a new instance of the <see cref="Style"/> class.
+        /// </summary>
+        /// <param name="selector">The style selector.</param>
         public Style(Func<Selector, Selector> selector)
-            : this()
         {
             this.Selector = selector(new Selector());
         }
 
-        public Selector Selector
-        {
-            get;
-            set;
-        }
+        /// <summary>
+        /// Gets or sets style's selector.
+        /// </summary>
+        public Selector Selector { get; set; }
 
-        public IEnumerable<Setter> Setters
-        {
-            get;
-            set;
-        }
+        /// <summary>
+        /// Gets or sets style's setters.
+        /// </summary>
+        public IEnumerable<ISetter> Setters { get; set; } = new List<ISetter>();
 
+        /// <summary>
+        /// Attaches the style to a control if the style's selector matches.
+        /// </summary>
+        /// <param name="control">The control to attach to.</param>
         public void Attach(IStyleable control)
         {
             var description = "Style " + this.Selector.ToString();
             var match = this.Selector.Match(control);
 
-            if (match.ImmediateResult.HasValue)
-            {
-                if (match.ImmediateResult == true)
-                {
-                    foreach (Setter setter in this.Setters)
-                    {
-                        if (setter.Source != null && setter.Value != null)
-                        {
-                            throw new InvalidOperationException("Cannot set both Source and Value on a Setter.");
-                        }
-
-                        if (setter.Source == null)
-                        {
-                            control.SetValue(setter.Property, setter.Value, BindingPriority.Style);
-                        }
-                        else
-                        {
-                            control.Bind(setter.Property, setter.Source, BindingPriority.Style);
-                        }
-                    }
-                }
-            }
-            else
+            if (match.ImmediateResult != false)
             {
-                foreach (Setter setter in this.Setters)
+                foreach (var setter in this.Setters)
                 {
-                    if (setter.Source != null && setter.Value != null)
-                    {
-                        throw new InvalidOperationException("Cannot set both Source and Value on a Setter.");
-                    }
-
-                    StyleBinding binding;
-
-                    if (setter.Source == null)
-                    {
-                        binding = new StyleBinding(match.ObservableResult, setter.Value, description);
-                    }
-                    else
-                    {
-                        binding = new StyleBinding(match.ObservableResult, setter.Source, description);
-                    }
-
-                    control.Bind(setter.Property, binding, BindingPriority.StyleTrigger);
+                    setter.Apply(this, control, match.ObservableResult);
                 }
             }
         }
 
+        /// <summary>
+        /// Returns a string representation of the style.
+        /// </summary>
+        /// <returns>A string representation of the style.</returns>
         public override string ToString()
         {
             return "Style: " + this.Selector.ToString();

+ 4 - 29
tests/Perspex.Styling.UnitTests/StyleTests.cs

@@ -109,7 +109,7 @@ namespace Perspex.Styling.UnitTests
         }
 
         [Fact]
-        public void Style_With_Value_And_Source_Should_Throw_Exception()
+        public void Style_With_ObservableSetter_Should_Update_Value()
         {
             var source = new BehaviorSubject<string>("Foo");
 
@@ -117,30 +117,7 @@ namespace Perspex.Styling.UnitTests
             {
                 Setters = new[]
                 {
-                    new Setter
-                    {
-                        Property = Class1.FooProperty,
-                        Source = source,
-                        Value = "Foo",
-                    },
-                },
-            };
-
-            var target = new Class1();
-
-            Assert.Throws<InvalidOperationException>(() => style.Attach(target));
-        }
-
-        [Fact]
-        public void Style_With_Source_Should_Update_Value()
-        {
-            var source = new BehaviorSubject<string>("Foo");
-
-            Style style = new Style(x => x.OfType<Class1>())
-            {
-                Setters = new[]
-                {
-                    new Setter(Class1.FooProperty, source),
+                    new ObservableSetter(Class1.FooProperty, source),
                 },
             };
 
@@ -149,12 +126,10 @@ namespace Perspex.Styling.UnitTests
             style.Attach(target);
 
             Assert.Equal("Foo", target.Foo);
-            source.OnNext("Bar");
-            Assert.Equal("Bar", target.Foo);
         }
 
         [Fact]
-        public void Style_With_Source_Should_Update_And_Restore_Value()
+        public void Style_With_ObservableSetter_Should_Update_And_Restore_Value()
         {
             var source = new BehaviorSubject<string>("Foo");
 
@@ -162,7 +137,7 @@ namespace Perspex.Styling.UnitTests
             {
                 Setters = new[]
                 {
-                    new Setter(Class1.FooProperty, source),
+                    new ObservableSetter(Class1.FooProperty, source),
                 },
             };