mirror of https://github.com/AMT-Cheif/Stylet.git
202 lines
8.1 KiB
C#
202 lines
8.1 KiB
C#
using System.Collections.Generic;
|
|
using System.Collections.Specialized;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Stylet
|
|
{
|
|
public partial class Conductor<T>
|
|
{
|
|
public partial class Collection
|
|
{
|
|
/// <summary>
|
|
/// Conductor with many items, only one of which is active
|
|
/// </summary>
|
|
public class OneActive : ConductorBaseWithActiveItem<T>
|
|
{
|
|
private readonly BindableCollection<T> items = new BindableCollection<T>();
|
|
|
|
/// <summary>
|
|
/// Gets the tems owned by this Conductor, one of which is active
|
|
/// </summary>
|
|
public IObservableCollection<T> Items
|
|
{
|
|
get { return this.items; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initialises a new instance of the <see cref="Conductor{T}.Collection.OneActive"/> class
|
|
/// </summary>
|
|
public OneActive()
|
|
{
|
|
this.items.CollectionChanged += (o, e) =>
|
|
{
|
|
switch (e.Action)
|
|
{
|
|
case NotifyCollectionChangedAction.Add:
|
|
this.SetParentAndSetActive(e.NewItems, false);
|
|
break;
|
|
|
|
case NotifyCollectionChangedAction.Remove:
|
|
this.CloseAndCleanUp(e.OldItems, this.DisposeChildren);
|
|
this.ActiveItemMayHaveBeenRemovedFromItems();
|
|
break;
|
|
|
|
case NotifyCollectionChangedAction.Replace:
|
|
this.SetParentAndSetActive(e.NewItems, false);
|
|
this.CloseAndCleanUp(e.OldItems, this.DisposeChildren);
|
|
this.ActiveItemMayHaveBeenRemovedFromItems();
|
|
break;
|
|
|
|
case NotifyCollectionChangedAction.Reset:
|
|
this.SetParentAndSetActive(this.items, false);
|
|
this.ActiveItemMayHaveBeenRemovedFromItems();
|
|
break;
|
|
}
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when the ActiveItem may have been removed from the Items collection. If it has, will change the ActiveItem to something sensible
|
|
/// </summary>
|
|
protected virtual void ActiveItemMayHaveBeenRemovedFromItems()
|
|
{
|
|
if (this.items.Contains(this.ActiveItem))
|
|
return;
|
|
|
|
this.ChangeActiveItem(this.items.FirstOrDefault(), true);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Return all items associated with this conductor
|
|
/// </summary>
|
|
/// <returns>All children associated with this conductor</returns>
|
|
public override IEnumerable<T> GetChildren()
|
|
{
|
|
return this.items;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Activate the given item and set it as the ActiveItem, deactivating the previous ActiveItem
|
|
/// </summary>
|
|
/// <param name="item">Item to deactivate</param>
|
|
public override void ActivateItem(T item)
|
|
{
|
|
if (item != null && item.Equals(this.ActiveItem))
|
|
{
|
|
if (this.IsActive)
|
|
ScreenExtensions.TryActivate(this.ActiveItem);
|
|
}
|
|
else
|
|
{
|
|
this.ChangeActiveItem(item, false);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Deactive the given item, and choose another item to set as the ActiveItem
|
|
/// </summary>
|
|
/// <param name="item">Item to deactivate</param>
|
|
public override void DeactivateItem(T item)
|
|
{
|
|
if (item == null)
|
|
return;
|
|
|
|
if (item.Equals(this.ActiveItem))
|
|
{
|
|
var nextItem = this.DetermineNextItemToActivate(item);
|
|
this.ChangeActiveItem(nextItem, false);
|
|
}
|
|
else
|
|
{
|
|
ScreenExtensions.TryDeactivate(item);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Close the given item (if and when possible, depending on IGuardClose.CanCloseAsync). This will deactive if it is the active item
|
|
/// </summary>
|
|
/// <param name="item">Item to close</param>
|
|
public override async void CloseItem(T item)
|
|
{
|
|
if (item == null || !await this.CanCloseItem(item))
|
|
return;
|
|
|
|
if (item.Equals(this.ActiveItem))
|
|
{
|
|
var nextItem = this.DetermineNextItemToActivate(item);
|
|
this.ChangeActiveItem(nextItem, true);
|
|
}
|
|
else
|
|
{
|
|
this.CloseAndCleanUp(item, this.DisposeChildren);
|
|
}
|
|
|
|
this.items.Remove(item);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Given a list of items, and and item which is going to be removed, choose a new item to be the next ActiveItem
|
|
/// </summary>
|
|
/// <param name="itemToRemove">Item to remove</param>
|
|
/// <returns>The next item to activate, or default(T) if no such item exists</returns>
|
|
protected virtual T DetermineNextItemToActivate(T itemToRemove)
|
|
{
|
|
if (itemToRemove == null)
|
|
{
|
|
return this.items.FirstOrDefault();
|
|
}
|
|
else if (this.items.Count > 1)
|
|
{
|
|
// indexOfItemBeingRemoved *can* be -1 - if the item being removed doesn't exist in the list
|
|
var indexOfItemBeingRemoved = this.items.IndexOf(itemToRemove);
|
|
|
|
if (indexOfItemBeingRemoved < 0)
|
|
return this.items[0];
|
|
else if (indexOfItemBeingRemoved == 0)
|
|
return this.items[1];
|
|
else
|
|
return this.items[indexOfItemBeingRemoved - 1];
|
|
}
|
|
else
|
|
{
|
|
return default(T);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns true if and when all children can close
|
|
/// </summary>
|
|
/// <returns>A task indicating whether this conductor can close</returns>
|
|
public override Task<bool> CanCloseAsync()
|
|
{
|
|
return this.CanAllItemsCloseAsync(this.items);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Ensures that all items are closed when this conductor is closed
|
|
/// </summary>
|
|
protected override void OnClose()
|
|
{
|
|
// We've already been deactivated by this point
|
|
foreach (var item in this.items)
|
|
this.CloseAndCleanUp(item, this.DisposeChildren);
|
|
this.items.Clear();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Ensure an item is ready to be activated
|
|
/// </summary>
|
|
/// <param name="newItem">New item to ensure</param>
|
|
protected override void EnsureItem(T newItem)
|
|
{
|
|
if (!this.items.Contains(newItem))
|
|
this.items.Add(newItem);
|
|
|
|
base.EnsureItem(newItem);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|