namespace Caliburn.Micro.Core { using System; using System.Collections.Generic; /// /// Used to gather the results from multiple child elements which may or may not prevent closing. /// /// The type of child element. public class DefaultCloseStrategy : ICloseStrategy { readonly bool closeConductedItemsWhenConductorCannotClose; /// /// Creates an instance of the class. /// /// Indicates that even if all conducted items are not closable, those that are should be closed. The default is FALSE. public DefaultCloseStrategy(bool closeConductedItemsWhenConductorCannotClose = false) { this.closeConductedItemsWhenConductorCannotClose = closeConductedItemsWhenConductorCannotClose; } /// /// Executes the strategy. /// /// Items that are requesting close. /// The action to call when all enumeration is complete and the close results are aggregated. /// The bool indicates whether close can occur. The enumerable indicates which children should close if the parent cannot. public void Execute(IEnumerable toClose, Action> callback) { using (var enumerator = toClose.GetEnumerator()) { Evaluate(new EvaluationState(), enumerator, callback); } } void Evaluate(EvaluationState state, IEnumerator enumerator, Action> callback) { var guardPending = false; do { if (!enumerator.MoveNext()) { callback(state.FinalResult, closeConductedItemsWhenConductorCannotClose ? state.Closable : new List()); break; } var current = enumerator.Current; var guard = current as IGuardClose; if (guard != null) { guardPending = true; guard.CanClose(canClose => { guardPending = false; if (canClose) { state.Closable.Add(current); } state.FinalResult = state.FinalResult && canClose; if (state.GuardMustCallEvaluate) { state.GuardMustCallEvaluate = false; Evaluate(state, enumerator, callback); } }); state.GuardMustCallEvaluate = state.GuardMustCallEvaluate || guardPending; } else { state.Closable.Add(current); } } while (!guardPending); } class EvaluationState { public readonly List Closable = new List(); public bool FinalResult = true; public bool GuardMustCallEvaluate; } } }