Browse Source

Refactor Setter into Setter and ObservableSetter.

Both sharing a common ISetter interface.
pull/90/head
Steven Kirk 11 years ago
parent
commit
7f6b198d02
  1. 2
      src/Perspex.Styling/Perspex.Styling.csproj
  2. 18
      src/Perspex.Styling/Styling/ISetter.cs
  3. 7
      src/Perspex.Styling/Styling/IStyle.cs
  4. 68
      src/Perspex.Styling/Styling/ObservableSetter.cs
  5. 42
      src/Perspex.Styling/Styling/Setter.cs
  6. 83
      src/Perspex.Styling/Styling/Style.cs
  7. 33
      tests/Perspex.Styling.UnitTests/StyleTests.cs

2
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
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
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
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);
}
}
}
}

42
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);
}
}
}
}

83
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();

33
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),
},
};

Loading…
Cancel
Save