namespace Terminal.Gui.App; #nullable enable /// /// Provides helper methods for executing property change workflows in the Cancellable Work Pattern (CWP). /// /// /// /// Used for workflows where a property value is modified, such as in or /// , allowing pre- and post-change events to customize or cancel the change. /// /// /// /// public static class CWPPropertyHelper { /// /// Executes a CWP workflow for a property change, with pre- and post-change events. /// /// /// The type of the property value, which may be a nullable reference type (e.g., /// ?). /// /// The current property value, which may be null for nullable types. /// The proposed new property value, which may be null for nullable types. /// The virtual method invoked before the change, returning true to cancel. /// The pre-change event raised to allow modification or cancellation. /// The virtual method invoked after the change. /// The post-change event raised to notify of the completed change. /// /// The final value after the workflow, reflecting any modifications, which may be null for /// nullable types. /// /// True if the property was changed, false if cancelled. /// /// Thrown if is null for non-nullable reference types after the /// workflow. /// /// /// /// string? current = null; /// string? proposed = "Base"; /// Func<ValueChangingEventArgs<string?>, bool> onChanging = args => false; /// EventHandler<ValueChangingEventArgs<string?>>? changingEvent = null; /// Action<ValueChangedEventArgs<string?>>? onChanged = args => /// Console.WriteLine($"SchemeName changed to {args.NewValue ?? "none"}."); /// EventHandler<ValueChangedEventArgs<string?>>? changedEvent = null; /// bool changed = CWPPropertyHelper.ChangeProperty( /// current, proposed, onChanging, changingEvent, onChanged, changedEvent, out string? final); /// /// public static bool ChangeProperty ( T currentValue, T newValue, Func, bool> onChanging, EventHandler>? changingEvent, Action>? onChanged, EventHandler>? changedEvent, out T finalValue ) { if (EqualityComparer.Default.Equals (currentValue, newValue)) { finalValue = currentValue; return false; } ValueChangingEventArgs args = new (currentValue, newValue); bool cancelled = onChanging (args) || args.Handled; if (cancelled) { finalValue = currentValue; return false; } changingEvent?.Invoke (null, args); if (args.Handled) { finalValue = currentValue; return false; } // Validate NewValue for non-nullable reference types if (args.NewValue is null && !typeof (T).IsValueType && !Nullable.GetUnderlyingType (typeof (T))?.IsValueType == true) { throw new InvalidOperationException ("NewValue cannot be null for non-nullable reference types."); } finalValue = args.NewValue; ValueChangedEventArgs changedArgs = new (currentValue, finalValue); onChanged?.Invoke (changedArgs); changedEvent?.Invoke (null, changedArgs); return true; } }