mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
* Initial plan * Add comprehensive analysis of Line implementation status Co-authored-by: tig <585482+tig@users.noreply.github.com> * Complete Line implementation with documentation, example, and tests Co-authored-by: tig <585482+tig@users.noreply.github.com> * Add PR summary documenting Line implementation completion Co-authored-by: tig <585482+tig@users.noreply.github.com> * Add comprehensive completion report for Issue 4150 Co-authored-by: tig <585482+tig@users.noreply.github.com> * Fix Line rendering: use SuperView's LineCanvas instead of own Co-authored-by: tig <585482+tig@users.noreply.github.com> * Redesign Line to use Border instead of manual LineCanvas Co-authored-by: tig <585482+tig@users.noreply.github.com> * Add Line.Style property to avoid BorderStyle conflict Co-authored-by: tig <585482+tig@users.noreply.github.com> * Add SetWidth/SetHeight methods to preserve dimensions on Orientation change Co-authored-by: tig <585482+tig@users.noreply.github.com> * Implement CWP events for Width/Height properties; update Line to use events Co-authored-by: tig <585482+tig@users.noreply.github.com> * WIP: Updating Line. Cleaned up Layout tests. * Made Height/Width non-nullable * Add doWork stage to CWPPropertyHelper to execute between Changing and Changed events Co-authored-by: tig <585482+tig@users.noreply.github.com> * Move ViewLayoutEventTests to parallelizable tests without AutoInitShutdown Co-authored-by: tig <585482+tig@users.noreply.github.com> * Replace tracking fields with Length property for thread-safe Line implementation Co-authored-by: tig <585482+tig@users.noreply.github.com> * Fix orientation handling to preserve user-set dimensions in object initializers Co-authored-by: tig <585482+tig@users.noreply.github.com> * Simplify orientation handling with dimension swapping - all tests passing Co-authored-by: tig <585482+tig@users.noreply.github.com> * Add Length backing field and fix object initializer dimension handling Co-authored-by: tig <585482+tig@users.noreply.github.com> * Use CWP OnChanging events to manage dimensions instead of OnChanged Co-authored-by: tig <585482+tig@users.noreply.github.com> * Move LineTests to parallelizable; simplify tests with GetAnchor; fix Length property Co-authored-by: tig <585482+tig@users.noreply.github.com> * Code cleanup. * Code cleanup. * Update Terminal.Gui/ViewBase/View.Layout.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update Terminal.Gui/ViewBase/View.Layout.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update Terminal.Gui/ViewBase/View.Layout.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update Terminal.Gui/ViewBase/View.Layout.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Fixed nullable warning in test * Removed PR files and updated copilot guidance * Reverted .gitignore change --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Tig <tig@users.noreply.github.com> Co-authored-by: tig <585482+tig@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
109 lines
4.6 KiB
C#
109 lines
4.6 KiB
C#
namespace Terminal.Gui.App;
|
|
|
|
#nullable enable
|
|
|
|
/// <summary>
|
|
/// Provides helper methods for executing property change workflows in the Cancellable Work Pattern (CWP).
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// Used for workflows where a property value is modified, such as in <see cref="OrientationHelper"/> or
|
|
/// <see cref="View.SchemeName"/>, allowing pre- and post-change events to customize or cancel the change.
|
|
/// </para>
|
|
/// </remarks>
|
|
/// <seealso cref="ValueChangingEventArgs{T}"/>
|
|
/// <seealso cref="ValueChangedEventArgs{T}"/>
|
|
public static class CWPPropertyHelper
|
|
{
|
|
/// <summary>
|
|
/// Executes a CWP workflow for a property change, with pre- and post-change events.
|
|
/// </summary>
|
|
/// <typeparam name="T">
|
|
/// The type of the property value, which may be a nullable reference type (e.g., <see cref="string"/>
|
|
/// ?).
|
|
/// </typeparam>
|
|
/// <param name="currentValue">The current property value, which may be null for nullable types.</param>
|
|
/// <param name="newValue">The proposed new property value, which may be null for nullable types.</param>
|
|
/// <param name="onChanging">The virtual method invoked before the change, returning true to cancel.</param>
|
|
/// <param name="changingEvent">The pre-change event raised to allow modification or cancellation.</param>
|
|
/// <param name="doWork">The action that performs the actual work of setting the property (e.g., updating backing field, calling related methods).</param>
|
|
/// <param name="onChanged">The virtual method invoked after the change.</param>
|
|
/// <param name="changedEvent">The post-change event raised to notify of the completed change.</param>
|
|
/// <param name="finalValue">
|
|
/// The final value after the workflow, reflecting any modifications, which may be null for
|
|
/// nullable types.
|
|
/// </param>
|
|
/// <returns>True if the property was changed, false if cancelled.</returns>
|
|
/// <exception cref="InvalidOperationException">
|
|
/// Thrown if <see cref="ValueChangingEventArgs{T}.NewValue"/> is null for non-nullable reference types after the
|
|
/// workflow.
|
|
/// </exception>
|
|
/// <example>
|
|
/// <code>
|
|
/// string? current = _schemeName;
|
|
/// string? proposed = "Base";
|
|
/// Func<ValueChangingEventArgs<string?>, bool> onChanging = OnSchemeNameChanging;
|
|
/// EventHandler<ValueChangingEventArgs<string?>>? changingEvent = SchemeNameChanging;
|
|
/// Action<string?> doWork = value => _schemeName = value;
|
|
/// Action<ValueChangedEventArgs<string?>>? onChanged = OnSchemeNameChanged;
|
|
/// EventHandler<ValueChangedEventArgs<string?>>? changedEvent = SchemeNameChanged;
|
|
/// bool changed = CWPPropertyHelper.ChangeProperty(
|
|
/// current, proposed, onChanging, changingEvent, doWork, onChanged, changedEvent, out string? final);
|
|
/// </code>
|
|
/// </example>
|
|
public static bool ChangeProperty<T> (
|
|
T currentValue,
|
|
T newValue,
|
|
Func<ValueChangingEventArgs<T>, bool> onChanging,
|
|
EventHandler<ValueChangingEventArgs<T>>? changingEvent,
|
|
Action<T> doWork,
|
|
Action<ValueChangedEventArgs<T>>? onChanged,
|
|
EventHandler<ValueChangedEventArgs<T>>? changedEvent,
|
|
out T finalValue
|
|
)
|
|
{
|
|
if (EqualityComparer<T>.Default.Equals (currentValue, newValue))
|
|
{
|
|
finalValue = currentValue;
|
|
|
|
return false;
|
|
}
|
|
|
|
ValueChangingEventArgs<T> 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;
|
|
|
|
// Do the work (set backing field, update related properties, etc.) BEFORE raising Changed events
|
|
doWork (finalValue);
|
|
|
|
ValueChangedEventArgs<T> changedArgs = new (currentValue, finalValue);
|
|
onChanged?.Invoke (changedArgs);
|
|
changedEvent?.Invoke (null, changedArgs);
|
|
|
|
return true;
|
|
}
|
|
}
|