// 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; using System.Collections.Generic; using Perspex.Controls.Templates; namespace Perspex.Controls.Generators { /// /// Creates containers for tree items and maintains a list of created containers. /// /// The type of the container. public class TreeItemContainerGenerator : ItemContainerGenerator, ITreeItemContainerGenerator where T : class, IControl, new() { private Dictionary _itemToContainer; private Dictionary _containerToItem; /// /// Initializes a new instance of the class. /// /// The owner control. /// 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. /// public TreeItemContainerGenerator( IControl owner, PerspexProperty contentProperty, PerspexProperty itemsProperty, PerspexProperty isExpandedProperty, ITreeItemContainerGenerator rootGenerator) : base(owner, contentProperty) { ItemsProperty = itemsProperty; IsExpandedProperty = isExpandedProperty; RootGenerator = rootGenerator; if (rootGenerator == null) { _itemToContainer = new Dictionary(); _containerToItem = new Dictionary(); } } /// /// Gets the item container for the root of the tree, or null if this generator is itself /// the root of the tree. /// public ITreeItemContainerGenerator RootGenerator { get; } /// /// Gets the item container's Items property. /// protected PerspexProperty ItemsProperty { get; } /// /// Gets the item container's IsExpanded property. /// 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) { var container = item as T; if (item == null) { return null; } else if (container != null) { return container; } else { var template = GetTreeDataTemplate(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 IList ClearContainers() { ClearIndex(); return base.ClearContainers(); } public override IList RemoveContainers(int startingIndex, int count) { RemoveFromIndex(GetContainerRange(startingIndex, count)); return base.RemoveContainers(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]; _containerToItem.Remove(container); _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. /// /// The item. /// The template. private ITreeDataTemplate GetTreeDataTemplate(object item) { IDataTemplate template = Owner.FindDataTemplate(item); if (template == null) { template = FuncDataTemplate.Default; } var treeTemplate = template as ITreeDataTemplate; if (treeTemplate == null) { treeTemplate = new FuncTreeDataTemplate(typeof(object), template.Build, x => null); } return treeTemplate; } } }