// ----------------------------------------------------------------------- // // Copyright 2015 MIT Licence. See licence.md for more information. // // ----------------------------------------------------------------------- namespace Perspex.Controls.Generators { using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reactive.Subjects; using Perspex.Controls.Templates; /// /// Creates containers for items and maintains a list of created containers. /// public class ItemContainerGenerator : IItemContainerGenerator { private Dictionary containers = new Dictionary(); private Subject containersInitialized = new Subject(); /// /// Initializes a new instance of the class. /// /// The owner control. public ItemContainerGenerator(IControl owner) { this.Owner = owner; } /// /// Signalled whenever new containers are initialized. /// public IObservable ContainersInitialized => this.containersInitialized; /// /// Gets the owner control. /// public IControl Owner { get; } /// /// Creates container controls for a collection of items. /// /// /// The index of the first item of the data in the containing collection. /// /// The items. /// An optional item template. /// The created container controls. public IList CreateContainers( int startingIndex, IEnumerable items, IDataTemplate itemTemplate) { Contract.Requires(items != null); int index = startingIndex; var result = new List(); foreach (var item in items) { IControl container = this.CreateContainer(item, itemTemplate); result.Add(container); } this.AddContainers(startingIndex, result); this.containersInitialized.OnNext(new ItemContainers(startingIndex, result)); return result.Where(x => x != null).ToList(); } /// /// Removes a set of created containers from the index and returns the removed controls. /// /// /// The index of the first item of the data in the containing collection. /// /// The items. /// The removed controls. public IList RemoveContainers(int startingIndex, IEnumerable items) { var result = new List(); var count = items.Cast().Count(); for (int i = startingIndex; i < startingIndex + count; ++i) { var container = this.containers[i]; if (container != null) { result.Add(container); this.containers.Remove(i); } } return result; } /// /// Clears the created containers from the index and returns the removed controls. /// /// The removed controls. public IList ClearContainers() { var result = this.containers; this.containers = new Dictionary(); return result.Values.ToList(); } /// /// Gets the container control representing the item with the specified index. /// /// The index. /// The container or null if no container created. public IControl ContainerFromIndex(int index) { IControl result; this.containers.TryGetValue(index, out result); return result; } /// /// Gets the index of the specified container control. /// /// The container. /// The index of the container or -1 if not found. public int IndexFromContainer(IControl container) { foreach (var i in this.containers) { if (i.Value == container) { return i.Key; } } return -1; } /// /// Creates the container for an item. /// /// The item. /// An optional item template. /// The created container control. protected virtual IControl CreateContainer(object item, IDataTemplate itemTemplate) { if (item == null) { return null; } else if (itemTemplate != null && itemTemplate.Match(item)) { var result = itemTemplate.Build(item); result.DataContext = item; return result; } else { return this.Owner.MaterializeDataTemplate(item); } } /// /// Adds a collection of containers to the index. /// /// The starting index. /// The container. protected void AddContainers(int index, IList container) { Contract.Requires(container != null); foreach (var c in container) { if (!this.containers.ContainsKey(index)) { this.containers[index] = c; } else { throw new InvalidOperationException("Container already created."); } ++index; } } } }