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;
}
}