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