26 changed files with 580 additions and 17 deletions
@ -0,0 +1,15 @@ |
|||
// -----------------------------------------------------------------------
|
|||
// <copyright file="IPerspexList.cs" company="Steven Kirk">
|
|||
// Copyright 2014 MIT Licence. See licence.md for more information.
|
|||
// </copyright>
|
|||
// -----------------------------------------------------------------------
|
|||
|
|||
namespace Perspex.Collections |
|||
{ |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
|
|||
public interface IPerspexList<T> : IList<T>, IList, IReadOnlyPerspexList<T> |
|||
{ |
|||
} |
|||
} |
|||
@ -0,0 +1,113 @@ |
|||
// -----------------------------------------------------------------------
|
|||
// <copyright file="PerspexList.cs" company="Steven Kirk">
|
|||
// Copyright 2014 MIT Licence. See licence.md for more information.
|
|||
// </copyright>
|
|||
// -----------------------------------------------------------------------
|
|||
|
|||
namespace Perspex.Collections |
|||
{ |
|||
using System; |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using System.Collections.Specialized; |
|||
using System.ComponentModel; |
|||
using System.Linq; |
|||
|
|||
/// <summary>
|
|||
/// Implements the <see cref="IReadOnlyPerspexList{T}"/> interface for single items.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The type of the single item.</typeparam>
|
|||
/// <remarks>
|
|||
/// Classes such as Border can only ever have a single logical child, but they need to
|
|||
/// implement a list of logical children in their ILogical.LogicalChildren property using the
|
|||
/// <see cref="IReadOnlyPerspexList{T}"/> interface. This class facilitates that
|
|||
/// without creating an actual <see cref="PerspexList{T}"/>.
|
|||
/// </remarks>
|
|||
public class SingleItemPerspexList<T> : IReadOnlyPerspexList<T> where T : class |
|||
{ |
|||
private T item; |
|||
|
|||
public SingleItemPerspexList() |
|||
{ |
|||
} |
|||
|
|||
public SingleItemPerspexList(T item) |
|||
{ |
|||
this.item = item; |
|||
} |
|||
|
|||
public T this[int index] |
|||
{ |
|||
get |
|||
{ |
|||
if (index < 0 || index >= this.Count) |
|||
{ |
|||
throw new ArgumentOutOfRangeException(); |
|||
} |
|||
|
|||
return item; |
|||
} |
|||
} |
|||
|
|||
public int Count |
|||
{ |
|||
get { return this.item != null ? 1 : 0; } |
|||
} |
|||
|
|||
public T SingleItem |
|||
{ |
|||
get |
|||
{ |
|||
return this.item; |
|||
} |
|||
|
|||
set |
|||
{ |
|||
NotifyCollectionChangedEventArgs e = null; |
|||
bool countChanged = false; |
|||
|
|||
if (value == null && this.item != null ) |
|||
{ |
|||
e = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, this.item, 0); |
|||
this.item = null; |
|||
countChanged = true; |
|||
} |
|||
else if (value != null && this.item == null) |
|||
{ |
|||
e = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, this.item, 0); |
|||
this.item = value; |
|||
countChanged = true; |
|||
} |
|||
else |
|||
{ |
|||
e = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, value, this.item); |
|||
this.item = value; |
|||
} |
|||
|
|||
if (e != null && this.CollectionChanged != null) |
|||
{ |
|||
this.CollectionChanged(this, e); |
|||
} |
|||
|
|||
if (countChanged && this.PropertyChanged != null) |
|||
{ |
|||
this.PropertyChanged(this, new PropertyChangedEventArgs("Count")); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public event NotifyCollectionChangedEventHandler CollectionChanged; |
|||
|
|||
public event PropertyChangedEventHandler PropertyChanged; |
|||
|
|||
public IEnumerator<T> GetEnumerator() |
|||
{ |
|||
return Enumerable.Repeat(this.item, this.Count).GetEnumerator(); |
|||
} |
|||
|
|||
IEnumerator IEnumerable.GetEnumerator() |
|||
{ |
|||
return this.GetEnumerator(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,114 @@ |
|||
// -----------------------------------------------------------------------
|
|||
// <copyright file="DecoratorTests.cs" company="Steven Kirk">
|
|||
// Copyright 2013 MIT Licence. See licence.md for more information.
|
|||
// </copyright>
|
|||
// -----------------------------------------------------------------------
|
|||
|
|||
namespace Perspex.Controls.UnitTests |
|||
{ |
|||
using System.Collections.Specialized; |
|||
using System.Linq; |
|||
using Microsoft.VisualStudio.TestTools.UnitTesting; |
|||
|
|||
[TestClass] |
|||
public class DecoratorTests |
|||
{ |
|||
[TestMethod] |
|||
public void Setting_Content_Should_Set_Child_Controls_Parent() |
|||
{ |
|||
var decorator = new Decorator(); |
|||
var child = new Control(); |
|||
|
|||
decorator.Content = child; |
|||
|
|||
Assert.AreEqual(child.Parent, decorator); |
|||
Assert.AreEqual(((ILogical)child).LogicalParent, decorator); |
|||
} |
|||
|
|||
[TestMethod] |
|||
public void Clearing_Content_Should_Clear_Child_Controls_Parent() |
|||
{ |
|||
var decorator = new Decorator(); |
|||
var child = new Control(); |
|||
|
|||
decorator.Content = child; |
|||
decorator.Content = null; |
|||
|
|||
Assert.IsNull(child.Parent); |
|||
Assert.IsNull(((ILogical)child).LogicalParent); |
|||
} |
|||
|
|||
[TestMethod] |
|||
public void Content_Control_Should_Appear_In_LogicalChildren() |
|||
{ |
|||
var decorator = new Decorator(); |
|||
var child = new Control(); |
|||
|
|||
decorator.Content = child; |
|||
|
|||
CollectionAssert.AreEqual(new[] { child }, ((ILogical)decorator).LogicalChildren.ToList()); |
|||
} |
|||
|
|||
[TestMethod] |
|||
public void Clearing_Content_Should_Remove_From_LogicalChildren() |
|||
{ |
|||
var decorator = new Decorator(); |
|||
var child = new Control(); |
|||
|
|||
decorator.Content = child; |
|||
decorator.Content = null; |
|||
|
|||
CollectionAssert.AreEqual(new ILogical[0], ((ILogical)decorator).LogicalChildren.ToList()); |
|||
} |
|||
|
|||
[TestMethod] |
|||
public void Setting_Content_Should_Fire_LogicalChildren_CollectionChanged() |
|||
{ |
|||
var decorator = new Decorator(); |
|||
var child = new Control(); |
|||
var called = false; |
|||
|
|||
((ILogical)decorator).LogicalChildren.CollectionChanged += (s, e) => |
|||
called = e.Action == NotifyCollectionChangedAction.Add; |
|||
|
|||
decorator.Content = child; |
|||
|
|||
Assert.IsTrue(called); |
|||
} |
|||
|
|||
[TestMethod] |
|||
public void Clearing_Content_Should_Fire_LogicalChildren_CollectionChanged() |
|||
{ |
|||
var decorator = new Decorator(); |
|||
var child = new Control(); |
|||
var called = false; |
|||
|
|||
decorator.Content = child; |
|||
|
|||
((ILogical)decorator).LogicalChildren.CollectionChanged += (s, e) => |
|||
called = e.Action == NotifyCollectionChangedAction.Remove; |
|||
|
|||
decorator.Content = null; |
|||
|
|||
Assert.IsTrue(called); |
|||
} |
|||
|
|||
[TestMethod] |
|||
public void Changing_Content_Should_Fire_LogicalChildren_CollectionChanged() |
|||
{ |
|||
var decorator = new Decorator(); |
|||
var child1 = new Control(); |
|||
var child2 = new Control(); |
|||
var called = false; |
|||
|
|||
decorator.Content = child1; |
|||
|
|||
((ILogical)decorator).LogicalChildren.CollectionChanged += (s, e) => |
|||
called = e.Action == NotifyCollectionChangedAction.Replace; |
|||
|
|||
decorator.Content = child2; |
|||
|
|||
Assert.IsTrue(called); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,82 @@ |
|||
// -----------------------------------------------------------------------
|
|||
// <copyright file="PanelTests.cs" company="Steven Kirk">
|
|||
// Copyright 2013 MIT Licence. See licence.md for more information.
|
|||
// </copyright>
|
|||
// -----------------------------------------------------------------------
|
|||
|
|||
namespace Perspex.Controls.UnitTests |
|||
{ |
|||
using System.Linq; |
|||
using Microsoft.VisualStudio.TestTools.UnitTesting; |
|||
|
|||
[TestClass] |
|||
public class PanelTests |
|||
{ |
|||
[TestMethod] |
|||
public void Adding_Control_To_Panel_Should_Set_Child_Controls_Parent() |
|||
{ |
|||
var panel = new Panel(); |
|||
var child = new Control(); |
|||
|
|||
panel.Children.Add(child); |
|||
|
|||
Assert.AreEqual(child.Parent, panel); |
|||
Assert.AreEqual(((ILogical)child).LogicalParent, panel); |
|||
} |
|||
|
|||
[TestMethod] |
|||
public void Removing_Control_From_Panel_Should_Clear_Child_Controls_Parent() |
|||
{ |
|||
var panel = new Panel(); |
|||
var child = new Control(); |
|||
|
|||
panel.Children.Add(child); |
|||
panel.Children.Remove(child); |
|||
|
|||
Assert.IsNull(child.Parent); |
|||
Assert.IsNull(((ILogical)child).LogicalParent); |
|||
} |
|||
|
|||
[TestMethod] |
|||
public void Clearing_Panel_Children_Should_Clear_Child_Controls_Parent() |
|||
{ |
|||
var panel = new Panel(); |
|||
var child1 = new Control(); |
|||
var child2 = new Control(); |
|||
|
|||
panel.Children.Add(child1); |
|||
panel.Children.Add(child2); |
|||
panel.Children.Clear(); |
|||
|
|||
Assert.IsNull(child1.Parent); |
|||
Assert.IsNull(((ILogical)child1).LogicalParent); |
|||
Assert.IsNull(child2.Parent); |
|||
Assert.IsNull(((ILogical)child2).LogicalParent); |
|||
} |
|||
|
|||
[TestMethod] |
|||
public void Child_Control_Should_Appear_In_Panel_Children() |
|||
{ |
|||
var panel = new Panel(); |
|||
var child = new Control(); |
|||
|
|||
panel.Children.Add(child); |
|||
|
|||
CollectionAssert.AreEqual(new[] { child }, panel.Children); |
|||
CollectionAssert.AreEqual(new[] { child }, ((ILogical)panel).LogicalChildren.ToList()); |
|||
} |
|||
|
|||
[TestMethod] |
|||
public void Removing_Child_Control_Should_Remove_From_Panel_Children() |
|||
{ |
|||
var panel = new Panel(); |
|||
var child = new Control(); |
|||
|
|||
panel.Children.Add(child); |
|||
panel.Children.Remove(child); |
|||
|
|||
CollectionAssert.AreEqual(new Control[0], panel.Children); |
|||
CollectionAssert.AreEqual(new ILogical[0], ((ILogical)panel).LogicalChildren.ToList()); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
// -----------------------------------------------------------------------
|
|||
// <copyright file="ILogical.cs" company="Steven Kirk">
|
|||
// Copyright 2014 MIT Licence. See licence.md for more information.
|
|||
// </copyright>
|
|||
// -----------------------------------------------------------------------
|
|||
|
|||
namespace Perspex.Controls |
|||
{ |
|||
using System.Collections.Generic; |
|||
using Perspex.Collections; |
|||
|
|||
/// <summary>
|
|||
/// Represents a node in the logical tree.
|
|||
/// </summary>
|
|||
public interface ILogical |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the logical parent.
|
|||
/// </summary>
|
|||
ILogical LogicalParent { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the logical children.
|
|||
/// </summary>
|
|||
IReadOnlyPerspexList<ILogical> LogicalChildren { get; } |
|||
} |
|||
} |
|||
Loading…
Reference in new issue