mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 07:47:54 +01:00
Simplify IRunnable: Rename Activating→Starting, remove Toplevel complexity
Co-authored-by: tig <585482+tig@users.noreply.github.com>
This commit is contained in:
@@ -17,7 +17,7 @@ namespace Terminal.Gui.App;
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// This interface follows the Terminal.Gui Cancellable Work Pattern (CWP) for lifecycle events
|
||||
/// where cancellation makes sense (Stopping, Activating, Deactivating).
|
||||
/// where cancellation makes sense (Stopping, Starting).
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public interface IRunnable
|
||||
@@ -53,60 +53,30 @@ public interface IRunnable
|
||||
void RaiseStoppingEvent ();
|
||||
|
||||
/// <summary>
|
||||
/// Raises the <see cref="Activating"/> event.
|
||||
/// Called by <see cref="IApplication.Begin"/> when this runnable is becoming the active session.
|
||||
/// Raises the <see cref="Starting"/> event.
|
||||
/// Called by <see cref="IApplication.Begin"/> or <see cref="IApplication.Run"/> when this runnable session is starting.
|
||||
/// </summary>
|
||||
/// <param name="deactivated">The previously active runnable being deactivated, or null if none.</param>
|
||||
/// <returns><see langword="true"/> if activation was canceled; otherwise <see langword="false"/>.</returns>
|
||||
/// <returns><see langword="true"/> if starting was canceled; otherwise <see langword="false"/>.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This method implements the Cancellable Work Pattern for activation:
|
||||
/// This method implements the Cancellable Work Pattern for starting:
|
||||
/// 1. Calls virtual method (can cancel)
|
||||
/// 2. Raises <see cref="Activating"/> event (can cancel)
|
||||
/// 2. Raises <see cref="Starting"/> event (can cancel)
|
||||
/// 3. If canceled, returns true
|
||||
/// 4. If not canceled, calls <see cref="RaiseActivatedEvent"/> and returns false
|
||||
/// 4. If not canceled, calls <see cref="RaiseStartedEvent"/> and returns false
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
bool RaiseActivatingEvent (IRunnable? deactivated);
|
||||
bool RaiseStartingEvent ();
|
||||
|
||||
/// <summary>
|
||||
/// Raises the <see cref="Activated"/> event.
|
||||
/// Called by <see cref="RaiseActivatingEvent"/> after activation succeeds.
|
||||
/// Raises the <see cref="Started"/> event.
|
||||
/// Called by <see cref="RaiseStartingEvent"/> after starting succeeds.
|
||||
/// </summary>
|
||||
/// <param name="deactivated">The previously active runnable that was deactivated, or null if none.</param>
|
||||
/// <remarks>
|
||||
/// This is the post-notification phase of activation. Implementations should raise the
|
||||
/// <see cref="Activated"/> event.
|
||||
/// This is the post-notification phase of starting. Implementations should raise the
|
||||
/// <see cref="Started"/> event.
|
||||
/// </remarks>
|
||||
void RaiseActivatedEvent (IRunnable? deactivated);
|
||||
|
||||
/// <summary>
|
||||
/// Raises the <see cref="Deactivating"/> event.
|
||||
/// Called by <see cref="IApplication.Begin"/> when switching to a new runnable.
|
||||
/// </summary>
|
||||
/// <param name="activated">The newly activated runnable, or null if none.</param>
|
||||
/// <returns><see langword="true"/> if deactivation was canceled; otherwise <see langword="false"/>.</returns>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This method implements the Cancellable Work Pattern for deactivation:
|
||||
/// 1. Calls virtual method (can cancel)
|
||||
/// 2. Raises <see cref="Deactivating"/> event (can cancel)
|
||||
/// 3. If canceled, returns true
|
||||
/// 4. If not canceled, calls <see cref="RaiseDeactivatedEvent"/> and returns false
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
bool RaiseDeactivatingEvent (IRunnable? activated);
|
||||
|
||||
/// <summary>
|
||||
/// Raises the <see cref="Deactivated"/> event.
|
||||
/// Called by <see cref="RaiseDeactivatingEvent"/> after deactivation succeeds.
|
||||
/// </summary>
|
||||
/// <param name="activated">The newly activated runnable, or null if none.</param>
|
||||
/// <remarks>
|
||||
/// This is the post-notification phase of deactivation. Implementations should raise the
|
||||
/// <see cref="Deactivated"/> event.
|
||||
/// </remarks>
|
||||
void RaiseDeactivatedEvent (IRunnable? activated);
|
||||
void RaiseStartedEvent ();
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -162,40 +132,24 @@ public interface IRunnable
|
||||
event EventHandler? Stopped;
|
||||
|
||||
/// <summary>
|
||||
/// Raised when the runnable session is about to become active (the current session).
|
||||
/// Can be canceled by setting <see cref="RunnableActivatingEventArgs.Cancel"/> to <see langword="true"/>.
|
||||
/// Raised when the runnable session is about to start running.
|
||||
/// Can be canceled by setting <see cref="System.ComponentModel.CancelEventArgs.Cancel"/> to <see langword="true"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Subscribe to this event to prevent activation or to perform pre-activation work.
|
||||
/// Subscribe to this event to prevent starting or to perform pre-start work.
|
||||
/// This aligns with <see cref="Running"/> and <see cref="IApplication.Run"/>.
|
||||
/// </remarks>
|
||||
event EventHandler<RunnableActivatingEventArgs>? Activating;
|
||||
event EventHandler<System.ComponentModel.CancelEventArgs>? Starting;
|
||||
|
||||
/// <summary>
|
||||
/// Raised when the runnable session has become active.
|
||||
/// Raised when the runnable session has started running.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the post-notification event in the Cancellable Work Pattern pair with <see cref="Activating"/>.
|
||||
/// Subscribe to this event for post-activation logic (e.g., setting focus).
|
||||
/// This is the post-notification event in the Cancellable Work Pattern pair with <see cref="Starting"/>.
|
||||
/// Subscribe to this event for post-start logic (e.g., setting focus).
|
||||
/// This aligns with <see cref="Running"/> and <see cref="IApplication.Run"/>.
|
||||
/// </remarks>
|
||||
event EventHandler<RunnableEventArgs>? Activated;
|
||||
|
||||
/// <summary>
|
||||
/// Raised when the runnable session is about to cease being active (another session is activating).
|
||||
/// Can be canceled by setting <see cref="RunnableDeactivatingEventArgs.Cancel"/> to <see langword="true"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Subscribe to this event to prevent deactivation or to perform pre-deactivation work.
|
||||
/// </remarks>
|
||||
event EventHandler<RunnableDeactivatingEventArgs>? Deactivating;
|
||||
|
||||
/// <summary>
|
||||
/// Raised when the runnable session has ceased being active.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is the post-notification event in the Cancellable Work Pattern pair with <see cref="Deactivating"/>.
|
||||
/// Subscribe to this event for cleanup or state preservation after deactivation.
|
||||
/// </remarks>
|
||||
event EventHandler<RunnableEventArgs>? Deactivated;
|
||||
event EventHandler? Started;
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -1,87 +1,5 @@
|
||||
namespace Terminal.Gui.App;
|
||||
|
||||
/// <summary>
|
||||
/// Event args for <see cref="IRunnable"/> lifecycle events that provide information about the runnable.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Used for post-notification events that cannot be canceled:
|
||||
/// <see cref="IRunnable.Activated"/> and <see cref="IRunnable.Deactivated"/>.
|
||||
/// </remarks>
|
||||
public class RunnableEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="RunnableEventArgs"/>.
|
||||
/// </summary>
|
||||
/// <param name="runnable">The runnable involved in the event.</param>
|
||||
public RunnableEventArgs (IRunnable runnable)
|
||||
{
|
||||
Runnable = runnable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the runnable involved in the event.
|
||||
/// </summary>
|
||||
public IRunnable Runnable { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event args for <see cref="IRunnable.Activating"/> event. Allows cancellation.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This event is raised when a runnable session is about to become active. It can be canceled
|
||||
/// by setting <see cref="System.ComponentModel.CancelEventArgs.Cancel"/> to <see langword="true"/>.
|
||||
/// </remarks>
|
||||
public class RunnableActivatingEventArgs : System.ComponentModel.CancelEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="RunnableActivatingEventArgs"/>.
|
||||
/// </summary>
|
||||
/// <param name="activating">The runnable that is being activated.</param>
|
||||
/// <param name="deactivated">The runnable that is being deactivated, or null if none.</param>
|
||||
public RunnableActivatingEventArgs (IRunnable activating, IRunnable? deactivated)
|
||||
{
|
||||
Activating = activating;
|
||||
Deactivated = deactivated;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the runnable that is being activated.
|
||||
/// </summary>
|
||||
public IRunnable Activating { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the runnable that is being deactivated, or null if none.
|
||||
/// </summary>
|
||||
public IRunnable? Deactivated { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event args for <see cref="IRunnable.Deactivating"/> event. Allows cancellation.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This event is raised when a runnable session is about to cease being active. It can be canceled
|
||||
/// by setting <see cref="System.ComponentModel.CancelEventArgs.Cancel"/> to <see langword="true"/>.
|
||||
/// </remarks>
|
||||
public class RunnableDeactivatingEventArgs : System.ComponentModel.CancelEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="RunnableDeactivatingEventArgs"/>.
|
||||
/// </summary>
|
||||
/// <param name="deactivating">The runnable that is being deactivated.</param>
|
||||
/// <param name="activated">The runnable that is being activated, or null if none.</param>
|
||||
public RunnableDeactivatingEventArgs (IRunnable deactivating, IRunnable? activated)
|
||||
{
|
||||
Deactivating = deactivating;
|
||||
Activated = activated;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the runnable that is being deactivated.
|
||||
/// </summary>
|
||||
public IRunnable Deactivating { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the runnable that is being activated, or null if none.
|
||||
/// </summary>
|
||||
public IRunnable? Activated { get; }
|
||||
}
|
||||
// Note: IRunnable lifecycle events (Starting, Started, Stopping, Stopped, Initializing, Initialized)
|
||||
// use standard EventArgs or System.ComponentModel.CancelEventArgs.
|
||||
// No custom event args are needed for the simplified IRunnable interface.
|
||||
|
||||
@@ -11,8 +11,7 @@ namespace Terminal.Gui.ViewBase;
|
||||
/// </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"/>.
|
||||
/// <see cref="OnStarting"/>, <see cref="OnStarted"/>, <see cref="OnStopping"/>, <see cref="OnStopped"/>.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class Runnable : View, IRunnable
|
||||
@@ -22,6 +21,42 @@ public class Runnable : View, IRunnable
|
||||
|
||||
#region IRunnable Implementation (RaiseXxxEvent Methods)
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual bool RaiseStartingEvent ()
|
||||
{
|
||||
// CWP Phase 1: Pre-notification via virtual method (can cancel)
|
||||
if (OnStarting ())
|
||||
{
|
||||
return true; // Starting canceled
|
||||
}
|
||||
|
||||
// CWP Phase 2: Event notification (can cancel)
|
||||
var args = new System.ComponentModel.CancelEventArgs ();
|
||||
Starting?.Invoke (this, args);
|
||||
|
||||
if (args.Cancel)
|
||||
{
|
||||
return true; // Starting canceled
|
||||
}
|
||||
|
||||
// CWP Phase 3: Perform the work (mark as running)
|
||||
Running = true;
|
||||
|
||||
// CWP Phase 4: Post-notification via virtual method
|
||||
OnStarted ();
|
||||
|
||||
// CWP Phase 5: Post-notification event
|
||||
Started?.Invoke (this, EventArgs.Empty);
|
||||
|
||||
return false; // Starting succeeded
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual void RaiseStartedEvent ()
|
||||
{
|
||||
Started?.Invoke (this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual void RaiseStoppingEvent ()
|
||||
{
|
||||
@@ -50,72 +85,47 @@ public class Runnable : View, IRunnable
|
||||
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="Starting"/> event. Override to cancel starting.
|
||||
/// </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 starting.
|
||||
/// Default implementation returns <see langword="false"/> (allow starting).
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Override this method to provide custom logic for determining whether the runnable
|
||||
/// should start (e.g., validating preconditions).
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
protected virtual bool OnStarting ()
|
||||
{
|
||||
return false; // Default: allow starting
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called after session has started. Override for post-start work.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This is the fourth phase of the Cancellable Work Pattern for starting.
|
||||
/// At this point, <see cref="Running"/> is <see langword="true"/>.
|
||||
/// Default implementation does nothing.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Override this method to perform work that should occur after the session starts.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
protected virtual void OnStarted ()
|
||||
{
|
||||
// Default: do nothing
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called before <see cref="Stopping"/> event. Override to cancel stopping.
|
||||
/// </summary>
|
||||
@@ -153,110 +163,24 @@ public class Runnable : View, IRunnable
|
||||
// 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>? Starting;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public event EventHandler? Started;
|
||||
|
||||
/// <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>
|
||||
|
||||
@@ -7,19 +7,13 @@ namespace Terminal.Gui.Views;
|
||||
/// scheme.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// To run the <see cref="Dialog"/> modally, create the <see cref="Dialog"/>, and pass it to
|
||||
/// <see cref="IApplication.Run(Toplevel, Func{Exception, bool})"/>. This will execute the dialog until
|
||||
/// it terminates via the <see cref="Application.QuitKey"/> (`Esc` by default),
|
||||
/// or when one of the views or buttons added to the dialog calls
|
||||
/// <see cref="Application.RequestStop"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Dialog implements <see cref="IModalRunnable{TResult}"/> with <c>int?</c> as the result type.
|
||||
/// The <see cref="Result"/> property contains the index of the button that was clicked, or null if canceled.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class Dialog : Window, IModalRunnable<int?>
|
||||
public class Dialog : Window
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Dialog"/> class with no <see cref="Button"/>s.
|
||||
@@ -66,24 +60,6 @@ public class Dialog : Window, IModalRunnable<int?>
|
||||
|
||||
_buttons.Add (button);
|
||||
Add (button);
|
||||
|
||||
// Subscribe to the button's Accept command to set Result
|
||||
button.Accepting += Button_Accepting;
|
||||
}
|
||||
|
||||
private void Button_Accepting (object? sender, CommandEventArgs e)
|
||||
{
|
||||
// Set Result to the index of the button that was clicked
|
||||
if (sender is Button button)
|
||||
{
|
||||
int index = _buttons.IndexOf (button);
|
||||
if (index >= 0)
|
||||
{
|
||||
Result = index;
|
||||
// For backward compatibility, set Canceled = false
|
||||
Canceled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Update button.X = Pos.Justify when alignment changes
|
||||
@@ -109,14 +85,7 @@ public class Dialog : Window, IModalRunnable<int?>
|
||||
}
|
||||
|
||||
/// <summary>Gets a value indicating whether the <see cref="Dialog"/> was canceled.</summary>
|
||||
/// <remarks>
|
||||
/// <para>The default value is <see langword="true"/>.</para>
|
||||
/// <para>
|
||||
/// <b>Obsolete:</b> Use <see cref="Result"/> instead. When <see cref="Result"/> is null, the dialog was canceled.
|
||||
/// This property is maintained for backward compatibility.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[Obsolete ("Use Result property instead. Result == null indicates the dialog was canceled.")]
|
||||
/// <remarks>The default value is <see langword="true"/>.</remarks>
|
||||
public bool Canceled
|
||||
{
|
||||
get { return _canceled; }
|
||||
@@ -132,29 +101,6 @@ public class Dialog : Window, IModalRunnable<int?>
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the result of the modal dialog operation.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Contains the zero-based index of the button that was clicked to close the dialog,
|
||||
/// or null if the dialog was canceled (e.g., ESC key pressed).
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The button index corresponds to the order buttons were added via <see cref="AddButton"/> or
|
||||
/// the <see cref="Buttons"/> initializer.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// For backward compatibility with the <see cref="Canceled"/> property:
|
||||
/// - <see cref="Result"/> == null means the dialog was canceled (<see cref="Canceled"/> == true)
|
||||
/// - <see cref="Result"/> != null means a button was clicked (<see cref="Canceled"/> == false)
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// This property implements <see cref="IModalRunnable{TResult}.Result"/> where TResult is <c>int?</c>.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public int? Result { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Defines the default border styling for <see cref="Dialog"/>. Can be configured via
|
||||
/// <see cref="ConfigurationManager"/>.
|
||||
|
||||
@@ -17,12 +17,8 @@ namespace Terminal.Gui.Views;
|
||||
/// and run (e.g. <see cref="Dialog"/>s). To run a Toplevel, create the <see cref="Toplevel"/> and call
|
||||
/// <see cref="IApplication.Run(Toplevel, Func{Exception, bool})"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Toplevel implements <see cref="IRunnable"/> to support the runnable session lifecycle with proper event handling
|
||||
/// following the Cancellable Work Pattern (CWP).
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public partial class Toplevel : View, IRunnable
|
||||
public partial class Toplevel : View
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Toplevel"/> class,
|
||||
@@ -96,60 +92,27 @@ public partial class Toplevel : View, IRunnable
|
||||
/// </summary>
|
||||
public bool IsLoaded { get; private set; }
|
||||
|
||||
// TODO: IRunnable: Re-implement as an event on IRunnable; IRunnable.Activating/Activate
|
||||
/// <summary>Invoked when the Toplevel <see cref="SessionToken"/> active.</summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// <b>Obsolete:</b> Use <see cref="IRunnable.Activated"/> instead. This event is maintained for backward
|
||||
/// compatibility and will be raised alongside the new <see cref="IRunnable.Activated"/> event.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[Obsolete ("Use IRunnable.Activated instead. This event is maintained for backward compatibility.")]
|
||||
public event EventHandler<ToplevelEventArgs>? Activate;
|
||||
|
||||
// TODO: IRunnable: Re-implement as an event on IRunnable; IRunnable.Deactivating/Deactivate?
|
||||
/// <summary>Invoked when the Toplevel<see cref="SessionToken"/> ceases to be active.</summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// <b>Obsolete:</b> Use <see cref="IRunnable.Deactivated"/> instead. This event is maintained for backward
|
||||
/// compatibility and will be raised alongside the new <see cref="IRunnable.Deactivated"/> event.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[Obsolete ("Use IRunnable.Deactivated instead. This event is maintained for backward compatibility.")]
|
||||
public event EventHandler<ToplevelEventArgs>? Deactivate;
|
||||
|
||||
/// <summary>Invoked when the Toplevel's <see cref="SessionToken"/> is closed by <see cref="IApplication.End(SessionToken)"/>.</summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// <b>Obsolete:</b> This event is maintained for backward compatibility. The IRunnable architecture
|
||||
/// combines this functionality into the <see cref="IRunnable.Stopped"/> event.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[Obsolete ("Use IRunnable.Stopped instead. This event is maintained for backward compatibility.")]
|
||||
public event EventHandler<ToplevelEventArgs>? Closed;
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the Toplevel's <see cref="SessionToken"/> is being closed by
|
||||
/// <see cref="IApplication.RequestStop(Toplevel)"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// <b>Obsolete:</b> Use <see cref="IRunnable.Stopping"/> instead. This event is maintained for backward
|
||||
/// compatibility and will be raised alongside the new <see cref="IRunnable.Stopping"/> event.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[Obsolete ("Use IRunnable.Stopping instead. This event is maintained for backward compatibility.")]
|
||||
public event EventHandler<ToplevelClosingEventArgs>? Closing;
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the <see cref="Toplevel"/> <see cref="SessionToken"/> has begun to be loaded. A Loaded event handler
|
||||
/// is a good place to finalize initialization before calling Run.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// <b>Obsolete:</b> Use <see cref="View.Initialized"/> instead. The Loaded event conceptually maps to
|
||||
/// the Initialized event from the ISupportInitialize pattern, which is now part of IRunnable.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[Obsolete ("Use View.Initialized instead. The Loaded event maps to the Initialized event from ISupportInitialize.")]
|
||||
public event EventHandler? Loaded;
|
||||
|
||||
/// <summary>
|
||||
@@ -181,13 +144,6 @@ public partial class Toplevel : View, IRunnable
|
||||
/// <see cref="IApplication.Run(Toplevel, Func{Exception, bool})"/> on this <see cref="Toplevel"/>.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// <b>Obsolete:</b> Use <see cref="View.Initialized"/> instead. The Ready event is similar to Initialized
|
||||
/// but was fired later in the lifecycle. The IRunnable architecture consolidates these into Initialized.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[Obsolete ("Use View.Initialized instead. The Ready event is consolidated into the Initialized event.")]
|
||||
public event EventHandler? Ready;
|
||||
|
||||
/// <summary>
|
||||
@@ -203,13 +159,6 @@ public partial class Toplevel : View, IRunnable
|
||||
/// Invoked when the Toplevel <see cref="SessionToken"/> has been unloaded. A Unloaded event handler is a good place
|
||||
/// to dispose objects after calling <see cref="IApplication.End(SessionToken)"/>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// <b>Obsolete:</b> Use <see cref="IRunnable.Stopped"/> instead. The Unloaded event is consolidated into
|
||||
/// the Stopped event in the IRunnable architecture.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[Obsolete ("Use IRunnable.Stopped instead. The Unloaded event is consolidated into the Stopped event.")]
|
||||
public event EventHandler? Unloaded;
|
||||
|
||||
internal virtual void OnActivate (Toplevel deactivated) { Activate?.Invoke (this, new (deactivated)); }
|
||||
@@ -254,226 +203,6 @@ public partial class Toplevel : View, IRunnable
|
||||
|
||||
#endregion
|
||||
|
||||
#region IRunnable Implementation
|
||||
|
||||
// Note: Running property is already defined above in the Life Cycle region (line 86)
|
||||
// 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;
|
||||
|
||||
/// <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));
|
||||
}
|
||||
|
||||
/// <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 calls the legacy <see cref="OnClosing"/> method for backward compatibility.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
protected virtual bool OnStopping ()
|
||||
{
|
||||
// For backward compatibility, delegate to legacy OnClosing method
|
||||
var ev = new ToplevelClosingEventArgs (this);
|
||||
return OnClosing (ev);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called after session has stopped. Override for post-stop cleanup.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Default implementation does nothing. For backward compatibility, the legacy <see cref="Closed"/>
|
||||
/// event is raised by Application.End().
|
||||
/// </remarks>
|
||||
protected virtual void OnStopped ()
|
||||
{
|
||||
// Default: do nothing
|
||||
// Note: Legacy Closed event is raised by Application.End()
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// Default implementation returns false (allow activation). For backward compatibility,
|
||||
/// the legacy <see cref="OnActivate"/> method is called after activation succeeds.
|
||||
/// </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>
|
||||
/// Default implementation raises the <see cref="Activated"/> event and calls the legacy
|
||||
/// <see cref="OnActivate"/> method for backward compatibility.
|
||||
/// </remarks>
|
||||
protected virtual void OnActivated (IRunnable? deactivated)
|
||||
{
|
||||
RaiseActivatedEvent (deactivated);
|
||||
|
||||
// For backward compatibility, call legacy OnActivate if deactivated is a Toplevel
|
||||
if (deactivated is Toplevel tl)
|
||||
{
|
||||
OnActivate (tl);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If not a Toplevel, still raise the legacy Activate event with null
|
||||
Activate?.Invoke (this, new ToplevelEventArgs (null));
|
||||
}
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// Default implementation returns false (allow deactivation).
|
||||
/// </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>
|
||||
/// Default implementation raises the <see cref="Deactivated"/> event and calls the legacy
|
||||
/// <see cref="OnDeactivate"/> method for backward compatibility.
|
||||
/// </remarks>
|
||||
protected virtual void OnDeactivated (IRunnable? activated)
|
||||
{
|
||||
RaiseDeactivatedEvent (activated);
|
||||
|
||||
// For backward compatibility, call legacy OnDeactivate if activated is a Toplevel
|
||||
if (activated is Toplevel tl)
|
||||
{
|
||||
OnDeactivate (tl);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If not a Toplevel, still raise the legacy Deactivate event with null
|
||||
Deactivate?.Invoke (this, new ToplevelEventArgs (null));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Size / Position Management
|
||||
|
||||
// TODO: Make cancelable?
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace UnitTests.ViewsTests;
|
||||
|
||||
public class IRunnableTests (ITestOutputHelper output)
|
||||
{
|
||||
private readonly ITestOutputHelper _output = output;
|
||||
|
||||
[Fact]
|
||||
public void Toplevel_Implements_IRunnable ()
|
||||
{
|
||||
var top = new Toplevel ();
|
||||
Assert.IsAssignableFrom<IRunnable> (top);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Dialog_Implements_IModalRunnable ()
|
||||
{
|
||||
var dialog = new Dialog ();
|
||||
Assert.IsAssignableFrom<IRunnable> (dialog);
|
||||
Assert.IsAssignableFrom<IModalRunnable<int?>> (dialog);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Runnable_Base_Class_Works ()
|
||||
{
|
||||
var runnable = new Runnable ();
|
||||
Assert.IsAssignableFrom<IRunnable> (runnable);
|
||||
Assert.False (runnable.Running);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[AutoInitShutdown]
|
||||
public void Dialog_Result_Property_Works ()
|
||||
{
|
||||
var dialog = new Dialog ();
|
||||
var btn1 = new Button { Text = "OK" };
|
||||
var btn2 = new Button { Text = "Cancel" };
|
||||
|
||||
dialog.AddButton (btn1);
|
||||
dialog.AddButton (btn2);
|
||||
|
||||
// Result should be null by default
|
||||
Assert.Null (dialog.Result);
|
||||
|
||||
// Simulate clicking the first button by invoking Accept
|
||||
btn1.InvokeCommand (Command.Accept);
|
||||
|
||||
// Result should now be 0 (first button)
|
||||
Assert.Equal (0, dialog.Result);
|
||||
|
||||
// Reset
|
||||
dialog.Result = null;
|
||||
|
||||
// Simulate clicking the second button
|
||||
btn2.InvokeCommand (Command.Accept);
|
||||
|
||||
// Result should now be 1 (second button)
|
||||
Assert.Equal (1, dialog.Result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[AutoInitShutdown]
|
||||
public void Toplevel_Legacy_Events_Still_Work ()
|
||||
{
|
||||
// Verify that legacy Toplevel events still fire for backward compatibility
|
||||
var eventsRaised = new List<string> ();
|
||||
var top = new Toplevel ();
|
||||
|
||||
#pragma warning disable CS0618 // Type or member is obsolete
|
||||
top.Activate += (s, e) => eventsRaised.Add ("Activate");
|
||||
#pragma warning restore CS0618
|
||||
|
||||
var token = Application.Begin (top);
|
||||
|
||||
// Legacy event should still fire
|
||||
Assert.Contains ("Activate", eventsRaised);
|
||||
|
||||
Application.End (token);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IRunnable_Stopping_Event_Works ()
|
||||
{
|
||||
// Test that the Stopping event can be subscribed to and fires
|
||||
var top = new Toplevel ();
|
||||
var stoppingFired = false;
|
||||
var stoppedFired = false;
|
||||
|
||||
top.Stopping += (s, e) => { stoppingFired = true; };
|
||||
top.Stopped += (s, e) => { stoppedFired = true; };
|
||||
|
||||
top.Running = true;
|
||||
top.RaiseStoppingEvent ();
|
||||
|
||||
Assert.True (stoppingFired);
|
||||
Assert.True (stoppedFired);
|
||||
Assert.False (top.Running);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IRunnable_Stopping_Can_Be_Canceled ()
|
||||
{
|
||||
// Test that the Stopping event can cancel the stop operation
|
||||
var top = new Toplevel ();
|
||||
var stoppingFired = false;
|
||||
var stoppedFired = false;
|
||||
|
||||
top.Stopping += (s, e) =>
|
||||
{
|
||||
stoppingFired = true;
|
||||
e.Cancel = true; // Cancel the stop
|
||||
};
|
||||
|
||||
top.Stopped += (s, e) => { stoppedFired = true; };
|
||||
|
||||
top.Running = true;
|
||||
top.RaiseStoppingEvent ();
|
||||
|
||||
Assert.True (stoppingFired);
|
||||
Assert.False (stoppedFired); // Should not fire because it was canceled
|
||||
Assert.True (top.Running); // Should still be running
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[AutoInitShutdown]
|
||||
public void IRunnable_Initialization_Events_Fire ()
|
||||
{
|
||||
// Test that Initializing and Initialized events fire
|
||||
var initializingFired = false;
|
||||
var initializedFired = false;
|
||||
var top = new Toplevel ();
|
||||
|
||||
top.Initializing += (s, e) => { initializingFired = true; };
|
||||
top.Initialized += (s, e) => { initializedFired = true; };
|
||||
|
||||
var token = Application.Begin (top);
|
||||
|
||||
Assert.True (initializingFired);
|
||||
Assert.True (initializedFired);
|
||||
|
||||
Application.End (token);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void IRunnable_Activating_And_Activated_Events_Can_Fire ()
|
||||
{
|
||||
// Test that manually calling the activation methods works
|
||||
var activatingFired = false;
|
||||
var activatedFired = false;
|
||||
var top = new Toplevel ();
|
||||
|
||||
top.Activating += (s, e) => { activatingFired = true; };
|
||||
top.Activated += (s, e) => { activatedFired = true; };
|
||||
|
||||
// Manually trigger activation
|
||||
bool canceled = top.RaiseActivatingEvent (null);
|
||||
|
||||
Assert.False (canceled);
|
||||
Assert.True (activatingFired);
|
||||
Assert.True (activatedFired);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user