DefaultCloseStrategy.cs 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. namespace Caliburn.Micro.Core {
  2. using System;
  3. using System.Collections.Generic;
  4. /// <summary>
  5. /// Used to gather the results from multiple child elements which may or may not prevent closing.
  6. /// </summary>
  7. /// <typeparam name="T">The type of child element.</typeparam>
  8. public class DefaultCloseStrategy<T> : ICloseStrategy<T> {
  9. readonly bool closeConductedItemsWhenConductorCannotClose;
  10. /// <summary>
  11. /// Creates an instance of the class.
  12. /// </summary>
  13. /// <param name="closeConductedItemsWhenConductorCannotClose">Indicates that even if all conducted items are not closable, those that are should be closed. The default is FALSE.</param>
  14. public DefaultCloseStrategy(bool closeConductedItemsWhenConductorCannotClose = false) {
  15. this.closeConductedItemsWhenConductorCannotClose = closeConductedItemsWhenConductorCannotClose;
  16. }
  17. /// <summary>
  18. /// Executes the strategy.
  19. /// </summary>
  20. /// <param name="toClose">Items that are requesting close.</param>
  21. /// <param name="callback">The action to call when all enumeration is complete and the close results are aggregated.
  22. /// The bool indicates whether close can occur. The enumerable indicates which children should close if the parent cannot.</param>
  23. public void Execute(IEnumerable<T> toClose, Action<bool, IEnumerable<T>> callback) {
  24. using (var enumerator = toClose.GetEnumerator()) {
  25. Evaluate(new EvaluationState(), enumerator, callback);
  26. }
  27. }
  28. void Evaluate(EvaluationState state, IEnumerator<T> enumerator, Action<bool, IEnumerable<T>> callback) {
  29. var guardPending = false;
  30. do {
  31. if (!enumerator.MoveNext()) {
  32. callback(state.FinalResult, closeConductedItemsWhenConductorCannotClose ? state.Closable : new List<T>());
  33. break;
  34. }
  35. var current = enumerator.Current;
  36. var guard = current as IGuardClose;
  37. if (guard != null) {
  38. guardPending = true;
  39. guard.CanClose(canClose => {
  40. guardPending = false;
  41. if (canClose) {
  42. state.Closable.Add(current);
  43. }
  44. state.FinalResult = state.FinalResult && canClose;
  45. if (state.GuardMustCallEvaluate) {
  46. state.GuardMustCallEvaluate = false;
  47. Evaluate(state, enumerator, callback);
  48. }
  49. });
  50. state.GuardMustCallEvaluate = state.GuardMustCallEvaluate || guardPending;
  51. } else {
  52. state.Closable.Add(current);
  53. }
  54. } while (!guardPending);
  55. }
  56. class EvaluationState {
  57. public readonly List<T> Closable = new List<T>();
  58. public bool FinalResult = true;
  59. public bool GuardMustCallEvaluate;
  60. }
  61. }
  62. }