| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 | namespace Caliburn.Micro.Core {    using System;    using System.Collections.Generic;    using System.Collections.Specialized;    using System.Linq;    public partial class Conductor<T> {        /// <summary>        /// An implementation of <see cref="IConductor"/> that holds on many items.        /// </summary>        public partial class Collection {            /// <summary>            /// An implementation of <see cref="IConductor"/> that holds on many items but only activates one at a time.            /// </summary>            public class OneActive : ConductorBaseWithActiveItem<T> {                readonly BindableCollection<T> items = new BindableCollection<T>();                /// <summary>                /// Initializes a new instance of the <see cref="Conductor<T>.Collection.OneActive"/> class.                /// </summary>                public OneActive() {                    items.CollectionChanged += (s, e) => {                        switch(e.Action) {                            case NotifyCollectionChangedAction.Add:                                e.NewItems.OfType<IChild>().Apply(x => x.Parent = this);                                break;                            case NotifyCollectionChangedAction.Remove:                                e.OldItems.OfType<IChild>().Apply(x => x.Parent = null);                                break;                            case NotifyCollectionChangedAction.Replace:                                e.NewItems.OfType<IChild>().Apply(x => x.Parent = this);                                e.OldItems.OfType<IChild>().Apply(x => x.Parent = null);                                break;                            case NotifyCollectionChangedAction.Reset:                                items.OfType<IChild>().Apply(x => x.Parent = this);                                break;                        }                    };                }                /// <summary>                /// Gets the items that are currently being conducted.                /// </summary>                public IObservableCollection<T> Items {                    get { return items; }                }                /// <summary>                /// Gets the children.                /// </summary>                /// <returns>The collection of children.</returns>                public override IEnumerable<T> GetChildren() {                    return items;                }                /// <summary>                /// Activates the specified item.                /// </summary>                /// <param name="item">The item to activate.</param>                public override void ActivateItem(T item) {                    if(item != null && item.Equals(ActiveItem)) {                        if (IsActive) {                            ScreenExtensions.TryActivate(item);                            OnActivationProcessed(item, true);                        }                        return;                    }                    ChangeActiveItem(item, false);                }                /// <summary>                /// Deactivates the specified item.                /// </summary>                /// <param name="item">The item to close.</param>                /// <param name="close">Indicates whether or not to close the item after deactivating it.</param>                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);                }                /// <summary>                /// Determines the next item to activate based on the last active index.                /// </summary>                /// <param name="list">The list of possible active items.</param>                /// <param name="lastIndex">The index of the last active item.</param>                /// <returns>The next item to activate.</returns>                /// <remarks>Called after an active item is closed.</remarks>                protected virtual T DetermineNextItemToActivate(IList<T> 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);                }                /// <summary>                /// Called to check whether or not this instance can close.                /// </summary>                /// <param name="callback">The implementor calls this action with the result of the close check.</param>                public override void CanClose(Action<bool> 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<IDeactivate>().Apply(x => x.Deactivate(true));                            items.RemoveRange(closable);                        }                        callback(canClose);                    });                }                /// <summary>                /// Called when activating.                /// </summary>                protected override void OnActivate() {                    ScreenExtensions.TryActivate(ActiveItem);                }                /// <summary>                /// Called when deactivating.                /// </summary>                /// <param name="close">Inidicates whether this instance will be closed.</param>                protected override void OnDeactivate(bool close) {                    if (close) {                        items.OfType<IDeactivate>().Apply(x => x.Deactivate(true));                        items.Clear();                    }                    else {                        ScreenExtensions.TryDeactivate(ActiveItem, false);                    }                }                /// <summary>                /// Ensures that an item is ready to be activated.                /// </summary>                /// <param name="newItem">The item that is about to be activated.</param>                /// <returns>The item to be activated.</returns>                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);                }            }        }    }}
 |