namespace Terminal.Gui.App; /// /// Extension methods for that enable running any as a runnable session. /// /// /// These extensions provide convenience methods for wrapping views in /// and running them in a single call, similar to how works. /// public static class ApplicationRunnableExtensions { /// /// Runs any View as a runnable session, extracting a typed result via a function. /// /// The type of view to run. /// The type of result data to extract. /// The application instance. Cannot be null. /// The view to run as a blocking session. Cannot be null. /// /// Function that extracts the result from the view when stopping. /// Called automatically when the runnable session ends. /// /// Optional handler for unhandled exceptions during the session. /// The extracted result, or null if the session was canceled. /// /// Thrown if , , or is null. /// /// /// /// This method wraps the view in a , runs it as a blocking /// session, and returns the extracted result. The wrapper is NOT disposed automatically; /// the caller is responsible for disposal. /// /// /// The result is extracted before the view is disposed, ensuring all data is still accessible. /// /// /// /// /// var app = Application.Create(); /// app.Init(); /// /// // Run a TextField and get the entered text /// var text = app.RunView( /// new TextField { Width = 40 }, /// tf => tf.Text); /// Console.WriteLine($"You entered: {text}"); /// /// // Run a ColorPicker and get the selected color /// var color = app.RunView( /// new ColorPicker(), /// cp => cp.SelectedColor); /// Console.WriteLine($"Selected color: {color}"); /// /// // Run a FlagSelector and get the selected flags /// var flags = app.RunView( /// new FlagSelector<SelectorStyles>(), /// fs => fs.Value); /// Console.WriteLine($"Selected styles: {flags}"); /// /// app.Shutdown(); /// /// public static TResult? RunView ( this IApplication app, TView view, Func resultExtractor, Func? errorHandler = null) where TView : View { if (app is null) { throw new ArgumentNullException (nameof (app)); } if (view is null) { throw new ArgumentNullException (nameof (view)); } if (resultExtractor is null) { throw new ArgumentNullException (nameof (resultExtractor)); } var wrapper = new RunnableWrapper { WrappedView = view }; // Subscribe to IsRunningChanging to extract result when stopping wrapper.IsRunningChanging += (s, e) => { if (!e.NewValue) // Stopping { wrapper.Result = resultExtractor (view); } }; app.Run (wrapper, errorHandler); return wrapper.Result; } /// /// Runs any View as a runnable session without result extraction. /// /// The type of view to run. /// The application instance. Cannot be null. /// The view to run as a blocking session. Cannot be null. /// Optional handler for unhandled exceptions during the session. /// The view that was run, allowing access to its state after the session ends. /// Thrown if or is null. /// /// /// This method wraps the view in a and runs it as a blocking /// session. The wrapper is NOT disposed automatically; the caller is responsible for disposal. /// /// /// Use this overload when you don't need automatic result extraction, but still want the view /// to run as a blocking session. Access the view's properties directly after running. /// /// /// /// /// var app = Application.Create(); /// app.Init(); /// /// // Run a ColorPicker without automatic result extraction /// var colorPicker = new ColorPicker(); /// app.RunView(colorPicker); /// /// // Access the view's state directly /// Console.WriteLine($"Selected: {colorPicker.SelectedColor}"); /// /// app.Shutdown(); /// /// public static TView RunView ( this IApplication app, TView view, Func? errorHandler = null) where TView : View { if (app is null) { throw new ArgumentNullException (nameof (app)); } if (view is null) { throw new ArgumentNullException (nameof (view)); } var wrapper = new RunnableWrapper { WrappedView = view }; app.Run (wrapper, errorHandler); return view; } }