|
|
@@ -1,11 +1,8 @@
|
|
|
// 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.Linq;
|
|
|
-using System.Reactive.Subjects;
|
|
|
using Perspex.Controls.Templates;
|
|
|
|
|
|
namespace Perspex.Controls.Generators
|
|
|
@@ -14,161 +11,84 @@ namespace Perspex.Controls.Generators
|
|
|
/// Creates containers for tree items and maintains a list of created containers.
|
|
|
/// </summary>
|
|
|
/// <typeparam name="T">The type of the container.</typeparam>
|
|
|
- public class TreeItemContainerGenerator<T> : ITreeItemContainerGenerator where T : TreeViewItem, new()
|
|
|
+ public class TreeItemContainerGenerator<T> : ItemContainerGenerator<T>, ITreeItemContainerGenerator
|
|
|
+ where T : class, IControl, new()
|
|
|
{
|
|
|
- private Dictionary<object, T> _containers = new Dictionary<object, T>();
|
|
|
-
|
|
|
- private readonly Subject<ItemContainers> _containersInitialized = new Subject<ItemContainers>();
|
|
|
+ private Dictionary<object, T> _itemToContainer;
|
|
|
+ private Dictionary<IControl, object> _containerToItem;
|
|
|
|
|
|
/// <summary>
|
|
|
/// Initializes a new instance of the <see cref="TreeItemContainerGenerator{T}"/> class.
|
|
|
/// </summary>
|
|
|
/// <param name="owner">The owner control.</param>
|
|
|
- public TreeItemContainerGenerator(IControl owner)
|
|
|
- {
|
|
|
- Owner = owner;
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Gets the currently realized containers.
|
|
|
- /// </summary>
|
|
|
- public IEnumerable<IControl> Containers => _containers.Values;
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Signalled whenever new containers are initialized.
|
|
|
- /// </summary>
|
|
|
- public IObservable<ItemContainers> ContainersInitialized => _containersInitialized;
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Gets the owner control.
|
|
|
- /// </summary>
|
|
|
- public IControl Owner { get; }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Creates container controls for a collection of items.
|
|
|
- /// </summary>
|
|
|
- /// <param name="startingIndex">
|
|
|
- /// The index of the first item of the data in the containing collection.
|
|
|
- /// </param>
|
|
|
- /// <param name="items">The items.</param>
|
|
|
- /// <param name="selector">An optional member selector.</param>
|
|
|
- /// <returns>The created container controls.</returns>
|
|
|
- public IList<IControl> CreateContainers(
|
|
|
- int startingIndex,
|
|
|
- IEnumerable items,
|
|
|
- IMemberSelector selector)
|
|
|
- {
|
|
|
- Contract.Requires<ArgumentNullException>(items != null);
|
|
|
-
|
|
|
- int index = startingIndex;
|
|
|
- var result = new List<IControl>();
|
|
|
-
|
|
|
- foreach (var item in items)
|
|
|
- {
|
|
|
- var i = selector != null ? selector.Select(item) : item;
|
|
|
- var container = CreateContainer(i);
|
|
|
- _containers.Add(i, container);
|
|
|
- result.Add(container);
|
|
|
- }
|
|
|
-
|
|
|
- _containersInitialized.OnNext(new ItemContainers(startingIndex, result));
|
|
|
-
|
|
|
- return result.Where(x => x != null).ToList();
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Removes a set of created containers from the index and returns the removed controls.
|
|
|
- /// </summary>
|
|
|
- /// <param name="startingIndex">
|
|
|
- /// The index of the first item of the data in the containing collection.
|
|
|
+ /// <param name="contentProperty">The container's Content property.</param>
|
|
|
+ /// <param name="itemsProperty">The container's Items property.</param>
|
|
|
+ /// <param name="isExpandedProperty">The container's IsExpanded property.</param>
|
|
|
+ /// <param name="rootGenerator">
|
|
|
+ /// The item container for the root of the tree, or null if this generator is itself the
|
|
|
+ /// root of the tree.
|
|
|
/// </param>
|
|
|
- /// <param name="items">The items.</param>
|
|
|
- /// <returns>The removed controls.</returns>
|
|
|
- public IList<IControl> RemoveContainers(int startingIndex, IEnumerable items)
|
|
|
+ public TreeItemContainerGenerator(
|
|
|
+ IControl owner,
|
|
|
+ PerspexProperty contentProperty,
|
|
|
+ PerspexProperty itemsProperty,
|
|
|
+ PerspexProperty isExpandedProperty,
|
|
|
+ ITreeItemContainerGenerator rootGenerator)
|
|
|
+ : base(owner, contentProperty)
|
|
|
{
|
|
|
- var result = new List<IControl>();
|
|
|
+ ItemsProperty = itemsProperty;
|
|
|
+ IsExpandedProperty = isExpandedProperty;
|
|
|
+ RootGenerator = rootGenerator;
|
|
|
|
|
|
- foreach (var item in items)
|
|
|
+ if (rootGenerator == null)
|
|
|
{
|
|
|
- T container;
|
|
|
-
|
|
|
- if (_containers.TryGetValue(item, out container))
|
|
|
- {
|
|
|
- Remove(container, result);
|
|
|
- }
|
|
|
+ _itemToContainer = new Dictionary<object, T>();
|
|
|
+ _containerToItem = new Dictionary<IControl, object>();
|
|
|
}
|
|
|
-
|
|
|
- return result;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
- /// Clears the created containers from the index and returns the removed controls.
|
|
|
+ /// Gets the item container for the root of the tree, or null if this generator is itself
|
|
|
+ /// the root of the tree.
|
|
|
/// </summary>
|
|
|
- /// <returns>The removed controls.</returns>
|
|
|
- public IList<IControl> ClearContainers()
|
|
|
- {
|
|
|
- var result = _containers;
|
|
|
- _containers = new Dictionary<object, T>();
|
|
|
- return result.Values.Cast<IControl>().ToList();
|
|
|
- }
|
|
|
+ public ITreeItemContainerGenerator RootGenerator { get; }
|
|
|
|
|
|
/// <summary>
|
|
|
- /// Gets the container control representing the item with the specified index.
|
|
|
+ /// Gets the item container's Items property.
|
|
|
/// </summary>
|
|
|
- /// <param name="index">The index.</param>
|
|
|
- /// <returns>The container or null if no container created.</returns>
|
|
|
- public IControl ContainerFromIndex(int index)
|
|
|
- {
|
|
|
- throw new NotImplementedException();
|
|
|
- }
|
|
|
+ protected PerspexProperty ItemsProperty { get; }
|
|
|
|
|
|
/// <summary>
|
|
|
- /// Gets the index of the specified container control.
|
|
|
+ /// Gets the item container's IsExpanded property.
|
|
|
/// </summary>
|
|
|
- /// <param name="container">The container.</param>
|
|
|
- /// <returns>The index of the container or -1 if not found.</returns>
|
|
|
- public int IndexFromContainer(IControl container)
|
|
|
- {
|
|
|
- throw new NotImplementedException();
|
|
|
- }
|
|
|
+ protected PerspexProperty IsExpandedProperty { get; }
|
|
|
|
|
|
/// <summary>
|
|
|
- /// Gets all of the generated container controls.
|
|
|
+ /// Gets the item container for the specified item, anywhere in the tree.
|
|
|
/// </summary>
|
|
|
- /// <returns>The containers.</returns>
|
|
|
- public IEnumerable<IControl> GetAllContainers()
|
|
|
+ /// <param name="item">The item.</param>
|
|
|
+ /// <returns>The container, or null if not found.</returns>
|
|
|
+ public IControl TreeContainerFromItem(object item)
|
|
|
{
|
|
|
- return _containers.Values;
|
|
|
+ T result;
|
|
|
+ _itemToContainer.TryGetValue(item, out result);
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
- /// Gets the item that is contained by the specified container.
|
|
|
+ /// Gets the item for the specified item container, anywhere in the tree.
|
|
|
/// </summary>
|
|
|
/// <param name="container">The container.</param>
|
|
|
- /// <returns>The item.</returns>
|
|
|
- public object ItemFromContainer(IControl container)
|
|
|
- {
|
|
|
- return container.DataContext;
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Gets the container for the specified item
|
|
|
- /// </summary>
|
|
|
- /// <param name="item">The item.</param>
|
|
|
- /// <returns>The container.</returns>
|
|
|
- public IControl ContainerFromItem(object item)
|
|
|
+ /// <returns>The item, or null if not found.</returns>
|
|
|
+ public object TreeItemFromContainer(IControl container)
|
|
|
{
|
|
|
- T result;
|
|
|
- _containers.TryGetValue(item, out result);
|
|
|
+ object result;
|
|
|
+ _containerToItem.TryGetValue(container, out result);
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
- /// <summary>
|
|
|
- /// Creates the container for an item.
|
|
|
- /// </summary>
|
|
|
- /// <param name="item">The item.</param>
|
|
|
- /// <returns>The created container control.</returns>
|
|
|
- protected virtual T CreateContainer(object item)
|
|
|
+ /// <inheritdoc/>
|
|
|
+ protected override IControl CreateContainer(object item)
|
|
|
{
|
|
|
var container = item as T;
|
|
|
|
|
|
@@ -183,22 +103,78 @@ namespace Perspex.Controls.Generators
|
|
|
else
|
|
|
{
|
|
|
var template = GetTreeDataTemplate(item);
|
|
|
- var result = new T
|
|
|
- {
|
|
|
- Header = template.Build(item),
|
|
|
- Items = template.ItemsSelector(item),
|
|
|
- IsExpanded = template.IsExpanded(item),
|
|
|
- };
|
|
|
+ var result = new T();
|
|
|
+
|
|
|
+ result.SetValue(ContentProperty, template.Build(item));
|
|
|
+ result.SetValue(ItemsProperty, template.ItemsSelector(item));
|
|
|
+ result.SetValue(IsExpandedProperty, template.IsExpanded(item));
|
|
|
|
|
|
if (!(item is IControl))
|
|
|
{
|
|
|
result.DataContext = item;
|
|
|
}
|
|
|
|
|
|
+ AddToIndex(item, result);
|
|
|
+
|
|
|
return result;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ public override IEnumerable<IControl> Clear()
|
|
|
+ {
|
|
|
+ ClearIndex();
|
|
|
+ return base.Clear();
|
|
|
+ }
|
|
|
+
|
|
|
+ public override IEnumerable<IControl> Dematerialize(int startingIndex, int count)
|
|
|
+ {
|
|
|
+ RemoveFromIndex(GetContainerRange(startingIndex, count));
|
|
|
+ return base.Dematerialize(startingIndex, count);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void AddToIndex(object item, T container)
|
|
|
+ {
|
|
|
+ if (RootGenerator != null)
|
|
|
+ {
|
|
|
+ ((TreeItemContainerGenerator<T>)RootGenerator).AddToIndex(item, container);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ _itemToContainer.Add(item, container);
|
|
|
+ _containerToItem.Add(container, item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void RemoveFromIndex(IEnumerable<IControl> containers)
|
|
|
+ {
|
|
|
+ if (RootGenerator != null)
|
|
|
+ {
|
|
|
+ ((TreeItemContainerGenerator<T>)RootGenerator).RemoveFromIndex(containers);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ foreach (var container in containers)
|
|
|
+ {
|
|
|
+ var item = _containerToItem[container];
|
|
|
+ _containerToItem.Remove(container);
|
|
|
+ _itemToContainer.Remove(item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void ClearIndex()
|
|
|
+ {
|
|
|
+ if (RootGenerator != null)
|
|
|
+ {
|
|
|
+ ((TreeItemContainerGenerator<T>)RootGenerator).ClearIndex();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ _containerToItem.Clear();
|
|
|
+ _itemToContainer.Clear();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/// <summary>
|
|
|
/// Gets the data template for the specified item.
|
|
|
/// </summary>
|
|
|
@@ -222,29 +198,5 @@ namespace Perspex.Controls.Generators
|
|
|
|
|
|
return treeTemplate;
|
|
|
}
|
|
|
-
|
|
|
- private void Remove(T container, IList<IControl> removed)
|
|
|
- {
|
|
|
- if (container.Items != null)
|
|
|
- {
|
|
|
- foreach (var childItem in container.Items)
|
|
|
- {
|
|
|
- T childContainer;
|
|
|
-
|
|
|
- if (_containers.TryGetValue(childItem, out childContainer))
|
|
|
- {
|
|
|
- Remove(childContainer, removed);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // TODO: Dual index.
|
|
|
- var i = _containers.FirstOrDefault(x => x.Value == container);
|
|
|
-
|
|
|
- if (i.Key != null)
|
|
|
- {
|
|
|
- _containers.Remove(i.Key);
|
|
|
- }
|
|
|
- }
|
|
|
}
|
|
|
}
|