namespace Terminal.Gui.ViewBase;
///
/// Extension methods for making any runnable with typed results.
///
///
/// These extensions provide a fluent API for wrapping views in ,
/// enabling any View to be run as a blocking session without implementing .
///
public static class ViewRunnableExtensions
{
///
/// Converts any View into a runnable with typed result extraction.
///
/// The type of view to make runnable.
/// The type of result data to extract.
/// The view to wrap. Cannot be null.
///
/// Function that extracts the result from the view when stopping.
/// Called automatically when the runnable session ends.
///
/// A that wraps the view.
/// Thrown if or is null.
///
///
/// This method wraps the view in a and automatically
/// subscribes to to extract the result when the session stops.
///
///
/// The result is extracted before the view is disposed, ensuring all data is still accessible.
///
///
///
///
/// // Make a TextField runnable with string result
/// var runnable = new TextField { Width = 40 }
/// .AsRunnable(tf => tf.Text);
///
/// app.Run(runnable);
/// Console.WriteLine($"User entered: {runnable.Result}");
/// runnable.Dispose();
///
/// // Make a ColorPicker runnable with Color? result
/// var colorRunnable = new ColorPicker()
/// .AsRunnable(cp => cp.SelectedColor);
///
/// app.Run(colorRunnable);
/// Console.WriteLine($"Selected: {colorRunnable.Result}");
/// colorRunnable.Dispose();
///
/// // Make a FlagSelector runnable with enum result
/// var flagsRunnable = new FlagSelector<SelectorStyles>()
/// .AsRunnable(fs => fs.Value);
///
/// app.Run(flagsRunnable);
/// Console.WriteLine($"Selected styles: {flagsRunnable.Result}");
/// flagsRunnable.Dispose();
///
///
public static RunnableWrapper AsRunnable (
this TView view,
Func resultExtractor)
where TView : View
{
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);
}
};
return wrapper;
}
///
/// Converts any View into a runnable without result extraction.
///
/// The type of view to make runnable.
/// The view to wrap. Cannot be null.
/// A that wraps the view.
/// Thrown if is null.
///
///
/// Use this overload when you don't need to extract a typed result, but still want to
/// run the view as a blocking session. The wrapped view can still be accessed via
/// after running.
///
///
///
///
/// // Make a view runnable without result extraction
/// var colorPicker = new ColorPicker();
/// var runnable = colorPicker.AsRunnable();
///
/// app.Run(runnable);
///
/// // Access the wrapped view directly to get the result
/// Console.WriteLine($"Selected: {runnable.WrappedView.SelectedColor}");
/// runnable.Dispose();
///
///
public static RunnableWrapper AsRunnable (this TView view)
where TView : View
{
if (view is null)
{
throw new ArgumentNullException (nameof (view));
}
return new RunnableWrapper { WrappedView = view };
}
}