Bladeren bron

Revamped to further simplify and make more correct

Tig 1 jaar geleden
bovenliggende
commit
cd43ee363d

+ 3 - 3
Terminal.Gui/Application/Application.cs

@@ -308,7 +308,7 @@ public static partial class Application
         SupportedCultures = GetSupportedCultures ();
         _mainThreadId = Thread.CurrentThread.ManagedThreadId;
         _initialized = true;
-        InitializedChanged?.Invoke (null, new (false, _initialized));
+        InitializedChanged?.Invoke (null, new (in _initialized));
     }
 
     private static void Driver_SizeChanged (object sender, SizeChangedEventArgs e) { OnSizeChanging (e); }
@@ -349,7 +349,7 @@ public static partial class Application
         // TODO: Throw an exception if Init hasn't been called.
         ResetState ();
         PrintJsonErrors ();
-        InitializedChanged?.Invoke (null, new (true, _initialized));
+        InitializedChanged?.Invoke (null, new (in _initialized));
     }
 
     /// <summary>
@@ -358,7 +358,7 @@ public static partial class Application
     /// <remarks>
     ///     Intended to support unit tests that need to know when the application has been initialized.
     /// </remarks>
-    public static event EventHandler<CancelEventArgs<bool>> InitializedChanged;
+    public static event EventHandler<EventArgs<bool>> InitializedChanged;
 
     #endregion Initialization (Init/Shutdown)
 

+ 3 - 3
Terminal.Gui/View/Adornment/Adornment.cs

@@ -61,16 +61,16 @@ public class Adornment : View
                     Parent?.LayoutSubviews ();
                 }
 
-                OnThicknessChanged (new (current, Thickness));
+                OnThicknessChanged (new (Thickness));
             }
         }
     }
 
     /// <summary>Fired whenever the <see cref="Thickness"/> property changes.</summary>
-    public event EventHandler<CancelEventArgs<Thickness>> ThicknessChanged;
+    public event EventHandler<EventArgs<Thickness>> ThicknessChanged;
 
     /// <summary>Called whenever the <see cref="Thickness"/> property changes.</summary>
-    public void OnThicknessChanged (CancelEventArgs<Thickness> args)
+    public void OnThicknessChanged (EventArgs<Thickness> args)
     {
         ThicknessChanged?.Invoke (this, args);
     }

+ 3 - 2
Terminal.Gui/View/Adornment/Border.cs

@@ -299,7 +299,8 @@ public class Border : Adornment
                 _startGrabPoint = new (mouseEvent.Position.X + Frame.X, mouseEvent.Position.Y + Frame.Y);
                 _dragPosition = mouseEvent.Position;
                 Application.GrabMouse (this);
-                SetHighlight (new (HighlightStyle, HighlightStyle));
+
+                SetHighlight (HighlightStyle);
             }
 
             return true;
@@ -343,7 +344,7 @@ public class Border : Adornment
         {
             _dragPosition = null;
             Application.UngrabMouse ();
-            SetHighlight (new (HighlightStyle, HighlightStyle.None));
+            SetHighlight (HighlightStyle.None);
 
             return true;
         }

+ 55 - 2
Terminal.Gui/View/CancelEventArgs.cs

@@ -12,14 +12,67 @@ namespace Terminal.Gui;
 ///     should be set to
 ///     <see langword="true"/> to prevent the state change from occurring.
 /// </remarks>
-public class CancelEventArgs<T> : CancelEventArgs
+public class CancelEventArgs<T> : CancelEventArgs where T : notnull
 {
     /// <summary>Initializes a new instance of the <see cref="CancelEventArgs{T}"/> class.</summary>
     /// <param name="currentValue">The current (old) value of the property.</param>
     /// <param name="newValue">The value the property will be set to if the event is not cancelled.</param>
     /// <param name="cancel">Whether the event should be canceled or not.</param>
     /// <typeparam name="T">The type of the value for the change being canceled.</typeparam>
-    public CancelEventArgs (T currentValue, T newValue, bool cancel = false) : base (cancel)
+    public CancelEventArgs (ref readonly T currentValue, ref T newValue, bool cancel = false) : base (cancel)
+    {
+        CurrentValue = currentValue;
+        NewValue = newValue;
+    }
+
+    /// <summary>The value the property will be set to if the event is not cancelled.</summary>
+    public T NewValue { get; set; }
+
+    /// <summary>The current value of the property.</summary>
+    public T CurrentValue { get; }
+}
+
+
+/// <summary>
+///     <see cref="EventArgs"/> for events that convey changes to a property of type <typeparamref name="T"/>.
+/// </summary>
+/// <typeparam name="T">The type of the value that was part of the change being canceled.</typeparam>
+/// <remarks>
+///     Events that use this class can be cancellable. Where applicable, the <see cref="CancelEventArgs.Cancel"/> property
+///     should be set to
+///     <see langword="true"/> to prevent the state change from occurring.
+/// </remarks>
+public class EventArgs<T> : EventArgs where T : notnull
+{
+    /// <summary>Initializes a new instance of the <see cref="EventArgs{T}"/> class.</summary>
+    /// <param name="currentValue">The current value of the property.</param>
+    /// <typeparam name="T">The type of the value.</typeparam>
+    public EventArgs (ref readonly T currentValue) : base ()
+    {
+        CurrentValue = currentValue;
+    }
+
+    /// <summary>The current value of the property.</summary>
+    public T CurrentValue { get; }
+}
+
+/// <summary>
+///     <see cref="EventArgs"/> for events that convey changes to a property of type <typeparamref name="T"/>.
+/// </summary>
+/// <typeparam name="T">The type of the value that was part of the change being canceled.</typeparam>
+/// <remarks>
+///     Events that use this class can be cancellable. Where applicable, the <see cref="CancelEventArgs.Cancel"/> property
+///     should be set to
+///     <see langword="true"/> to prevent the state change from occurring.
+/// </remarks>
+public class CancelEventArgsStruct<T> : CancelEventArgs where T : notnull
+{
+    /// <summary>Initializes a new instance of the <see cref="CancelEventArgs{T}"/> class.</summary>
+    /// <param name="currentValue">The current (old) value of the property.</param>
+    /// <param name="newValue">The value the property will be set to if the event is not cancelled.</param>
+    /// <param name="cancel">Whether the event should be canceled or not.</param>
+    /// <typeparam name="T">The type of the value for the change being canceled.</typeparam>
+    public CancelEventArgsStruct (T currentValue, T newValue, bool cancel = false) : base (cancel)
     {
         CurrentValue = currentValue;
         NewValue = newValue;

+ 1 - 1
Terminal.Gui/View/HighlightEventArgs.cs

@@ -6,5 +6,5 @@
 public class HighlightEventArgs : CancelEventArgs<HighlightStyle>
 {
     /// <inheritdoc />
-    public HighlightEventArgs (HighlightStyle currentValue, HighlightStyle newValue) : base (currentValue, newValue) { }
+    public HighlightEventArgs (ref HighlightStyle currentValue, ref HighlightStyle newValue) : base (ref currentValue, ref newValue) { }
 }

+ 27 - 0
Terminal.Gui/View/StateEventArgs.cs

@@ -0,0 +1,27 @@
+#nullable enable
+using System.ComponentModel;
+
+namespace Terminal.Gui;
+
+/// <summary><see cref="EventArgs"/> for events that convey state changes to a <see cref="View"/> class.</summary>
+/// <remarks>
+/// Events that use this class can be cancellable. The <see cref="CancelEventArgs.Cancel"/> property should be set to
+/// <see langword="true"/> to prevent the state change from occurring.
+/// </remarks>
+public class StateEventArgs<T> : CancelEventArgs
+{
+    /// <summary>Creates a new instance of the <see cref="StateEventArgs{T}"/> class.</summary>
+    /// <param name="oldValue"></param>
+    /// <param name="newValue"></param>
+    public StateEventArgs (T oldValue, T newValue)
+    {
+        OldValue = oldValue;
+        NewValue = newValue;
+    }
+
+    /// <summary>The new state</summary>
+    public T NewValue { get; set; }
+
+    /// <summary>The previous state</summary>
+    public T OldValue { get; }
+}

+ 7 - 10
Terminal.Gui/View/View.cs

@@ -457,7 +457,7 @@ public partial class View : Responder, ISupportInitializeNotification
                 return;
             }
 
-            if (!OnTitleChanging (_title, value))
+            if (!OnTitleChanging (ref value))
             {
                 string old = _title;
                 _title = value;
@@ -472,7 +472,7 @@ public partial class View : Responder, ISupportInitializeNotification
                     Id = _title;
                 }
 #endif // DEBUG
-                OnTitleChanged (old, _title);
+                OnTitleChanged ();
             }
         }
     }
@@ -488,12 +488,9 @@ public partial class View : Responder, ISupportInitializeNotification
     }
 
     /// <summary>Called when the <see cref="View.Title"/> has been changed. Invokes the <see cref="TitleChanged"/> event.</summary>
-    /// <param name="oldTitle">The <see cref="View.Title"/> that is/has been replaced.</param>
-    /// <param name="newTitle">The new <see cref="View.Title"/> to be replaced.</param>
-    public virtual void OnTitleChanged (string oldTitle, string newTitle)
+    protected void OnTitleChanged ()
     {
-        CancelEventArgs<string> args = new (oldTitle, newTitle);
-        TitleChanged?.Invoke (this, args);
+        TitleChanged?.Invoke (this, new (ref _title));
     }
 
     /// <summary>
@@ -503,16 +500,16 @@ public partial class View : Responder, ISupportInitializeNotification
     /// <param name="oldTitle">The <see cref="View.Title"/> that is/has been replaced.</param>
     /// <param name="newTitle">The new <see cref="View.Title"/> to be replaced.</param>
     /// <returns>`true` if an event handler canceled the Title change.</returns>
-    public virtual bool OnTitleChanging (string oldTitle, string newTitle)
+    protected bool OnTitleChanging (ref string newTitle)
     {
-        CancelEventArgs<string> args = new (oldTitle, newTitle);
+        CancelEventArgs<string> args = new (ref _title, ref newTitle);
         TitleChanging?.Invoke (this, args);
 
         return args.Cancel;
     }
 
     /// <summary>Event fired after the <see cref="View.Title"/> has been changed.</summary>
-    public event EventHandler<CancelEventArgs<string>> TitleChanged;
+    public event EventHandler<EventArgs<string>> TitleChanged;
 
     /// <summary>
     ///     Event fired when the <see cref="View.Title"/> is changing. Set <see cref="CancelEventArgs.Cancel"/> to `true`

+ 2 - 1
Terminal.Gui/View/ViewAdornments.cs

@@ -124,7 +124,8 @@ public partial class View
         get => Border?.LineStyle ?? LineStyle.Single;
         set
         {
-            CancelEventArgs<LineStyle> e = new (Border?.LineStyle ?? LineStyle.None, value);
+            var old = Border?.LineStyle ?? LineStyle.None;
+            CancelEventArgs<LineStyle> e = new (ref old, ref value);
             OnBorderStyleChanging (e);
 
         }

+ 8 - 11
Terminal.Gui/View/ViewMouse.cs

@@ -283,7 +283,7 @@ public partial class View
             // We're grabbed. Clicked event comes after the last Release. This is our signal to ungrab
             Application.UngrabMouse ();
 
-            if (SetHighlight (new (HighlightStyle, HighlightStyle.None)))
+            if (SetHighlight (HighlightStyle.None))
             {
                 return true;
             }
@@ -318,7 +318,7 @@ public partial class View
         {
             if (Application.MouseGrabView == this)
             {
-                SetHighlight (new (HighlightStyle, HighlightStyle.None));
+                SetHighlight (HighlightStyle.None);
             }
 
             return mouseEvent.Handled = true;
@@ -432,7 +432,7 @@ public partial class View
     ///     </para>
     /// </remarks>
     /// <returns><see langword="true"/>, if the Highlight event was handled, <see langword="false"/> otherwise.</returns>
-    internal bool SetHighlight (HighlightEventArgs args)
+    internal bool SetHighlight (HighlightStyle newHighlightStyle)
     {
         // TODO: Make the highlight colors configurable
         if (!CanFocus)
@@ -441,6 +441,9 @@ public partial class View
         }
 
         // Enable override via virtual method and/or event
+        HighlightStyle copy = HighlightStyle;
+        var args = new HighlightEventArgs (ref copy, ref newHighlightStyle);
+
         if (OnHighlight (args) == true)
         {
             return true;
@@ -541,10 +544,7 @@ public partial class View
             if (Viewport.Contains (mouseEvent.Position))
             {
                 if (this is not Adornment
-                    && SetHighlight (
-                                     new (
-                                          HighlightStyle,
-                                          HighlightStyle.HasFlag (HighlightStyle.Pressed) ? HighlightStyle.Pressed : HighlightStyle.None)))
+                    && SetHighlight (HighlightStyle.HasFlag (HighlightStyle.Pressed) ? HighlightStyle.Pressed : HighlightStyle.None))
                 {
                     return true;
                 }
@@ -552,10 +552,7 @@ public partial class View
             else
             {
                 if (this is not Adornment
-                    && SetHighlight (
-                                     new (
-                                          HighlightStyle,
-                                          HighlightStyle.HasFlag (HighlightStyle.PressedOutside) ? HighlightStyle.PressedOutside : HighlightStyle.None)))
+                    && SetHighlight (HighlightStyle.HasFlag (HighlightStyle.PressedOutside) ? HighlightStyle.PressedOutside : HighlightStyle.None))
 
                 {
                     return true;

+ 4 - 5
Terminal.Gui/View/ViewText.cs

@@ -69,23 +69,22 @@ public partial class View
                 Id = _text;
             }
 #endif
-            OnTextChanged (new CancelEventArgs<string> (old, Text));
+            OnTextChanged ();
         }
     }
 
     /// <summary>
     /// Called when the <see cref="Text"/> has changed. Fires the <see cref="TextChanged"/> event.
     /// </summary>
-    /// <param name="args">The event arguments</param>
-    public void OnTextChanged (CancelEventArgs<string> args)
+    public void OnTextChanged ()
     {
-        TextChanged?.Invoke (this, args);
+        TextChanged?.Invoke (this, EventArgs.Empty);
     }
 
     /// <summary>
     ///     Text changed event, raised when the text has changed.
     /// </summary>
-    public event EventHandler<CancelEventArgs<string>> TextChanged;
+    public event EventHandler<EventArgs> TextChanged;
 
     /// <summary>
     ///     Gets or sets how the View's <see cref="Text"/> is aligned horizontally when drawn. Changing this property will

+ 2 - 2
Terminal.Gui/Views/Button.cs

@@ -110,9 +110,9 @@ public class Button : View
         e.Handled = InvokeCommand (Command.HotKey) == true;
     }
 
-    private void Button_TitleChanged (object sender, CancelEventArgs<string> e)
+    private void Button_TitleChanged (object sender, EventArgs<string> e)
     {
-        base.Text = e.NewValue;
+        base.Text = e.CurrentValue;
         TextFormatter.HotKeySpecifier = HotKeySpecifier;
     }
 

+ 22 - 5
Terminal.Gui/Views/CheckBox.cs

@@ -42,9 +42,9 @@ public class CheckBox : View
         e.Handled = OnToggled () == true;
     }
 
-    private void Checkbox_TitleChanged (object? sender, CancelEventArgs<string> e)
+    private void Checkbox_TitleChanged (object? sender, EventArgs<string> e)
     {
-        base.Text = e.NewValue;
+        base.Text = e.CurrentValue;
         TextFormatter.HotKeySpecifier = HotKeySpecifier;
     }
 
@@ -63,7 +63,7 @@ public class CheckBox : View
     }
 
     /// <summary>
-    ///     If <see langword="true"/> allows <see cref="Checked"/> to be null, true or false. If <see langword="false"/>
+    ///     If <see langword="true"/> allows <see cref="Checked"/> to be null, true, or false. If <see langword="false"/>
     ///     only allows <see cref="Checked"/> to be true or false.
     /// </summary>
     public bool AllowNullChecked
@@ -76,7 +76,23 @@ public class CheckBox : View
         }
     }
 
-    /// <summary>The state of the <see cref="CheckBox"/></summary>
+    /// <summary>
+    ///     The state of the <see cref="CheckBox"/>.
+    /// </summary>
+    /// <remarks>
+    ///     <para>
+    ///        If <see langword="null"/> and <see cref="AllowNullChecked"/> is <see langword="true"/>, the <see cref="CheckBox"/>
+    ///        will display the <c>ConfigurationManager.Glyphs.NullChecked</c> character (☒).
+    ///     </para>
+    ///     <para>
+    ///        If <see langword="false"/>, the <see cref="CheckBox"/>
+    ///        will display the <c>ConfigurationManager.Glyphs.UnChecked</c> character (☐).
+    ///     </para>
+    ///     <para>
+    ///        If <see langword="false"/>, the <see cref="CheckBox"/>
+    ///        will display the <c>ConfigurationManager.Glyphs.Checked</c> character (☑).
+    ///     </para>
+    /// </remarks>
     public bool? Checked
     {
         get => _checked;
@@ -99,7 +115,8 @@ public class CheckBox : View
     /// <returns>If <see langword="true"/> the <see cref="Toggled"/> event was canceled.</returns>
     public bool? OnToggled ()
     {
-        CancelEventArgs<bool?> e = new (Checked, false);
+        bool ? oldValue = Checked;
+        CancelEventArgs<bool?> e = new (ref _checked, ref oldValue);
 
         if (AllowNullChecked)
         {

+ 30 - 15
Terminal.Gui/Views/ComboBox.cs

@@ -68,7 +68,7 @@ public class ComboBox : View
 
                      SetNeedsLayout ();
                      SetNeedsDisplay ();
-                     Search_Changed (this, new CancelEventArgs<string> (string.Empty, Text));
+                     ShowHideList (Text);
                  };
 
         // Things this view knows how to do
@@ -185,15 +185,19 @@ public class ComboBox : View
             // Only need to refresh list if its been added to a container view
             if (SuperView is { } && SuperView.Subviews.Contains (this))
             {
-                SelectedItem = -1;
-                _search.Text = string.Empty;
-                Search_Changed (this, new CancelEventArgs<string> (string.Empty, _search.Text));
+                Text = string.Empty;
+//                SelectedItem = -1;
+//                _search.Text = string.Empty;
+//                ResetSearchSet ();
+
+//                HideList ();
+////                ShowHideList (string.Empty);
                 SetNeedsDisplay ();
             }
         }
     }
 
-    /// <summary>The currently selected list item</summary>
+    /// <summary>The text of the currently selected list item</summary>
     public new string Text
     {
         get => _text;
@@ -243,7 +247,7 @@ public class ComboBox : View
     public event EventHandler Expanded;
 
     /// <inheritdoc/>
-    protected internal override bool OnMouseEvent  (MouseEvent me)
+    protected internal override bool OnMouseEvent (MouseEvent me)
     {
         if (me.Position.X == Viewport.Right - 1
             && me.Position.Y == Viewport.Top
@@ -423,12 +427,12 @@ public class ComboBox : View
 
             if (SelectedItem > -1 && _listview.Source?.Count > 0)
             {
-                _search.Text = _text = _listview.Source.ToList () [SelectedItem].ToString ();
+                Text = _listview.Source.ToList () [SelectedItem].ToString ();
             }
         }
         else if (!ReadOnly)
         {
-            _search.Text = _text = "";
+            Text = string.Empty;
             _selectedItem = _lastSelectedItem;
             OnSelectedChanged ();
         }
@@ -660,7 +664,7 @@ public class ComboBox : View
     // Tell TextField to handle Accept Command (Enter)
     void Search_Accept (object sender, HandledEventArgs e) { e.Handled = true; }
 
-    private void Search_Changed (object sender, CancelEventArgs<string> e)
+    private void Search_Changed (object sender, EventArgs e)
     {
         if (_source is null)
         {
@@ -668,13 +672,18 @@ public class ComboBox : View
             return;
         }
 
-        if (string.IsNullOrEmpty (_search.Text) && string.IsNullOrEmpty (e.CurrentValue))
+        ShowHideList (Text);
+    }
+
+    private void ShowHideList (string oldText)
+    {
+        if (string.IsNullOrEmpty (_search.Text) && string.IsNullOrEmpty (oldText))
         {
             ResetSearchSet ();
         }
-        else if (_search.Text != e.CurrentValue)
+        else if (_search.Text != oldText)
         {
-            if (_search.Text.Length < e.CurrentValue.Length)
+            if (_search.Text.Length < oldText.Length)
             {
                 _selectedItem = -1;
             }
@@ -730,7 +739,7 @@ public class ComboBox : View
 
         SetValue (_listview.SelectedItem > -1 ? _searchSet [_listview.SelectedItem] : _text);
         _search.CursorPosition = _search.Text.GetColumns ();
-        Search_Changed (this, new CancelEventArgs<string> (_search.Text, _search.Text));
+        ShowHideList (Text);
         OnOpenSelectedItem ();
         Reset (true);
         HideList ();
@@ -756,7 +765,13 @@ public class ComboBox : View
         _listview.ResumeSuspendCollectionChangedEvent ();
     }
 
-    private void SetSearchText (string value) { _search.Text = _text = value; }
+    // Sets the search text field Text as well as our own Text property
+    private void SetSearchText (string value)
+    {
+//        _text = value;
+        _search.Text = value;
+        _text = value;
+    }
 
     private void SetValue (object text, bool isFromSelectedItem = false)
     {
@@ -813,7 +828,7 @@ public class ComboBox : View
             set => _hideDropdownListOnClick = WantContinuousButtonPressed = value;
         }
 
-        protected internal override bool OnMouseEvent  (MouseEvent me)
+        protected internal override bool OnMouseEvent (MouseEvent me)
         {
             var res = false;
             bool isMousePositionValid = IsMousePositionValid (me);

+ 2 - 2
Terminal.Gui/Views/Label.cs

@@ -31,9 +31,9 @@ public class Label : View
         e.Handled = InvokeCommand (Command.HotKey) == true;
     }
 
-    private void Label_TitleChanged (object sender, CancelEventArgs<string> e)
+    private void Label_TitleChanged (object sender, EventArgs<string> e)
     {
-        base.Text = e.NewValue;
+        base.Text = e.CurrentValue;
         TextFormatter.HotKeySpecifier = HotKeySpecifier;
     }
 

+ 1 - 1
Terminal.Gui/Views/Shortcut.cs

@@ -446,7 +446,7 @@ public class Shortcut : View
     CommandView.Y = 0; //Pos.Center ();
 }
 
-private void Shortcut_TitleChanged (object sender, CancelEventArgs<string> e)
+private void Shortcut_TitleChanged (object sender, EventArgs<string> e)
 {
     // If the Title changes, update the CommandView text.
     // This is a helper to make it easier to set the CommandView text.

+ 4 - 2
Terminal.Gui/Views/TextField.cs

@@ -533,7 +533,7 @@ public class TextField : View
             }
 
             string newText = value.Replace ("\t", "").Split ("\n") [0];
-            CancelEventArgs<string> args = new (oldText, newText);
+            CancelEventArgs<string> args = new (ref oldText, ref newText);
             OnTextChanging (args);
 
             if (args.Cancel)
@@ -547,6 +547,8 @@ public class TextField : View
             }
 
             ClearAllSelection ();
+
+            // Note we use NewValue here; TextChanging subscribers may have changed it
             _text = args.NewValue.EnumerateRunes ().ToList ();
 
             if (!Secret && !_historyText.IsFromHistory)
@@ -563,7 +565,7 @@ public class TextField : View
                                  );
             }
 
-            OnTextChanged (new (oldText, StringExtensions.ToString (_text)));
+            OnTextChanged ();
 
             ProcessAutocomplete ();
 

+ 11 - 11
Terminal.Gui/Views/TextValidateField.cs

@@ -64,8 +64,8 @@ namespace Terminal.Gui
 
             /// <summary>Method that invoke the <see cref="TextChanged"/> event if it's defined.</summary>
             /// <param name="oldValue">The previous text before replaced.</param>
-            /// <returns>Returns the <see cref="CancelEventArgs{T}"/></returns>
-            void OnTextChanged (CancelEventArgs<string> oldValue);
+            /// <returns>Returns the <see cref="EventArgs{T}"/></returns>
+            void OnTextChanged (EventArgs<string> oldValue);
 
             /// <summary>
             ///     Changed event, raised when the text has changed.
@@ -74,7 +74,7 @@ namespace Terminal.Gui
             ///         <see cref="string"/> containing the old value.
             ///     </remarks>
             /// </summary>
-            event EventHandler<CancelEventArgs<string>> TextChanged;
+            event EventHandler<EventArgs<string>> TextChanged;
         }
 
         //////////////////////////////////////////////////////////////////////////////
@@ -125,7 +125,7 @@ namespace Terminal.Gui
             }
 
             /// <inheritdoc/>
-            public event EventHandler<CancelEventArgs<string>> TextChanged;
+            public event EventHandler<EventArgs<string>> TextChanged;
 
             /// <inheritdoc/>
             public string Text
@@ -206,7 +206,7 @@ namespace Terminal.Gui
 
                 if (result)
                 {
-                    OnTextChanged (new CancelEventArgs<string> (oldValue, Text));
+                    OnTextChanged (new EventArgs<string> (ref oldValue));
                 }
 
                 return result;
@@ -220,14 +220,14 @@ namespace Terminal.Gui
 
                 if (result)
                 {
-                    OnTextChanged (new CancelEventArgs<string> (oldValue, Text));
+                    OnTextChanged (new EventArgs<string> (ref oldValue));
                 }
 
                 return result;
             }
 
             /// <inheritdoc/>
-            public void OnTextChanged (CancelEventArgs<string> args) { TextChanged?.Invoke (this, args); }
+            public void OnTextChanged (EventArgs<string> args) { TextChanged?.Invoke (this, args); }
         }
 
         #endregion
@@ -260,7 +260,7 @@ namespace Terminal.Gui
             public bool ValidateOnInput { get; set; } = true;
 
             /// <inheritdoc/>
-            public event EventHandler<CancelEventArgs<string>> TextChanged;
+            public event EventHandler<EventArgs<string>> TextChanged;
 
             /// <inheritdoc/>
             public string Text
@@ -333,7 +333,7 @@ namespace Terminal.Gui
                 {
                     string oldValue = Text;
                     _text.RemoveAt (pos);
-                    OnTextChanged (new CancelEventArgs<string> (oldValue, Text));
+                    OnTextChanged (new EventArgs<string> (oldValue));
                 }
 
                 return true;
@@ -349,7 +349,7 @@ namespace Terminal.Gui
                 {
                     string oldValue = Text;
                     _text.Insert (pos, (Rune)ch);
-                    OnTextChanged (new CancelEventArgs<string> (oldValue, Text));
+                    OnTextChanged (new EventArgs<string> (ref oldValue));
 
                     return true;
                 }
@@ -358,7 +358,7 @@ namespace Terminal.Gui
             }
 
             /// <inheritdoc/>
-            public void OnTextChanged (CancelEventArgs<string> args) { TextChanged?.Invoke (this, args); }
+            public void OnTextChanged (EventArgs<string> args) { TextChanged?.Invoke (this, args); }
 
             /// <summary>Compiles the regex pattern for validation./></summary>
             private void CompileMask () { _regex = new Regex (StringExtensions.ToString (_pattern), RegexOptions.Compiled); }

+ 1 - 2
Terminal.Gui/Views/TextView.cs

@@ -2820,7 +2820,6 @@ public class TextView : View
         }
         set
         {
-            string old = Text;
             ResetPosition ();
             _model.LoadString (value);
 
@@ -2830,7 +2829,7 @@ public class TextView : View
                 _model = _wrapManager.WrapModel (Viewport.Width, out _, out _, out _, out _);
             }
 
-            OnTextChanged (new (old, Text));
+            OnTextChanged ();
             SetNeedsDisplay ();
 
             _historyText.Clear (Text);

+ 3 - 3
Terminal.Gui/Views/Tile.cs

@@ -61,7 +61,7 @@ public class Tile
     /// <param name="newTitle">The new <see cref="Title"/> to be replaced.</param>
     public virtual void OnTitleChanged (string oldTitle, string newTitle)
     {
-        var args = new CancelEventArgs<string> (oldTitle, newTitle);
+        var args = new EventArgs<string> (newTitle);
         TitleChanged?.Invoke (this, args);
     }
 
@@ -74,14 +74,14 @@ public class Tile
     /// <returns><c>true</c> if an event handler cancelled the Title change.</returns>
     public virtual bool OnTitleChanging (string oldTitle, string newTitle)
     {
-        var args = new CancelEventArgs<string> (oldTitle, newTitle);
+        var args = new CancelEventArgs<string> (ref oldTitle, ref newTitle);
         TitleChanging?.Invoke (this, args);
 
         return args.Cancel;
     }
 
     /// <summary>Event fired after the <see cref="Title"/> has been changed.</summary>
-    public event EventHandler<CancelEventArgs<string>> TitleChanged;
+    public event EventHandler<EventArgs<string>> TitleChanged;
 
     /// <summary>
     ///     Event fired when the <see cref="Title"/> is changing.

+ 2 - 2
Terminal.Gui/Views/Wizard/Wizard.cs

@@ -562,11 +562,11 @@ public class Wizard : Dialog
         // gets the first step if CurrentStep == null
     }
 
-    private void Wizard_TitleChanged (object sender, CancelEventArgs<string> e)
+    private void Wizard_TitleChanged (object sender, EventArgs<string> e)
     {
         if (string.IsNullOrEmpty (_wizardTitle))
         {
-            _wizardTitle = e.NewValue;
+            _wizardTitle = e.CurrentValue;
         }
     }
 }

+ 4 - 4
UICatalog/Scenarios/Buttons.cs

@@ -341,7 +341,7 @@ public class Buttons : Scenario
         };
         numericUpDown.ValueChanged += NumericUpDown_ValueChanged;
 
-        void NumericUpDown_ValueChanged (object sender, CancelEventArgs<int> e) { }
+        void NumericUpDown_ValueChanged (object sender, EventArgs<int> e) { }
 
         main.Add (label, numericUpDown);
 
@@ -518,7 +518,7 @@ public class Buttons : Scenario
                 }
 
                 T oldValue = value;
-                CancelEventArgs<T> args = new CancelEventArgs<T> (_value, value);
+                CancelEventArgs<T> args = new (ref _value, ref value);
                 ValueChanging?.Invoke (this, args);
 
                 if (args.Cancel)
@@ -528,7 +528,7 @@ public class Buttons : Scenario
 
                 _value = value;
                 _number.Text = _value.ToString ();
-                ValueChanged?.Invoke (this, new (oldValue, _value));
+                ValueChanged?.Invoke (this, new (ref _value));
             }
         }
 
@@ -542,7 +542,7 @@ public class Buttons : Scenario
         /// Fired when the value has changed.
         /// </summary>
         [CanBeNull]
-        public event EventHandler<CancelEventArgs<T>> ValueChanged;
+        public event EventHandler<EventArgs<T>> ValueChanged;
 
         /// <summary>
         /// The number of digits to display. The <see cref="View.Viewport"/> will be resized to fit this number of characters plus the buttons. The default is 3.

+ 78 - 84
UICatalog/Scenarios/CharacterMap.cs

@@ -77,19 +77,8 @@ public class CharacterMap : Scenario
         };
         top.Add (_errorLabel);
 
-#if TEXT_CHANGED_TO_JUMP
-        jumpEdit.TextChanged += JumpEdit_TextChanged;
-#else
         jumpEdit.Accept += JumpEditOnAccept;
 
-        void JumpEditOnAccept (object sender, HandledEventArgs e)
-        {
-            JumpEdit_TextChanged (sender, new (jumpEdit.Text, jumpEdit.Text));
-
-            // Cancel the event to prevent ENTER from being handled elsewhere
-            e.Handled = true;
-        }
-#endif
         _categoryList = new () { X = Pos.Right (_charMap), Y = Pos.Bottom (jumpLabel), Height = Dim.Fill () };
         _categoryList.FullRowSelect = true;
 
@@ -181,6 +170,83 @@ public class CharacterMap : Scenario
         Application.Run (top);
         top.Dispose ();
         Application.Shutdown ();
+
+        return;
+
+        void JumpEditOnAccept (object sender, HandledEventArgs e)
+        {
+            if (jumpEdit.Text.Length == 0)
+            {
+                return;
+            }
+
+            uint result = 0;
+
+            if (jumpEdit.Text.StartsWith ("U+", StringComparison.OrdinalIgnoreCase) || jumpEdit.Text.StartsWith ("\\u"))
+            {
+                try
+                {
+                    result = uint.Parse (jumpEdit.Text [2..], NumberStyles.HexNumber);
+                }
+                catch (FormatException)
+                {
+                    _errorLabel.Text = "Invalid hex value";
+
+                    return;
+                }
+            }
+            else if (jumpEdit.Text.StartsWith ("0", StringComparison.OrdinalIgnoreCase) || jumpEdit.Text.StartsWith ("\\u"))
+            {
+                try
+                {
+                    result = uint.Parse (jumpEdit.Text, NumberStyles.HexNumber);
+                }
+                catch (FormatException)
+                {
+                    _errorLabel.Text = "Invalid hex value";
+
+                    return;
+                }
+            }
+            else
+            {
+                try
+                {
+                    result = uint.Parse (jumpEdit.Text, NumberStyles.Integer);
+                }
+                catch (FormatException)
+                {
+                    _errorLabel.Text = "Invalid value";
+
+                    return;
+                }
+            }
+
+            if (result > RuneExtensions.MaxUnicodeCodePoint)
+            {
+                _errorLabel.Text = "Beyond maximum codepoint";
+
+                return;
+            }
+
+            _errorLabel.Text = $"U+{result:x5}";
+
+            EnumerableTableSource<UnicodeRange> table = (EnumerableTableSource<UnicodeRange>)_categoryList.Table;
+
+            _categoryList.SelectedRow = table.Data
+                                             .Select ((item, index) => new { item, index })
+                                             .FirstOrDefault (x => x.item.Start <= result && x.item.End >= result)
+                                             ?.index
+                                        ?? -1;
+            _categoryList.EnsureSelectedCellIsVisible ();
+
+            // Ensure the typed glyph is selected 
+            _charMap.SelectedCodePoint = (int)result;
+
+
+            // Cancel the event to prevent ENTER from being handled elsewhere
+            e.Handled = true;
+        }
     }
 
     private void _categoryList_Initialized (object sender, EventArgs e) { _charMap.Width = Dim.Fill () - _categoryList.Width; }
@@ -240,78 +306,6 @@ public class CharacterMap : Scenario
         return item;
     }
 
-    private void JumpEdit_TextChanged (object sender, CancelEventArgs<string> e)
-    {
-        var jumpEdit = sender as TextField;
-
-        if (jumpEdit.Text.Length == 0)
-        {
-            return;
-        }
-
-        uint result = 0;
-
-        if (jumpEdit.Text.StartsWith ("U+", StringComparison.OrdinalIgnoreCase) || jumpEdit.Text.StartsWith ("\\u"))
-        {
-            try
-            {
-                result = uint.Parse (jumpEdit.Text [2..], NumberStyles.HexNumber);
-            }
-            catch (FormatException)
-            {
-                _errorLabel.Text = "Invalid hex value";
-
-                return;
-            }
-        }
-        else if (jumpEdit.Text.StartsWith ("0", StringComparison.OrdinalIgnoreCase) || jumpEdit.Text.StartsWith ("\\u"))
-        {
-            try
-            {
-                result = uint.Parse (jumpEdit.Text, NumberStyles.HexNumber);
-            }
-            catch (FormatException)
-            {
-                _errorLabel.Text = "Invalid hex value";
-
-                return;
-            }
-        }
-        else
-        {
-            try
-            {
-                result = uint.Parse (jumpEdit.Text, NumberStyles.Integer);
-            }
-            catch (FormatException)
-            {
-                _errorLabel.Text = "Invalid value";
-
-                return;
-            }
-        }
-
-        if (result > RuneExtensions.MaxUnicodeCodePoint)
-        {
-            _errorLabel.Text = "Beyond maximum codepoint";
-
-            return;
-        }
-
-        _errorLabel.Text = $"U+{result:x5}";
-
-        EnumerableTableSource<UnicodeRange> table = (EnumerableTableSource<UnicodeRange>)_categoryList.Table;
-
-        _categoryList.SelectedRow = table.Data
-                                         .Select ((item, index) => new { item, index })
-                                         .FirstOrDefault (x => x.item.Start <= result && x.item.End >= result)
-                                         ?.index
-                                    ?? -1;
-        _categoryList.EnsureSelectedCellIsVisible ();
-
-        // Ensure the typed glyph is selected 
-        _charMap.SelectedCodePoint = (int)result;
-    }
 }
 
 internal class CharMap : View
@@ -1005,7 +999,7 @@ internal class CharMap : View
                                                         document.RootElement,
                                                         new
                                                             JsonSerializerOptions
-                                                            { WriteIndented = true }
+                                                        { WriteIndented = true }
                                                        );
             }
 

+ 1 - 1
UICatalog/Scenarios/CsvEditor.cs

@@ -565,7 +565,7 @@ public class CsvEditor : Scenario
         }
     }
 
-    private void SelectedCellLabel_TextChanged (object sender, CancelEventArgs<string> e)
+    private void SelectedCellLabel_TextChanged (object sender, EventArgs e)
     {
         // if user is in the text control and editing the selected cell
         if (!_selectedCellTextField.HasFocus)

+ 3 - 2
UICatalog/Scenarios/ExpanderButton.cs

@@ -133,15 +133,16 @@ public class ExpanderButton : Button
 
     /// <summary>Called when the orientation is changing. Invokes the <see cref="OrientationChanging"/> event.</summary>
     /// <param name="newOrientation"></param>
+    /// <param name="newValue"></param>
     /// <returns>True of the event was cancelled.</returns>
     protected virtual bool OnCollapsedChanging (bool newValue)
     {
-        CancelEventArgs<bool> args = new (Collapsed, newValue);
+        CancelEventArgs<bool> args = new (ref _collapsed, ref newValue);
         CollapsedChanging?.Invoke (this, args);
 
         if (!args.Cancel)
         {
-            _collapsed = newValue;
+            _collapsed = args.NewValue;
 
             ExpandOrCollapse (_collapsed);
 

+ 4 - 4
UnitTests/Application/ApplicationTests.cs

@@ -295,9 +295,9 @@ public class ApplicationTests
 
         return;
 
-        void OnApplicationOnInitializedChanged (object s, CancelEventArgs<bool> a)
+        void OnApplicationOnInitializedChanged (object s, EventArgs<bool> a)
         {
-            if (a.NewValue)
+            if (a.CurrentValue)
             {
                 initialized = true;
             }
@@ -1151,9 +1151,9 @@ public class ApplicationTests
 
         return;
 
-        void OnApplicationOnInitializedChanged (object s, CancelEventArgs<bool> a)
+        void OnApplicationOnInitializedChanged (object s, EventArgs<bool> a)
         {
-            if (a.NewValue)
+            if (a.CurrentValue)
             {
                 Application.Iteration += OnApplicationOnIteration;
                 initialized = true;

+ 3 - 3
UnitTests/Application/KeyboardTests.cs

@@ -129,10 +129,10 @@ public class KeyboardTests
 
         return;
 
-        void OnApplicationOnInitializedChanged (object s, CancelEventArgs<bool> a)
+        void OnApplicationOnInitializedChanged (object s, EventArgs<bool> a)
         {
-            _output.WriteLine ("OnApplicationOnInitializedChanged: {0}", a.NewValue);
-            if (a.NewValue)
+            _output.WriteLine ("OnApplicationOnInitializedChanged: {0}", a.CurrentValue);
+            if (a.CurrentValue)
             {
                 Application.Iteration += OnApplicationOnIteration;
                 initialized = true;

+ 1 - 1
UnitTests/Dialogs/WizardTests.cs

@@ -597,7 +597,7 @@ public class WizardTests ()
         Assert.Equal (string.Empty, r.Title);
 
         var expected = string.Empty;
-        r.TitleChanged += (s, args) => { Assert.Equal (r.Title, args.NewValue); };
+        r.TitleChanged += (s, args) => { Assert.Equal (r.Title, args.CurrentValue); };
 
         expected = "title";
         r.Title = expected;

+ 2 - 2
UnitTests/UICatalog/ScenarioTests.cs

@@ -73,9 +73,9 @@ public class ScenarioTests : TestsAllViews
 
         return;
 
-        void OnApplicationOnInitializedChanged (object s, CancelEventArgs<bool> a)
+        void OnApplicationOnInitializedChanged (object s, EventArgs<bool> a)
         {
-            if (a.NewValue)
+            if (a.CurrentValue)
             {
                 Application.Iteration += OnApplicationOnIteration;
                 initialized = true;

+ 1 - 2
UnitTests/View/Adornment/AdornmentTests.cs

@@ -326,8 +326,7 @@ public class AdornmentTests (ITestOutputHelper output)
         adornment.ThicknessChanged += (s, e) =>
                                       {
                                           raised = true;
-                                          Assert.Equal (Thickness.Empty, e.CurrentValue);
-                                          Assert.Equal (new Thickness (1, 2, 3, 4), e.NewValue);
+                                          Assert.Equal (new Thickness (1, 2, 3, 4), e.CurrentValue);
                                           Assert.Equal (new Thickness (1, 2, 3, 4), adornment.Thickness);
                                       };
         adornment.Thickness = new Thickness (1, 2, 3, 4);

+ 1 - 2
UnitTests/View/TitleTests.cs

@@ -53,8 +53,7 @@ public class TitleTests (ITestOutputHelper output)
 
         r.TitleChanged += (s, args) =>
                           {
-                              Assert.Equal (expectedOld, args.CurrentValue);
-                              Assert.Equal (r.Title, args.NewValue);
+                              Assert.Equal (r.Title, args.CurrentValue);
                           };
 
         expected = "title";

+ 1 - 0
UnitTests/Views/ComboBoxTests.cs

@@ -828,6 +828,7 @@ Three ",
         Assert.Equal ("Tw", cb.Text);
         Assert.False (cb.IsShow);
         cb.SetSource<string> (null);
+        Assert.False (cb.IsShow);
         Assert.False (cb.NewKeyDownEvent (Key.Enter));
         Assert.True (cb.NewKeyDownEvent (Key.F4)); // with no source also expand empty
         Assert.True (cb.IsShow);

+ 9 - 3
UnitTests/Views/TextFieldTests.cs

@@ -429,8 +429,11 @@ public class TextFieldTests (ITestOutputHelper output)
         var oldText = "";
         var tf = new TextField { Width = 10, Text = "-1" };
 
-        tf.TextChanging += (s, e) => newText = e.NewValue;
-        tf.TextChanged += (s, e) => oldText = e.CurrentValue;
+        tf.TextChanging += (s, e) =>
+                           {
+                               newText = e.NewValue;
+                               oldText = e.CurrentValue;
+                           };
 
         var top = new Toplevel ();
         top.Add (tf);
@@ -1191,10 +1194,13 @@ public class TextFieldTests (ITestOutputHelper output)
     [TextFieldTestsAutoInitShutdown]
     public void TextChanged_Event ()
     {
-        _textField.TextChanged += (s, e) => { Assert.Equal ("TAB to jump between text fields.", e.CurrentValue); };
+        bool eventFired = false;
+        _textField.TextChanged += (s, e) => eventFired = true;
 
         _textField.Text = "changed";
+        Assert.True (eventFired);
         Assert.Equal ("changed", _textField.Text);
+
     }
 
     [Fact]