diff --git a/Perspex.Animation/PropertyTransitions.cs b/Perspex.Animation/PropertyTransitions.cs index 9b578fc942..1bb91b18f1 100644 --- a/Perspex.Animation/PropertyTransitions.cs +++ b/Perspex.Animation/PropertyTransitions.cs @@ -4,6 +4,8 @@ // // ----------------------------------------------------------------------- +using Perspex.Collections; + namespace Perspex.Animation { public class PropertyTransitions : PerspexList diff --git a/Perspex.Base/Collections/IPerspexList.cs b/Perspex.Base/Collections/IPerspexList.cs new file mode 100644 index 0000000000..6d958f07fb --- /dev/null +++ b/Perspex.Base/Collections/IPerspexList.cs @@ -0,0 +1,15 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2014 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Collections +{ + using System.Collections; + using System.Collections.Generic; + + public interface IPerspexList : IList, IList, IReadOnlyPerspexList + { + } +} \ No newline at end of file diff --git a/Perspex.Base/IReadOnlyPerspexList.cs b/Perspex.Base/Collections/IReadOnlyPerspexList.cs similarity index 74% rename from Perspex.Base/IReadOnlyPerspexList.cs rename to Perspex.Base/Collections/IReadOnlyPerspexList.cs index 87b7074bd2..7329082f9f 100644 --- a/Perspex.Base/IReadOnlyPerspexList.cs +++ b/Perspex.Base/Collections/IReadOnlyPerspexList.cs @@ -4,13 +4,13 @@ // // ----------------------------------------------------------------------- -namespace Perspex +namespace Perspex.Collections { using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; - public interface IReadOnlyPerspexList : IReadOnlyList, INotifyCollectionChanged, INotifyPropertyChanged + public interface IReadOnlyPerspexList : IReadOnlyList, INotifyCollectionChanged, INotifyPropertyChanged { } } \ No newline at end of file diff --git a/Perspex.Base/PerspexList.cs b/Perspex.Base/Collections/PerspexList.cs similarity index 91% rename from Perspex.Base/PerspexList.cs rename to Perspex.Base/Collections/PerspexList.cs index 13fa97801c..b0775bd4a9 100644 --- a/Perspex.Base/PerspexList.cs +++ b/Perspex.Base/Collections/PerspexList.cs @@ -4,7 +4,7 @@ // // ----------------------------------------------------------------------- -namespace Perspex +namespace Perspex.Collections { using System; using System.Collections; @@ -13,7 +13,17 @@ namespace Perspex using System.ComponentModel; using System.Linq; - public class PerspexList : IList, IList, IReadOnlyPerspexList, INotifyCollectionChanged, INotifyPropertyChanged + /// + /// A notifying list. + /// + /// The type of the list items. + /// + /// PerspexList is similar to + /// except that when the method is called, it notifies with a + /// action, passing the items that were + /// removed. + /// + public class PerspexList : IPerspexList, INotifyCollectionChanged, INotifyPropertyChanged { private List inner; diff --git a/Perspex.Base/PerspexListExtensions.cs b/Perspex.Base/Collections/PerspexListExtensions.cs similarity index 99% rename from Perspex.Base/PerspexListExtensions.cs rename to Perspex.Base/Collections/PerspexListExtensions.cs index 13ee014d49..62c754f2b3 100644 --- a/Perspex.Base/PerspexListExtensions.cs +++ b/Perspex.Base/Collections/PerspexListExtensions.cs @@ -4,7 +4,7 @@ // // ----------------------------------------------------------------------- -namespace Perspex +namespace Perspex.Collections { using System; using System.Collections.Generic; diff --git a/Perspex.Base/Collections/SingleItemPerspexList.cs b/Perspex.Base/Collections/SingleItemPerspexList.cs new file mode 100644 index 0000000000..96a629d556 --- /dev/null +++ b/Perspex.Base/Collections/SingleItemPerspexList.cs @@ -0,0 +1,113 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2014 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Collections +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Collections.Specialized; + using System.ComponentModel; + using System.Linq; + + /// + /// Implements the interface for single items. + /// + /// The type of the single item. + /// + /// 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 + /// interface. This class facilitates that + /// without creating an actual . + /// + public class SingleItemPerspexList : IReadOnlyPerspexList 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 GetEnumerator() + { + return Enumerable.Repeat(this.item, this.Count).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return this.GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/Perspex.Base/Perspex.Base.csproj b/Perspex.Base/Perspex.Base.csproj index 715391fbfa..70631febbb 100644 --- a/Perspex.Base/Perspex.Base.csproj +++ b/Perspex.Base/Perspex.Base.csproj @@ -35,13 +35,15 @@ + + + + + - - - diff --git a/Perspex.Controls.UnitTests/ContentControlTests.cs b/Perspex.Controls.UnitTests/ContentControlTests.cs index 67dc838d4f..c7d3351ec8 100644 --- a/Perspex.Controls.UnitTests/ContentControlTests.cs +++ b/Perspex.Controls.UnitTests/ContentControlTests.cs @@ -7,6 +7,7 @@ namespace Perspex.Controls.UnitTests { using System; + using System.Collections.Specialized; using System.Linq; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -92,6 +93,104 @@ namespace Perspex.Controls.UnitTests Assert.IsNull(child.TemplatedParent); } + [TestMethod] + public void Setting_Content_Should_Set_Child_Controls_Parent() + { + var target = new ContentControl(); + var child = new Control(); + + target.Content = child; + + Assert.AreEqual(child.Parent, target); + Assert.AreEqual(((ILogical)child).LogicalParent, target); + } + + [TestMethod] + public void Clearing_Content_Should_Clear_Child_Controls_Parent() + { + var target = new ContentControl(); + var child = new Control(); + + target.Content = child; + target.Content = null; + + Assert.IsNull(child.Parent); + Assert.IsNull(((ILogical)child).LogicalParent); + } + + [TestMethod] + public void Setting_Content_To_Control_Should_Make_Control_Appear_In_LogicalChildren() + { + var target = new ContentControl(); + var child = new Control(); + + target.Content = child; + + CollectionAssert.AreEqual(new[] { child }, ((ILogical)target).LogicalChildren.ToList()); + } + + [TestMethod] + public void Clearing_Content_Should_Remove_From_LogicalChildren() + { + var contentControl = new ContentControl(); + var child = new Control(); + + contentControl.Content = child; + contentControl.Content = null; + + CollectionAssert.AreEqual(new ILogical[0], ((ILogical)contentControl).LogicalChildren.ToList()); + } + + [TestMethod] + public void Setting_Content_Should_Fire_LogicalChildren_CollectionChanged() + { + var contentControl = new ContentControl(); + var child = new Control(); + var called = false; + + ((ILogical)contentControl).LogicalChildren.CollectionChanged += (s, e) => + called = e.Action == NotifyCollectionChangedAction.Add; + + contentControl.Content = child; + + Assert.IsTrue(called); + } + + [TestMethod] + public void Clearing_Content_Should_Fire_LogicalChildren_CollectionChanged() + { + var contentControl = new ContentControl(); + var child = new Control(); + var called = false; + + contentControl.Content = child; + + ((ILogical)contentControl).LogicalChildren.CollectionChanged += (s, e) => + called = e.Action == NotifyCollectionChangedAction.Remove; + + contentControl.Content = null; + + Assert.IsTrue(called); + } + + [TestMethod] + public void Changing_Content_Should_Fire_LogicalChildren_CollectionChanged() + { + var contentControl = new ContentControl(); + var child1 = new Control(); + var child2 = new Control(); + var called = false; + + contentControl.Content = child1; + + ((ILogical)contentControl).LogicalChildren.CollectionChanged += (s, e) => + called = e.Action == NotifyCollectionChangedAction.Replace; + + contentControl.Content = child2; + + Assert.IsTrue(called); + } + private void ApplyTemplate(ILayoutable control) { control.Measure(new Size(100, 100)); diff --git a/Perspex.Controls.UnitTests/DecoratorTests.cs b/Perspex.Controls.UnitTests/DecoratorTests.cs new file mode 100644 index 0000000000..ae6a82d98e --- /dev/null +++ b/Perspex.Controls.UnitTests/DecoratorTests.cs @@ -0,0 +1,114 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2013 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +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); + } + } +} diff --git a/Perspex.Controls.UnitTests/PanelTests.cs b/Perspex.Controls.UnitTests/PanelTests.cs new file mode 100644 index 0000000000..f4976e9399 --- /dev/null +++ b/Perspex.Controls.UnitTests/PanelTests.cs @@ -0,0 +1,82 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2013 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +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()); + } + } +} diff --git a/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj b/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj index 4eea508951..c16687597e 100644 --- a/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj +++ b/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj @@ -65,6 +65,8 @@ + + diff --git a/Perspex.Controls/ColumnDefinitions.cs b/Perspex.Controls/ColumnDefinitions.cs index 73656b8854..0dc5a1834a 100644 --- a/Perspex.Controls/ColumnDefinitions.cs +++ b/Perspex.Controls/ColumnDefinitions.cs @@ -4,6 +4,8 @@ // // ----------------------------------------------------------------------- +using Perspex.Collections; + namespace Perspex.Controls { public class ColumnDefinitions : PerspexList diff --git a/Perspex.Controls/ContentControl.cs b/Perspex.Controls/ContentControl.cs index ad4bb2f6d2..df9ec3a8ca 100644 --- a/Perspex.Controls/ContentControl.cs +++ b/Perspex.Controls/ContentControl.cs @@ -6,10 +6,12 @@ namespace Perspex.Controls { + using System; + using Perspex.Collections; using Perspex.Controls.Primitives; using Perspex.Layout; - public class ContentControl : TemplatedControl + public class ContentControl : TemplatedControl, ILogical { public static readonly PerspexProperty ContentProperty = PerspexProperty.Register("Content"); @@ -20,12 +22,40 @@ namespace Perspex.Controls public static readonly PerspexProperty VerticalContentAlignmentProperty = PerspexProperty.Register("VerticalContentAlignment"); + private SingleItemPerspexList logicalChild = new SingleItemPerspexList(); + + public ContentControl() + { + this.GetObservableWithHistory(ContentProperty).Subscribe(x => + { + var control1 = x.Item1 as Control; + var control2 = x.Item2 as Control; + + if (control1 != null) + { + control1.Parent = null; + } + + if (control2 != null) + { + control2.Parent = this; + } + + this.logicalChild.SingleItem = control2; + }); + } + public object Content { get { return this.GetValue(ContentProperty); } set { this.SetValue(ContentProperty, value); } } + IReadOnlyPerspexList ILogical.LogicalChildren + { + get { return this.logicalChild; } + } + public HorizontalAlignment HorizontalContentAlignment { get { return this.GetValue(HorizontalContentAlignmentProperty); } diff --git a/Perspex.Controls/Control.cs b/Perspex.Controls/Control.cs index f7b60daf9d..2b5a8b5075 100644 --- a/Perspex.Controls/Control.cs +++ b/Perspex.Controls/Control.cs @@ -7,8 +7,10 @@ namespace Perspex.Controls { using System; + using System.Collections.Generic; + using System.Linq; using System.Reactive.Linq; - using Perspex.Animation; + using Perspex.Collections; using Perspex.Input; using Perspex.Interactivity; using Perspex.Media; @@ -16,7 +18,7 @@ namespace Perspex.Controls using Perspex.Styling; using Splat; - public class Control : InputElement, IStyleable, IStyleHost + public class Control : InputElement, ILogical, IStyleable, IStyleHost { public static readonly PerspexProperty BorderBrushProperty = PerspexProperty.Register("BorderBrush"); @@ -27,6 +29,9 @@ namespace Perspex.Controls public static readonly PerspexProperty ForegroundProperty = PerspexProperty.Register("Foreground", new SolidColorBrush(0xff000000), inherits: true); + public static readonly PerspexProperty ParentProperty = + PerspexProperty.Register("Parent"); + public static readonly PerspexProperty TemplatedParentProperty = PerspexProperty.Register("TemplatedParent", inherits: true); @@ -143,12 +148,28 @@ namespace Perspex.Controls } } + public Control Parent + { + get { return this.GetValue(ParentProperty); } + internal set { this.SetValue(ParentProperty, value); } + } + public ITemplatedControl TemplatedParent { get { return this.GetValue(TemplatedParentProperty); } internal set { this.SetValue(TemplatedParentProperty, value); } } + ILogical ILogical.LogicalParent + { + get { return this.Parent; } + } + + IReadOnlyPerspexList ILogical.LogicalChildren + { + get { throw new NotImplementedException(); } + } + public void BringIntoView() { this.BringIntoView(new Rect(this.ActualSize)); diff --git a/Perspex.Controls/Controls.cs b/Perspex.Controls/Controls.cs index 5214e59ade..353ecf03db 100644 --- a/Perspex.Controls/Controls.cs +++ b/Perspex.Controls/Controls.cs @@ -7,6 +7,7 @@ namespace Perspex.Controls { using System.Collections.Generic; + using Perspex.Collections; public class Controls : PerspexList { diff --git a/Perspex.Controls/DataTemplates.cs b/Perspex.Controls/DataTemplates.cs index 1f81fde90f..42a1a17182 100644 --- a/Perspex.Controls/DataTemplates.cs +++ b/Perspex.Controls/DataTemplates.cs @@ -13,6 +13,7 @@ namespace Perspex.Controls using System.Linq; using System.Reactive; using System.Reactive.Subjects; + using Perspex.Collections; public class DataTemplates : PerspexList { diff --git a/Perspex.Controls/Decorator.cs b/Perspex.Controls/Decorator.cs index 231fe7b820..1ae8711fcd 100644 --- a/Perspex.Controls/Decorator.cs +++ b/Perspex.Controls/Decorator.cs @@ -10,9 +10,10 @@ namespace Perspex.Controls using System.Collections.Generic; using System.Linq; using System.Reactive.Linq; + using Perspex.Collections; using Perspex.Layout; - public class Decorator : Control, IVisual + public class Decorator : Control, IVisual, ILogical { public static readonly PerspexProperty ContentProperty = PerspexProperty.Register("Content"); @@ -20,16 +21,25 @@ namespace Perspex.Controls public static readonly PerspexProperty PaddingProperty = PerspexProperty.Register("Padding"); + private SingleItemPerspexList logicalChild = new SingleItemPerspexList(); + public Decorator() { - this.GetObservable(ContentProperty).Subscribe(x => + this.GetObservableWithHistory(ContentProperty).Subscribe(x => { - this.ClearVisualChildren(); + if (x.Item1 != null) + { + this.RemoveVisualChild(x.Item1); + x.Item1.Parent = null; + } - if (x != null) + if (x.Item2 != null) { - this.AddVisualChild(x); + this.AddVisualChild(x.Item2); + x.Item2.Parent = this; } + + this.logicalChild.SingleItem = x.Item2; }); } @@ -45,6 +55,11 @@ namespace Perspex.Controls set { this.SetValue(PaddingProperty, value); } } + IReadOnlyPerspexList ILogical.LogicalChildren + { + get { return this.logicalChild; } + } + protected override Size ArrangeOverride(Size finalSize) { Control content = this.Content; diff --git a/Perspex.Controls/Grid.cs b/Perspex.Controls/Grid.cs index 789c4e06c7..b5e57cc178 100644 --- a/Perspex.Controls/Grid.cs +++ b/Perspex.Controls/Grid.cs @@ -9,6 +9,7 @@ namespace Perspex.Controls using System; using System.Collections.Generic; using System.Linq; + using Perspex.Collections; public class Grid : Panel { diff --git a/Perspex.Controls/ILogical.cs b/Perspex.Controls/ILogical.cs new file mode 100644 index 0000000000..1435f85651 --- /dev/null +++ b/Perspex.Controls/ILogical.cs @@ -0,0 +1,27 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2014 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Controls +{ + using System.Collections.Generic; + using Perspex.Collections; + + /// + /// Represents a node in the logical tree. + /// + public interface ILogical + { + /// + /// Gets the logical parent. + /// + ILogical LogicalParent { get; } + + /// + /// Gets the logical children. + /// + IReadOnlyPerspexList LogicalChildren { get; } + } +} diff --git a/Perspex.Controls/Panel.cs b/Perspex.Controls/Panel.cs index 147831e3bf..d449f4da05 100644 --- a/Perspex.Controls/Panel.cs +++ b/Perspex.Controls/Panel.cs @@ -9,11 +9,12 @@ namespace Perspex.Controls using System; using System.Collections.Specialized; using System.Linq; + using Perspex.Collections; /// /// Base class for controls that can contain multiple children. /// - public class Panel : Control + public class Panel : Control, ILogical { private Controls children; @@ -54,6 +55,11 @@ namespace Perspex.Controls } } + IReadOnlyPerspexList ILogical.LogicalChildren + { + get { return this.children; } + } + private void ChildrenChanged(object sender, NotifyCollectionChangedEventArgs e) { // TODO: Handle Move and Replace. @@ -61,10 +67,22 @@ namespace Perspex.Controls { case NotifyCollectionChangedAction.Add: this.AddVisualChildren(e.NewItems.OfType()); + + foreach (var child in e.NewItems.OfType()) + { + child.Parent = this; + } + break; case NotifyCollectionChangedAction.Remove: this.RemoveVisualChildren(e.OldItems.OfType()); + + foreach (var child in e.OldItems.OfType()) + { + child.Parent = null; + } + break; case NotifyCollectionChangedAction.Reset: diff --git a/Perspex.Controls/Perspex.Controls.csproj b/Perspex.Controls/Perspex.Controls.csproj index 98bf840977..1ce77bb0e5 100644 --- a/Perspex.Controls/Perspex.Controls.csproj +++ b/Perspex.Controls/Perspex.Controls.csproj @@ -36,6 +36,7 @@ + diff --git a/Perspex.Controls/RowDefinitions.cs b/Perspex.Controls/RowDefinitions.cs index 60ea0da556..7affaa019f 100644 --- a/Perspex.Controls/RowDefinitions.cs +++ b/Perspex.Controls/RowDefinitions.cs @@ -6,6 +6,8 @@ namespace Perspex.Controls { + using Perspex.Collections; + public class RowDefinitions : PerspexList { } diff --git a/Perspex.SceneGraph/IVisual.cs b/Perspex.SceneGraph/IVisual.cs index 12a1104864..24dee5fc20 100644 --- a/Perspex.SceneGraph/IVisual.cs +++ b/Perspex.SceneGraph/IVisual.cs @@ -7,6 +7,7 @@ namespace Perspex { using System.Collections.Generic; + using Perspex.Collections; using Perspex.Media; /// diff --git a/Perspex.SceneGraph/Visual.cs b/Perspex.SceneGraph/Visual.cs index 28eed3521f..2f9351fc12 100644 --- a/Perspex.SceneGraph/Visual.cs +++ b/Perspex.SceneGraph/Visual.cs @@ -12,6 +12,7 @@ namespace Perspex using System.Linq; using System.Reactive.Linq; using Perspex.Animation; + using Perspex.Collections; using Perspex.Media; using Perspex.Rendering; using Splat; diff --git a/Perspex.Styling/Styles.cs b/Perspex.Styling/Styles.cs index b6e1111b54..5e95978abe 100644 --- a/Perspex.Styling/Styles.cs +++ b/Perspex.Styling/Styles.cs @@ -6,6 +6,8 @@ namespace Perspex.Styling { + using Perspex.Collections; + public class Styles : PerspexList, IStyle { public void Attach(IStyleable control) diff --git a/TestApplication/Program.cs b/TestApplication/Program.cs index 297e244473..f3543bff94 100644 --- a/TestApplication/Program.cs +++ b/TestApplication/Program.cs @@ -2,6 +2,7 @@ using System.Reactive.Linq; using Perspex; using Perspex.Animation; +using Perspex.Collections; using Perspex.Controls; using Perspex.Controls.Primitives; using Perspex.Controls.Shapes;