namespace Caliburn.Micro.Core { using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Linq; public partial class Conductor { /// /// An implementation of that holds on many items. /// public partial class Collection { /// /// An implementation of that holds on many items but only activates one at a time. /// public class OneActive : ConductorBaseWithActiveItem { readonly BindableCollection items = new BindableCollection(); /// /// Initializes a new instance of the class. /// public OneActive() { items.CollectionChanged += (s, e) => { switch(e.Action) { case NotifyCollectionChangedAction.Add: e.NewItems.OfType().Apply(x => x.Parent = this); break; case NotifyCollectionChangedAction.Remove: e.OldItems.OfType().Apply(x => x.Parent = null); break; case NotifyCollectionChangedAction.Replace: e.NewItems.OfType().Apply(x => x.Parent = this); e.OldItems.OfType().Apply(x => x.Parent = null); break; case NotifyCollectionChangedAction.Reset: items.OfType().Apply(x => x.Parent = this); break; } }; } /// /// Gets the items that are currently being conducted. /// public IObservableCollection Items { get { return items; } } /// /// Gets the children. /// /// The collection of children. public override IEnumerable GetChildren() { return items; } /// /// Activates the specified item. /// /// The item to activate. public override void ActivateItem(T item) { if(item != null && item.Equals(ActiveItem)) { if (IsActive) { ScreenExtensions.TryActivate(item); OnActivationProcessed(item, true); } return; } ChangeActiveItem(item, false); } /// /// Deactivates the specified item. /// /// The item to close. /// Indicates whether or not to close the item after deactivating it. public override void DeactivateItem(T item, bool close) { if (item == null) { return; } if (!close) { ScreenExtensions.TryDeactivate(item, false); } else { CloseStrategy.Execute(new[] { item }, (canClose, closable) => { if (canClose) { CloseItemCore(item); } }); } } void CloseItemCore(T item) { if(item.Equals(ActiveItem)) { var index = items.IndexOf(item); var next = DetermineNextItemToActivate(items, index); ChangeActiveItem(next, true); } else { ScreenExtensions.TryDeactivate(item, true); } items.Remove(item); } /// /// Determines the next item to activate based on the last active index. /// /// The list of possible active items. /// The index of the last active item. /// The next item to activate. /// Called after an active item is closed. protected virtual T DetermineNextItemToActivate(IList list, int lastIndex) { var toRemoveAt = lastIndex - 1; if (toRemoveAt == -1 && list.Count > 1) { return list[1]; } if (toRemoveAt > -1 && toRemoveAt < list.Count - 1) { return list[toRemoveAt]; } return default(T); } /// /// Called to check whether or not this instance can close. /// /// The implementor calls this action with the result of the close check. public override void CanClose(Action callback) { CloseStrategy.Execute(items.ToList(), (canClose, closable) => { if(!canClose && closable.Any()) { if(closable.Contains(ActiveItem)) { var list = items.ToList(); var next = ActiveItem; do { var previous = next; next = DetermineNextItemToActivate(list, list.IndexOf(previous)); list.Remove(previous); } while(closable.Contains(next)); var previousActive = ActiveItem; ChangeActiveItem(next, true); items.Remove(previousActive); var stillToClose = closable.ToList(); stillToClose.Remove(previousActive); closable = stillToClose; } closable.OfType().Apply(x => x.Deactivate(true)); items.RemoveRange(closable); } callback(canClose); }); } /// /// Called when activating. /// protected override void OnActivate() { ScreenExtensions.TryActivate(ActiveItem); } /// /// Called when deactivating. /// /// Inidicates whether this instance will be closed. protected override void OnDeactivate(bool close) { if (close) { items.OfType().Apply(x => x.Deactivate(true)); items.Clear(); } else { ScreenExtensions.TryDeactivate(ActiveItem, false); } } /// /// Ensures that an item is ready to be activated. /// /// The item that is about to be activated. /// The item to be activated. protected override T EnsureItem(T newItem) { if (newItem == null) { newItem = DetermineNextItemToActivate(items, ActiveItem != null ? items.IndexOf(ActiveItem) : 0); } else { var index = items.IndexOf(newItem); if (index == -1) items.Add(newItem); else newItem = items[index]; } return base.EnsureItem(newItem); } public void ClearItems() { items.Clear(); ChangeActiveItem(null, true); } } } } }