Browse Source

Make IStyleable.Classes an IPerspexReadOnlyList.

So we can mock it.
pull/366/head
Steven Kirk 11 years ago
parent
commit
5d2658d856
  1. BIN
      _NCrunch_Perspex/StoredText/e0ab357f917440988efaba9c0cd4a9c0
  2. 1
      src/Markup/Perspex.Markup.Xaml/Converters/ClassesTypeConverter.cs
  3. 25
      src/Perspex.Controls/Classes.cs
  4. 5
      src/Perspex.Controls/Control.cs
  5. 5
      src/Perspex.Controls/IControl.cs
  6. 1
      src/Perspex.Controls/Perspex.Controls.csproj
  7. 7
      src/Perspex.Controls/Primitives/SelectingItemsControl.cs
  8. 7
      src/Perspex.Controls/TreeView.cs
  9. 9
      src/Perspex.Diagnostics/ViewModels/TreeNode.cs
  10. 1
      src/Perspex.Styling/Perspex.Styling.csproj
  11. 155
      src/Perspex.Styling/Styling/Classes.cs
  12. 3
      src/Perspex.Styling/Styling/IStyleable.cs
  13. 10
      src/Perspex.Styling/Styling/Selectors.cs
  14. 1
      tests/Perspex.LeakTests/StyleTests.cs
  15. 4
      tests/Perspex.Markup.Xaml.UnitTests/Converters/PerspexPropertyConverterTest.cs
  16. 7
      tests/Perspex.Styling.UnitTests/SelectorTests_Child.cs
  17. 1
      tests/Perspex.Styling.UnitTests/SelectorTests_Class.cs
  18. 3
      tests/Perspex.Styling.UnitTests/SelectorTests_Descendent.cs
  19. 2
      tests/Perspex.Styling.UnitTests/SelectorTests_Multiple.cs
  20. 4
      tests/Perspex.Styling.UnitTests/TestControlBase.cs
  21. 4
      tests/Perspex.Styling.UnitTests/TestTemplatedControl.cs

BIN
_NCrunch_Perspex/StoredText/e0ab357f917440988efaba9c0cd4a9c0

Binary file not shown.

1
src/Markup/Perspex.Markup.Xaml/Converters/ClassesTypeConverter.cs

@ -4,6 +4,7 @@
using System; using System;
using System.Globalization; using System.Globalization;
using OmniXaml.TypeConversion; using OmniXaml.TypeConversion;
using Perspex.Controls;
using Perspex.Styling; using Perspex.Styling;
namespace Perspex.Markup.Xaml.Converters namespace Perspex.Markup.Xaml.Converters

25
src/Perspex.Controls/Classes.cs

@ -0,0 +1,25 @@
// 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.Collections;
namespace Perspex.Controls
{
public class Classes : PerspexList<string>
{
public Classes()
{
}
public Classes(IEnumerable<string> items)
: base(items)
{
}
public Classes(params string[] items)
: base(items)
{
}
}
}

5
src/Perspex.Controls/Control.cs

@ -129,7 +129,7 @@ namespace Perspex.Controls
if (_classes != value) if (_classes != value)
{ {
_classes.Clear(); _classes.Clear();
_classes.Add(value); _classes.AddRange(value);
} }
} }
} }
@ -216,6 +216,9 @@ namespace Perspex.Controls
/// </summary> /// </summary>
IPerspexReadOnlyList<ILogical> ILogical.LogicalChildren => LogicalChildren; IPerspexReadOnlyList<ILogical> ILogical.LogicalChildren => LogicalChildren;
/// <inheritdoc/>
IPerspexReadOnlyList<string> IStyleable.Classes => Classes;
/// <summary> /// <summary>
/// Gets the type by which the control is styled. /// Gets the type by which the control is styled.
/// </summary> /// </summary>

5
src/Perspex.Controls/IControl.cs

@ -13,6 +13,11 @@ namespace Perspex.Controls
/// </summary> /// </summary>
public interface IControl : IVisual, ILogical, ILayoutable, IInputElement, INamed, IStyleable, IStyleHost public interface IControl : IVisual, ILogical, ILayoutable, IInputElement, INamed, IStyleable, IStyleHost
{ {
/// <summary>
/// Gets or sets the control's styling classes.
/// </summary>
new Classes Classes { get; set; }
/// <summary> /// <summary>
/// Gets or sets the control's data context. /// Gets or sets the control's data context.
/// </summary> /// </summary>

1
src/Perspex.Controls/Perspex.Controls.csproj

@ -42,6 +42,7 @@
<Compile Include="..\Shared\SharedAssemblyInfo.cs"> <Compile Include="..\Shared\SharedAssemblyInfo.cs">
<Link>Properties\SharedAssemblyInfo.cs</Link> <Link>Properties\SharedAssemblyInfo.cs</Link>
</Compile> </Compile>
<Compile Include="Classes.cs" />
<Compile Include="DockPanel.cs" /> <Compile Include="DockPanel.cs" />
<Compile Include="HotkeyManager.cs" /> <Compile Include="HotkeyManager.cs" />
<Compile Include="INameScope.cs" /> <Compile Include="INameScope.cs" />

7
src/Perspex.Controls/Primitives/SelectingItemsControl.cs

@ -593,7 +593,6 @@ namespace Perspex.Controls.Primitives
try try
{ {
var selectable = container as ISelectable; var selectable = container as ISelectable;
var styleable = container as IStyleable;
_ignoreContainerSelectionChanged = true; _ignoreContainerSelectionChanged = true;
@ -601,15 +600,15 @@ namespace Perspex.Controls.Primitives
{ {
selectable.IsSelected = selected; selectable.IsSelected = selected;
} }
else if (styleable != null) else
{ {
if (selected) if (selected)
{ {
styleable.Classes.Add(":selected"); container.Classes.Add(":selected");
} }
else else
{ {
styleable.Classes.Remove(":selected"); container.Classes.Remove(":selected");
} }
} }
} }

7
src/Perspex.Controls/TreeView.cs

@ -179,21 +179,20 @@ namespace Perspex.Controls
private void MarkContainerSelected(IControl container, bool selected) private void MarkContainerSelected(IControl container, bool selected)
{ {
var selectable = container as ISelectable; var selectable = container as ISelectable;
var styleable = container as IStyleable;
if (selectable != null) if (selectable != null)
{ {
selectable.IsSelected = selected; selectable.IsSelected = selected;
} }
else if (styleable != null) else
{ {
if (selected) if (selected)
{ {
styleable.Classes.Add(":selected"); container.Classes.Add(":selected");
} }
else else
{ {
styleable.Classes.Remove(":selected"); container.Classes.Remove(":selected");
} }
} }
} }

9
src/Perspex.Diagnostics/ViewModels/TreeNode.cs

@ -2,6 +2,7 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information. // Licensed under the MIT license. See licence.md file in the project root for full license information.
using System; using System;
using System.Collections.Specialized;
using System.Reactive; using System.Reactive;
using System.Reactive.Linq; using System.Reactive.Linq;
using Perspex.Controls; using Perspex.Controls;
@ -18,7 +19,13 @@ namespace Perspex.Diagnostics.ViewModels
Control = control; Control = control;
Type = control.GetType().Name; Type = control.GetType().Name;
control.Classes.Changed.Select(_ => Unit.Default) var classesChanged = Observable.FromEventPattern<
NotifyCollectionChangedEventHandler,
NotifyCollectionChangedEventHandler>(
x => control.Classes.CollectionChanged += x,
x => control.Classes.CollectionChanged -= x);
classesChanged.Select(_ => Unit.Default)
.StartWith(Unit.Default) .StartWith(Unit.Default)
.Subscribe(_ => .Subscribe(_ =>
{ {

1
src/Perspex.Styling/Perspex.Styling.csproj

@ -45,7 +45,6 @@
<Compile Include="ILogical.cs" /> <Compile Include="ILogical.cs" />
<Compile Include="LogicalTree\LogicalExtensions.cs" /> <Compile Include="LogicalTree\LogicalExtensions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Styling\Classes.cs" />
<Compile Include="Styling\IGlobalStyles.cs" /> <Compile Include="Styling\IGlobalStyles.cs" />
<Compile Include="Styling\ISetter.cs" /> <Compile Include="Styling\ISetter.cs" />
<Compile Include="Styling\IStyle.cs" /> <Compile Include="Styling\IStyle.cs" />

155
src/Perspex.Styling/Styling/Classes.cs

@ -1,155 +0,0 @@
// 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 System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Reactive;
using System.Reactive.Subjects;
namespace Perspex.Styling
{
public class Classes : ICollection<string>, INotifyCollectionChanged
{
private readonly List<string> _inner;
private readonly Subject<NotifyCollectionChangedEventArgs> _beforeChanged
= new Subject<NotifyCollectionChangedEventArgs>();
private readonly Subject<NotifyCollectionChangedEventArgs> _changed
= new Subject<NotifyCollectionChangedEventArgs>();
private readonly Subject<NotifyCollectionChangedEventArgs> _afterChanged
= new Subject<NotifyCollectionChangedEventArgs>();
public Classes()
{
_inner = new List<string>();
}
public Classes(params string[] classes)
{
_inner = new List<string>(classes);
}
public Classes(IEnumerable<string> classes)
{
_inner = new List<string>(classes);
}
public event NotifyCollectionChangedEventHandler CollectionChanged;
public int Count => _inner.Count;
public bool IsReadOnly => false;
public IObservable<NotifyCollectionChangedEventArgs> BeforeChanged => _beforeChanged;
public IObservable<NotifyCollectionChangedEventArgs> Changed => _changed;
public IObservable<NotifyCollectionChangedEventArgs> AfterChanged => _afterChanged;
public void Add(string item)
{
Add(Enumerable.Repeat(item, 1));
}
public void Add(params string[] items)
{
Add((IEnumerable<string>)items);
}
public void Add(IEnumerable<string> items)
{
items = items.Except(_inner);
NotifyCollectionChangedEventArgs e = new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Add,
items);
_beforeChanged.OnNext(e);
_inner.AddRange(items);
RaiseChanged(e);
}
public void Clear()
{
NotifyCollectionChangedEventArgs e = new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Reset);
_beforeChanged.OnNext(e);
_inner.Clear();
RaiseChanged(e);
}
public bool Contains(string item)
{
return _inner.Contains(item);
}
public void CopyTo(string[] array, int arrayIndex)
{
_inner.CopyTo(array, arrayIndex);
}
public IEnumerator<string> GetEnumerator()
{
return _inner.GetEnumerator();
}
public override string ToString()
{
return string.Join(" ", this);
}
IEnumerator IEnumerable.GetEnumerator()
{
return _inner.GetEnumerator();
}
public bool Remove(string item)
{
return Remove(Enumerable.Repeat(item, 1));
}
public bool Remove(params string[] items)
{
return Remove((IEnumerable<string>)items);
}
public bool Remove(IEnumerable<string> items)
{
items = items.Intersect(_inner);
if (items.Any())
{
NotifyCollectionChangedEventArgs e = new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Remove,
items);
_beforeChanged.OnNext(e);
foreach (string item in items)
{
_inner.Remove(item);
}
RaiseChanged(e);
return true;
}
else
{
return false;
}
}
private void RaiseChanged(NotifyCollectionChangedEventArgs e)
{
CollectionChanged?.Invoke(this, e);
_changed.OnNext(e);
_afterChanged.OnNext(e);
}
}
}

3
src/Perspex.Styling/Styling/IStyleable.cs

@ -2,6 +2,7 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information. // Licensed under the MIT license. See licence.md file in the project root for full license information.
using System; using System;
using Perspex.Collections;
namespace Perspex.Styling namespace Perspex.Styling
{ {
@ -13,7 +14,7 @@ namespace Perspex.Styling
/// <summary> /// <summary>
/// Gets the list of classes for the control. /// Gets the list of classes for the control.
/// </summary> /// </summary>
Classes Classes { get; } IPerspexReadOnlyList<string> Classes { get; }
/// <summary> /// <summary>
/// Gets the type by which the control is styled. /// Gets the type by which the control is styled.

10
src/Perspex.Styling/Styling/Selectors.cs

@ -3,6 +3,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Reflection; using System.Reflection;
@ -176,10 +178,16 @@ namespace Perspex.Styling
private static SelectorMatch MatchClass(IStyleable control, string name) private static SelectorMatch MatchClass(IStyleable control, string name)
{ {
var changed = Observable.FromEventPattern<
NotifyCollectionChangedEventHandler,
NotifyCollectionChangedEventHandler>(
x => control.Classes.CollectionChanged += x,
x => control.Classes.CollectionChanged -= x);
return new SelectorMatch( return new SelectorMatch(
Observable Observable
.Return(control.Classes.Contains(name)) .Return(control.Classes.Contains(name))
.Concat(control.Classes.Changed.Select(e => control.Classes.Contains(name)))); .Concat(changed.Select(e => control.Classes.Contains(name))));
} }
private static SelectorMatch MatchDescendent(IStyleable control, Selector previous) private static SelectorMatch MatchDescendent(IStyleable control, Selector previous)

1
tests/Perspex.LeakTests/StyleTests.cs

@ -123,6 +123,7 @@ namespace Perspex.LeakTests
dotMemory.Check(memory => dotMemory.Check(memory =>
Assert.Equal(1, memory.GetObjects(where => where.Type.Is<StyleActivator>()).ObjectsCount)); Assert.Equal(1, memory.GetObjects(where => where.Type.Is<StyleActivator>()).ObjectsCount));
Assert.False(true);
} }
} }
} }

4
tests/Perspex.Markup.Xaml.UnitTests/Converters/PerspexPropertyConverterTest.cs

@ -7,6 +7,8 @@ using OmniXaml;
using OmniXaml.ObjectAssembler.Commands; using OmniXaml.ObjectAssembler.Commands;
using OmniXaml.TypeConversion; using OmniXaml.TypeConversion;
using OmniXaml.Typing; using OmniXaml.Typing;
using Perspex.Collections;
using Perspex.Controls;
using Perspex.Markup.Xaml.Converters; using Perspex.Markup.Xaml.Converters;
using Perspex.Styling; using Perspex.Styling;
using Xunit; using Xunit;
@ -74,7 +76,7 @@ namespace Perspex.Markup.Xaml.UnitTests.Converters
public static readonly PerspexProperty<string> FooProperty = public static readonly PerspexProperty<string> FooProperty =
PerspexProperty.Register<Class1, string>("Foo"); PerspexProperty.Register<Class1, string>("Foo");
public Classes Classes public IPerspexReadOnlyList<string> Classes
{ {
get { throw new NotImplementedException(); } get { throw new NotImplementedException(); }
} }

7
tests/Perspex.Styling.UnitTests/SelectorTests_Child.cs

@ -2,11 +2,13 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information. // Licensed under the MIT license. See licence.md file in the project root for full license information.
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Reactive.Subjects; using System.Reactive.Subjects;
using System.Threading.Tasks; using System.Threading.Tasks;
using Perspex.Collections; using Perspex.Collections;
using Perspex.Controls;
using Perspex.Styling; using Perspex.Styling;
using Xunit; using Xunit;
@ -43,7 +45,7 @@ namespace Perspex.Styling.UnitTests
} }
[Fact] [Fact]
public async Task Child_Matches_Control_When_It_Is_Child_OfType_And_Class() public async void Child_Matches_Control_When_It_Is_Child_OfType_And_Class()
{ {
var parent = new TestLogical1(); var parent = new TestLogical1();
var child = new TestLogical2(); var child = new TestLogical2();
@ -52,6 +54,7 @@ namespace Perspex.Styling.UnitTests
var selector = new Selector().OfType<TestLogical1>().Class("foo").Child().OfType<TestLogical2>(); var selector = new Selector().OfType<TestLogical1>().Class("foo").Child().OfType<TestLogical2>();
var activator = selector.Match(child).ObservableResult; var activator = selector.Match(child).ObservableResult;
var result = new List<bool>();
Assert.False(await activator.Take(1)); Assert.False(await activator.Take(1));
parent.Classes.Add("foo"); parent.Classes.Add("foo");
@ -96,6 +99,8 @@ namespace Perspex.Styling.UnitTests
} }
} }
IPerspexReadOnlyList<string> IStyleable.Classes => Classes;
public IDisposable Bind(PerspexProperty property, IObservable<object> source, BindingPriority priority) public IDisposable Bind(PerspexProperty property, IObservable<object> source, BindingPriority priority)
{ {
throw new NotImplementedException(); throw new NotImplementedException();

1
tests/Perspex.Styling.UnitTests/SelectorTests_Class.cs

@ -5,6 +5,7 @@ using System.Linq;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Moq; using Moq;
using Perspex.Controls;
using Perspex.Styling; using Perspex.Styling;
using Xunit; using Xunit;

3
tests/Perspex.Styling.UnitTests/SelectorTests_Descendent.cs

@ -7,6 +7,7 @@ using System.Reactive.Linq;
using System.Reactive.Subjects; using System.Reactive.Subjects;
using System.Threading.Tasks; using System.Threading.Tasks;
using Perspex.Collections; using Perspex.Collections;
using Perspex.Controls;
using Perspex.Styling; using Perspex.Styling;
using Xunit; using Xunit;
@ -128,6 +129,8 @@ namespace Perspex.Styling.UnitTests
} }
} }
IPerspexReadOnlyList<string> IStyleable.Classes => Classes;
public IDisposable Bind(PerspexProperty property, IObservable<object> source, BindingPriority priority) public IDisposable Bind(PerspexProperty property, IObservable<object> source, BindingPriority priority)
{ {
throw new NotImplementedException(); throw new NotImplementedException();

2
tests/Perspex.Styling.UnitTests/SelectorTests_Multiple.cs

@ -44,7 +44,7 @@ namespace Perspex.Styling.UnitTests
activator.Subscribe(x => values.Add(x)); activator.Subscribe(x => values.Add(x));
Assert.Equal(new[] { false }, values); Assert.Equal(new[] { false }, values);
control.Classes.Add("foo", "bar"); control.Classes.AddRange(new[] { "foo", "bar" });
Assert.Equal(new[] { false, true }, values); Assert.Equal(new[] { false, true }, values);
control.Classes.Remove("foo"); control.Classes.Remove("foo");
Assert.Equal(new[] { false, true, false }, values); Assert.Equal(new[] { false, true, false }, values);

4
tests/Perspex.Styling.UnitTests/TestControlBase.cs

@ -3,6 +3,8 @@
using System; using System;
using System.Reactive.Subjects; using System.Reactive.Subjects;
using Perspex.Collections;
using Perspex.Controls;
namespace Perspex.Styling.UnitTests namespace Perspex.Styling.UnitTests
{ {
@ -36,6 +38,8 @@ namespace Perspex.Styling.UnitTests
} }
} }
IPerspexReadOnlyList<string> IStyleable.Classes => Classes;
public IDisposable Bind(PerspexProperty property, IObservable<object> source, BindingPriority priority) public IDisposable Bind(PerspexProperty property, IObservable<object> source, BindingPriority priority)
{ {
throw new NotImplementedException(); throw new NotImplementedException();

4
tests/Perspex.Styling.UnitTests/TestTemplatedControl.cs

@ -4,6 +4,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reactive.Subjects; using System.Reactive.Subjects;
using Perspex.Collections;
using Perspex.Controls;
namespace Perspex.Styling.UnitTests namespace Perspex.Styling.UnitTests
{ {
@ -42,6 +44,8 @@ namespace Perspex.Styling.UnitTests
} }
} }
IPerspexReadOnlyList<string> IStyleable.Classes => Classes;
public IObservable<T> GetObservable<T>(PerspexProperty<T> property) public IObservable<T> GetObservable<T>(PerspexProperty<T> property)
{ {
throw new NotImplementedException(); throw new NotImplementedException();

Loading…
Cancel
Save