Browse Source

Make IStyleable.Classes an IPerspexReadOnlyList.

So we can mock it.
pull/366/head
Steven Kirk 10 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.Globalization;
using OmniXaml.TypeConversion;
using Perspex.Controls;
using Perspex.Styling;
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)
{
_classes.Clear();
_classes.Add(value);
_classes.AddRange(value);
}
}
}
@ -216,6 +216,9 @@ namespace Perspex.Controls
/// </summary>
IPerspexReadOnlyList<ILogical> ILogical.LogicalChildren => LogicalChildren;
/// <inheritdoc/>
IPerspexReadOnlyList<string> IStyleable.Classes => Classes;
/// <summary>
/// Gets the type by which the control is styled.
/// </summary>

5
src/Perspex.Controls/IControl.cs

@ -13,6 +13,11 @@ namespace Perspex.Controls
/// </summary>
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>
/// Gets or sets the control's data context.
/// </summary>

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

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

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

@ -593,7 +593,6 @@ namespace Perspex.Controls.Primitives
try
{
var selectable = container as ISelectable;
var styleable = container as IStyleable;
_ignoreContainerSelectionChanged = true;
@ -601,15 +600,15 @@ namespace Perspex.Controls.Primitives
{
selectable.IsSelected = selected;
}
else if (styleable != null)
else
{
if (selected)
{
styleable.Classes.Add(":selected");
container.Classes.Add(":selected");
}
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)
{
var selectable = container as ISelectable;
var styleable = container as IStyleable;
if (selectable != null)
{
selectable.IsSelected = selected;
}
else if (styleable != null)
else
{
if (selected)
{
styleable.Classes.Add(":selected");
container.Classes.Add(":selected");
}
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.
using System;
using System.Collections.Specialized;
using System.Reactive;
using System.Reactive.Linq;
using Perspex.Controls;
@ -18,7 +19,13 @@ namespace Perspex.Diagnostics.ViewModels
Control = control;
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)
.Subscribe(_ =>
{

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

@ -45,7 +45,6 @@
<Compile Include="ILogical.cs" />
<Compile Include="LogicalTree\LogicalExtensions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Styling\Classes.cs" />
<Compile Include="Styling\IGlobalStyles.cs" />
<Compile Include="Styling\ISetter.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.
using System;
using Perspex.Collections;
namespace Perspex.Styling
{
@ -13,7 +14,7 @@ namespace Perspex.Styling
/// <summary>
/// Gets the list of classes for the control.
/// </summary>
Classes Classes { get; }
IPerspexReadOnlyList<string> Classes { get; }
/// <summary>
/// Gets the type by which the control is styled.

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

@ -3,6 +3,8 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Reactive.Linq;
using System.Reflection;
@ -176,10 +178,16 @@ namespace Perspex.Styling
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(
Observable
.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)

1
tests/Perspex.LeakTests/StyleTests.cs

@ -123,6 +123,7 @@ namespace Perspex.LeakTests
dotMemory.Check(memory =>
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.TypeConversion;
using OmniXaml.Typing;
using Perspex.Collections;
using Perspex.Controls;
using Perspex.Markup.Xaml.Converters;
using Perspex.Styling;
using Xunit;
@ -74,7 +76,7 @@ namespace Perspex.Markup.Xaml.UnitTests.Converters
public static readonly PerspexProperty<string> FooProperty =
PerspexProperty.Register<Class1, string>("Foo");
public Classes Classes
public IPerspexReadOnlyList<string> Classes
{
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.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading.Tasks;
using Perspex.Collections;
using Perspex.Controls;
using Perspex.Styling;
using Xunit;
@ -43,7 +45,7 @@ namespace Perspex.Styling.UnitTests
}
[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 child = new TestLogical2();
@ -52,6 +54,7 @@ namespace Perspex.Styling.UnitTests
var selector = new Selector().OfType<TestLogical1>().Class("foo").Child().OfType<TestLogical2>();
var activator = selector.Match(child).ObservableResult;
var result = new List<bool>();
Assert.False(await activator.Take(1));
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)
{
throw new NotImplementedException();

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

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

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

@ -7,6 +7,7 @@ using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Threading.Tasks;
using Perspex.Collections;
using Perspex.Controls;
using Perspex.Styling;
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)
{
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));
Assert.Equal(new[] { false }, values);
control.Classes.Add("foo", "bar");
control.Classes.AddRange(new[] { "foo", "bar" });
Assert.Equal(new[] { false, true }, values);
control.Classes.Remove("foo");
Assert.Equal(new[] { false, true, false }, values);

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

@ -3,6 +3,8 @@
using System;
using System.Reactive.Subjects;
using Perspex.Collections;
using Perspex.Controls;
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)
{
throw new NotImplementedException();

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

@ -4,6 +4,8 @@
using System;
using System.Collections.Generic;
using System.Reactive.Subjects;
using Perspex.Collections;
using Perspex.Controls;
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)
{
throw new NotImplementedException();

Loading…
Cancel
Save