diff --git a/src/Perspex.Controls/Generators/ITreeItemContainerGenerator.cs b/src/Perspex.Controls/Generators/ITreeItemContainerGenerator.cs index 37f097618b..fa78433c57 100644 --- a/src/Perspex.Controls/Generators/ITreeItemContainerGenerator.cs +++ b/src/Perspex.Controls/Generators/ITreeItemContainerGenerator.cs @@ -11,23 +11,8 @@ namespace Perspex.Controls.Generators public interface ITreeItemContainerGenerator : IItemContainerGenerator { /// - /// Gets the item container for the root of the tree, or null if this generator is itself - /// the root of the tree. + /// Gets the container index for the tree. /// - ITreeItemContainerGenerator RootGenerator { get; } - - /// - /// Gets the item container for the specified item, anywhere in the tree. - /// - /// The item. - /// The container, or null if not found. - IControl TreeContainerFromItem(object item); - - /// - /// Gets the item for the specified item container, anywhere in the tree. - /// - /// The container. - /// The item, or null if not found. - object TreeItemFromContainer(IControl container); + TreeContainerIndex Index { get; } } } \ No newline at end of file diff --git a/src/Perspex.Controls/Generators/TreeContainerIndex.cs b/src/Perspex.Controls/Generators/TreeContainerIndex.cs new file mode 100644 index 0000000000..9de4ca1050 --- /dev/null +++ b/src/Perspex.Controls/Generators/TreeContainerIndex.cs @@ -0,0 +1,87 @@ +// 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; + +namespace Perspex.Controls.Generators +{ + /// + /// Maintains an index of all item containers currently materialized by a . + /// + /// + /// Each has its own + /// that maintains the list of its direct children, but they also share an instance of this + /// class in their property which tracks + /// the containers materialized for the entire tree. + /// + public class TreeContainerIndex + { + private readonly Dictionary _itemToContainer = new Dictionary(); + private readonly Dictionary _containerToItem = new Dictionary(); + + /// + /// Gets the currently materialized containers. + /// + public IEnumerable Items => _containerToItem.Keys; + + /// + /// Adds an entry to the index. + /// + /// The item. + /// The item container. + public void Add(object item, IControl container) + { + _itemToContainer.Add(item, container); + _containerToItem.Add(container, item); + } + + /// + /// Removes a container from the index. + /// + /// The item container. + public void Remove(IControl container) + { + var item = _containerToItem[container]; + _containerToItem.Remove(container); + _itemToContainer.Remove(item); + } + + /// + /// Removes a set of containers from the index. + /// + /// The item containers. + public void Remove(IEnumerable containers) + { + foreach (var container in containers) + { + var item = _containerToItem[container.ContainerControl]; + _containerToItem.Remove(container.ContainerControl); + _itemToContainer.Remove(item); + } + } + + /// + /// Gets the container for an item. + /// + /// The item. + /// The container, or null of not found. + public IControl ContainerFromItem(object item) + { + IControl result; + _itemToContainer.TryGetValue(item, out result); + return result; + } + + /// + /// Gets the item for a container. + /// + /// The container. + /// The item, or null of not found. + public object ItemFromContainer(IControl container) + { + object result; + _containerToItem.TryGetValue(container, out result); + return result; + } + } +} diff --git a/src/Perspex.Controls/Generators/TreeItemContainerGenerator.cs b/src/Perspex.Controls/Generators/TreeItemContainerGenerator.cs index 4caa53e3c1..0f2db6aa50 100644 --- a/src/Perspex.Controls/Generators/TreeItemContainerGenerator.cs +++ b/src/Perspex.Controls/Generators/TreeItemContainerGenerator.cs @@ -1,6 +1,7 @@ // 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 Perspex.Controls.Templates; @@ -14,9 +15,6 @@ namespace Perspex.Controls.Generators public class TreeItemContainerGenerator : ItemContainerGenerator, ITreeItemContainerGenerator where T : class, IControl, new() { - private readonly Dictionary _itemToContainer; - private readonly Dictionary _containerToItem; - /// /// Initializes a new instance of the class. /// @@ -24,34 +22,30 @@ namespace Perspex.Controls.Generators /// The container's Content property. /// The container's Items property. /// The container's IsExpanded property. - /// - /// The item container for the root of the tree, or null if this generator is itself the - /// root of the tree. - /// + /// The container index for the tree public TreeItemContainerGenerator( IControl owner, PerspexProperty contentProperty, PerspexProperty itemsProperty, PerspexProperty isExpandedProperty, - ITreeItemContainerGenerator rootGenerator) + TreeContainerIndex index) : base(owner, contentProperty) { + Contract.Requires(owner != null); + Contract.Requires(contentProperty != null); + Contract.Requires(itemsProperty != null); + Contract.Requires(isExpandedProperty != null); + Contract.Requires(index != null); + ItemsProperty = itemsProperty; IsExpandedProperty = isExpandedProperty; - RootGenerator = rootGenerator; - - if (rootGenerator == null) - { - _itemToContainer = new Dictionary(); - _containerToItem = new Dictionary(); - } + Index = index; } /// - /// Gets the item container for the root of the tree, or null if this generator is itself - /// the root of the tree. + /// Gets the container index for the tree. /// - public ITreeItemContainerGenerator RootGenerator { get; } + public TreeContainerIndex Index { get; } /// /// Gets the item container's Items property. @@ -63,30 +57,6 @@ namespace Perspex.Controls.Generators /// protected PerspexProperty IsExpandedProperty { get; } - /// - /// Gets the item container for the specified item, anywhere in the tree. - /// - /// The item. - /// The container, or null if not found. - public IControl TreeContainerFromItem(object item) - { - T result; - _itemToContainer.TryGetValue(item, out result); - return result; - } - - /// - /// Gets the item for the specified item container, anywhere in the tree. - /// - /// The container. - /// The item, or null if not found. - public object TreeItemFromContainer(IControl container) - { - object result; - _containerToItem.TryGetValue(container, out result); - return result; - } - /// protected override IControl CreateContainer(object item) { @@ -114,7 +84,7 @@ namespace Perspex.Controls.Generators result.DataContext = item; } - AddToIndex(item, result); + Index.Add(item, result); return result; } @@ -122,59 +92,17 @@ namespace Perspex.Controls.Generators public override IEnumerable Clear() { - ClearIndex(); - return base.Clear(); + var items = base.Clear(); + Index.Remove(items); + return items; } public override IEnumerable Dematerialize(int startingIndex, int count) { - RemoveFromIndex(GetContainerRange(startingIndex, count)); + Index.Remove(GetContainerRange(startingIndex, count)); return base.Dematerialize(startingIndex, count); } - private void AddToIndex(object item, T container) - { - if (RootGenerator != null) - { - ((TreeItemContainerGenerator)RootGenerator).AddToIndex(item, container); - } - else - { - _itemToContainer.Add(item, container); - _containerToItem.Add(container, item); - } - } - - private void RemoveFromIndex(IEnumerable containers) - { - if (RootGenerator != null) - { - ((TreeItemContainerGenerator)RootGenerator).RemoveFromIndex(containers); - } - else - { - foreach (var container in containers) - { - var item = _containerToItem[container.ContainerControl]; - _containerToItem.Remove(container.ContainerControl); - _itemToContainer.Remove(item); - } - } - } - - private void ClearIndex() - { - if (RootGenerator != null) - { - ((TreeItemContainerGenerator)RootGenerator).ClearIndex(); - } - else - { - _containerToItem.Clear(); - _itemToContainer.Clear(); - } - } - /// /// Gets the data template for the specified item. /// diff --git a/src/Perspex.Controls/Perspex.Controls.csproj b/src/Perspex.Controls/Perspex.Controls.csproj index 0e8f07767e..c0fbb8fab3 100644 --- a/src/Perspex.Controls/Perspex.Controls.csproj +++ b/src/Perspex.Controls/Perspex.Controls.csproj @@ -46,6 +46,7 @@ + diff --git a/src/Perspex.Controls/TreeView.cs b/src/Perspex.Controls/TreeView.cs index 2dcb136526..4b7b1f986a 100644 --- a/src/Perspex.Controls/TreeView.cs +++ b/src/Perspex.Controls/TreeView.cs @@ -58,7 +58,7 @@ namespace Perspex.Controls TreeViewItem.HeaderProperty, TreeViewItem.ItemsProperty, TreeViewItem.IsExpandedProperty, - null); + new TreeContainerIndex()); } /// @@ -101,13 +101,13 @@ namespace Perspex.Controls bool rangeModifier = false, bool toggleModifier = false) { - var item = ItemContainerGenerator.TreeItemFromContainer(container); + var item = ItemContainerGenerator.Index.ItemFromContainer(container); if (item != null) { if (SelectedItem != null) { - var old = ItemContainerGenerator.TreeContainerFromItem(SelectedItem); + var old = ItemContainerGenerator.Index.ContainerFromItem(SelectedItem); MarkContainerSelected(old, false); } @@ -162,7 +162,7 @@ namespace Perspex.Controls if (item != null) { - if (item.ItemContainerGenerator.RootGenerator == this.ItemContainerGenerator) + if (item.ItemContainerGenerator.Index == this.ItemContainerGenerator.Index) { return item; } diff --git a/src/Perspex.Controls/TreeViewItem.cs b/src/Perspex.Controls/TreeViewItem.cs index da263ca951..05cafe60ab 100644 --- a/src/Perspex.Controls/TreeViewItem.cs +++ b/src/Perspex.Controls/TreeViewItem.cs @@ -79,7 +79,7 @@ namespace Perspex.Controls TreeViewItem.HeaderProperty, TreeViewItem.ItemsProperty, TreeViewItem.IsExpandedProperty, - _treeView?.ItemContainerGenerator); + _treeView?.ItemContainerGenerator.Index ?? new TreeContainerIndex()); } /// diff --git a/tests/Perspex.Controls.UnitTests/TreeViewTests.cs b/tests/Perspex.Controls.UnitTests/TreeViewTests.cs index 06337d9412..627ab0d053 100644 --- a/tests/Perspex.Controls.UnitTests/TreeViewTests.cs +++ b/tests/Perspex.Controls.UnitTests/TreeViewTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; +using Perspex.Collections; using Perspex.Controls.Presenters; using Perspex.Controls.Templates; using Perspex.Input; @@ -65,7 +66,7 @@ namespace Perspex.Controls.UnitTests ApplyTemplates(target); - var container = target.ItemContainerGenerator.TreeContainerFromItem( + var container = target.ItemContainerGenerator.Index.ContainerFromItem( tree[0].Children[1].Children[0]); Assert.NotNull(container); @@ -92,7 +93,7 @@ namespace Perspex.Controls.UnitTests ApplyTemplates(target); var item = tree[0].Children[1].Children[0]; - var container = (TreeViewItem)target.ItemContainerGenerator.TreeContainerFromItem(item); + var container = (TreeViewItem)target.ItemContainerGenerator.Index.ContainerFromItem(item); Assert.NotNull(container);