| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277 |
- namespace Terminal.Gui.ViewBase;
- /// <summary>
- /// Base implementation of <see cref="IRunnable"/> for views that can be run as sessions.
- /// </summary>
- /// <remarks>
- /// <para>
- /// Views can derive from this class or implement <see cref="IRunnable"/> directly.
- /// This base class provides a complete reference implementation of the <see cref="IRunnable"/>
- /// interface following Terminal.Gui's Cancellable Work Pattern.
- /// </para>
- /// <para>
- /// To customize lifecycle behavior, override the protected virtual methods:
- /// <see cref="OnStopping"/>, <see cref="OnStopped"/>, <see cref="OnActivating"/>,
- /// <see cref="OnActivated"/>, <see cref="OnDeactivating"/>, <see cref="OnDeactivated"/>.
- /// </para>
- /// </remarks>
- public class Runnable : View, IRunnable
- {
- /// <inheritdoc/>
- public bool Running { get; set; }
- #region IRunnable Implementation (RaiseXxxEvent Methods)
- /// <inheritdoc/>
- public virtual void RaiseStoppingEvent ()
- {
- // CWP Phase 1: Pre-notification via virtual method (can cancel)
- if (OnStopping ())
- {
- return; // Stopping canceled
- }
- // CWP Phase 2: Event notification (can cancel)
- var args = new System.ComponentModel.CancelEventArgs ();
- Stopping?.Invoke (this, args);
- if (args.Cancel)
- {
- return; // Stopping canceled
- }
- // CWP Phase 3: Perform the work (stop the session)
- Running = false;
- // CWP Phase 4: Post-notification via virtual method
- OnStopped ();
- // CWP Phase 5: Post-notification event
- Stopped?.Invoke (this, EventArgs.Empty);
- }
- /// <inheritdoc/>
- public virtual bool RaiseActivatingEvent (IRunnable? deactivated)
- {
- // CWP Phase 1: Pre-notification via virtual method (can cancel)
- if (OnActivating (deactivated))
- {
- return true; // Activation canceled
- }
- // CWP Phase 2: Event notification (can cancel)
- var args = new RunnableActivatingEventArgs (this, deactivated);
- Activating?.Invoke (this, args);
- if (args.Cancel)
- {
- return true; // Activation canceled
- }
- // CWP Phase 3: Work is done by Application (setting Current)
- // CWP Phase 4 & 5: Call post-notification methods
- OnActivated (deactivated);
- return false; // Activation succeeded
- }
- /// <inheritdoc/>
- public virtual void RaiseActivatedEvent (IRunnable? deactivated)
- {
- Activated?.Invoke (this, new RunnableEventArgs (this));
- }
- /// <inheritdoc/>
- public virtual bool RaiseDeactivatingEvent (IRunnable? activated)
- {
- // CWP Phase 1: Pre-notification via virtual method (can cancel)
- if (OnDeactivating (activated))
- {
- return true; // Deactivation canceled
- }
- // CWP Phase 2: Event notification (can cancel)
- var args = new RunnableDeactivatingEventArgs (this, activated);
- Deactivating?.Invoke (this, args);
- if (args.Cancel)
- {
- return true; // Deactivation canceled
- }
- // CWP Phase 3: Work is done by Application (changing Current)
- // CWP Phase 4 & 5: Call post-notification methods
- OnDeactivated (activated);
- return false; // Deactivation succeeded
- }
- /// <inheritdoc/>
- public virtual void RaiseDeactivatedEvent (IRunnable? activated)
- {
- Deactivated?.Invoke (this, new RunnableEventArgs (this));
- }
- #endregion
- #region Protected Virtual Methods (Override Pattern)
- /// <summary>
- /// Called before <see cref="Stopping"/> event. Override to cancel stopping.
- /// </summary>
- /// <returns><see langword="true"/> to cancel; <see langword="false"/> to proceed.</returns>
- /// <remarks>
- /// <para>
- /// This is the first phase of the Cancellable Work Pattern for stopping.
- /// Default implementation returns <see langword="false"/> (allow stopping).
- /// </para>
- /// <para>
- /// Override this method to provide custom logic for determining whether the runnable
- /// should stop (e.g., prompting the user to save changes).
- /// </para>
- /// </remarks>
- protected virtual bool OnStopping ()
- {
- return false; // Default: allow stopping
- }
- /// <summary>
- /// Called after session has stopped. Override for post-stop cleanup.
- /// </summary>
- /// <remarks>
- /// <para>
- /// This is the fourth phase of the Cancellable Work Pattern for stopping.
- /// At this point, <see cref="Running"/> is <see langword="false"/>.
- /// Default implementation does nothing.
- /// </para>
- /// <para>
- /// Override this method to perform cleanup work that should occur after the session stops.
- /// </para>
- /// </remarks>
- protected virtual void OnStopped ()
- {
- // Default: do nothing
- }
- /// <summary>
- /// Called before <see cref="Activating"/> event. Override to cancel activation.
- /// </summary>
- /// <param name="deactivated">The previously active runnable being deactivated, or null if none.</param>
- /// <returns><see langword="true"/> to cancel; <see langword="false"/> to proceed.</returns>
- /// <remarks>
- /// <para>
- /// This is the first phase of the Cancellable Work Pattern for activation.
- /// Default implementation returns <see langword="false"/> (allow activation).
- /// </para>
- /// <para>
- /// Override this method to provide custom logic for determining whether the runnable
- /// should become active.
- /// </para>
- /// </remarks>
- protected virtual bool OnActivating (IRunnable? deactivated)
- {
- return false; // Default: allow activation
- }
- /// <summary>
- /// Called after activation succeeds. Override for post-activation logic.
- /// </summary>
- /// <param name="deactivated">The previously active runnable that was deactivated, or null if none.</param>
- /// <remarks>
- /// <para>
- /// This is the fourth phase of the Cancellable Work Pattern for activation.
- /// Default implementation calls <see cref="RaiseActivatedEvent"/>.
- /// </para>
- /// <para>
- /// Override this method to perform work that should occur after activation
- /// (e.g., setting focus, updating UI). Overrides must call base to ensure the
- /// <see cref="Activated"/> event is raised.
- /// </para>
- /// </remarks>
- protected virtual void OnActivated (IRunnable? deactivated)
- {
- RaiseActivatedEvent (deactivated);
- }
- /// <summary>
- /// Called before <see cref="Deactivating"/> event. Override to cancel deactivation.
- /// </summary>
- /// <param name="activated">The newly activated runnable, or null if none.</param>
- /// <returns><see langword="true"/> to cancel; <see langword="false"/> to proceed.</returns>
- /// <remarks>
- /// <para>
- /// This is the first phase of the Cancellable Work Pattern for deactivation.
- /// Default implementation returns <see langword="false"/> (allow deactivation).
- /// </para>
- /// <para>
- /// Override this method to provide custom logic for determining whether the runnable
- /// should be deactivated (e.g., preventing switching away if unsaved changes exist).
- /// </para>
- /// </remarks>
- protected virtual bool OnDeactivating (IRunnable? activated)
- {
- return false; // Default: allow deactivation
- }
- /// <summary>
- /// Called after deactivation succeeds. Override for post-deactivation logic.
- /// </summary>
- /// <param name="activated">The newly activated runnable, or null if none.</param>
- /// <remarks>
- /// <para>
- /// This is the fourth phase of the Cancellable Work Pattern for deactivation.
- /// Default implementation calls <see cref="RaiseDeactivatedEvent"/>.
- /// </para>
- /// <para>
- /// Override this method to perform work that should occur after deactivation
- /// (e.g., saving state, releasing resources). Overrides must call base to ensure the
- /// <see cref="Deactivated"/> event is raised.
- /// </para>
- /// </remarks>
- protected virtual void OnDeactivated (IRunnable? activated)
- {
- RaiseDeactivatedEvent (activated);
- }
- #endregion
- #region Events
- // Note: Initializing and Initialized events are inherited from View (ISupportInitialize pattern)
- /// <inheritdoc/>
- public event EventHandler<System.ComponentModel.CancelEventArgs>? Stopping;
- /// <inheritdoc/>
- public event EventHandler? Stopped;
- /// <inheritdoc/>
- public event EventHandler<RunnableActivatingEventArgs>? Activating;
- /// <inheritdoc/>
- public event EventHandler<RunnableEventArgs>? Activated;
- /// <inheritdoc/>
- public event EventHandler<RunnableDeactivatingEventArgs>? Deactivating;
- /// <inheritdoc/>
- public event EventHandler<RunnableEventArgs>? Deactivated;
- #endregion
- /// <summary>
- /// Stops and closes this runnable session.
- /// </summary>
- /// <remarks>
- /// <para>
- /// This method calls <see cref="RaiseStoppingEvent"/> to initiate the stopping process.
- /// The Application infrastructure will update this once IApplication supports IRunnable directly.
- /// </para>
- /// </remarks>
- public virtual void RequestStop ()
- {
- // TODO: Phase 3 - Update Application.RequestStop to accept IRunnable
- // For now, directly call RaiseStoppingEvent which follows CWP
- RaiseStoppingEvent ();
- }
- }
|