Parcourir la source

Fixes #3189. TextValidateField doesn't show the cursor and doesn't have TextChanged event. (#3190)

* Prefix private fields with underscore and code cleanup.

* Rename to SetInitialProperties and fix a typo.

* Cleaning code and some adjustments.

* Fix default width for view.

* Enable cursor visibility.

* Reduces indentation and remove AutoInitShutdown.

* Add unit test for default Width is always equal to the provider DisplayText.Length.

* Also prevents showing the cursor if position is less than 0.

* Add OnTextChanged method and TextChanged event.

* Remove unnecessary TextChanged.
BDisp il y a 1 an
Parent
commit
a3627aed5e

+ 154 - 89
Terminal.Gui/Views/TextValidateField.cs

@@ -6,12 +6,12 @@
 //
 //
 
 
 using System.Text;
 using System.Text;
-using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.ComponentModel;
 using System.ComponentModel;
 using System.Linq;
 using System.Linq;
 using System.Text.RegularExpressions;
 using System.Text.RegularExpressions;
 using Terminal.Gui.TextValidateProviders;
 using Terminal.Gui.TextValidateProviders;
+using System;
 
 
 namespace Terminal.Gui {
 namespace Terminal.Gui {
 
 
@@ -89,6 +89,22 @@ namespace Terminal.Gui {
 			/// Gets the formatted string for display.
 			/// Gets the formatted string for display.
 			/// </summary>
 			/// </summary>
 			string DisplayText { get; }
 			string DisplayText { get; }
+
+			/// <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="TextChangedEventArgs"/></returns>
+			void OnTextChanged (TextChangedEventArgs oldValue);
+
+			/// <summary>
+			/// Changed event, raised when the text has changed.
+			/// <remarks>
+			/// This event is raised when the <see cref="Text"/> changes.
+			/// The passed <see cref="EventArgs"/> is a <see cref="string"/> containing the old value.
+			/// </remarks>
+			/// </summary>
+			event EventHandler<TextChangedEventArgs> TextChanged;
 		}
 		}
 
 
 		//////////////////////////////////////////////////////////////////////////////
 		//////////////////////////////////////////////////////////////////////////////
@@ -104,7 +120,10 @@ namespace Terminal.Gui {
 		/// <para><a href="https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.maskedtextbox.mask?view=net-5.0">Masking elements</a></para>
 		/// <para><a href="https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.maskedtextbox.mask?view=net-5.0">Masking elements</a></para>
 		/// </summary>
 		/// </summary>
 		public class NetMaskedTextProvider : ITextValidateProvider {
 		public class NetMaskedTextProvider : ITextValidateProvider {
-			MaskedTextProvider provider;
+			MaskedTextProvider _provider;
+
+			/// <inheritdoc/>
+			public event EventHandler<TextChangedEventArgs> TextChanged;
 
 
 			/// <summary>
 			/// <summary>
 			/// Empty Constructor
 			/// Empty Constructor
@@ -119,13 +138,13 @@ namespace Terminal.Gui {
 			/// </summary>
 			/// </summary>
 			public string Mask {
 			public string Mask {
 				get {
 				get {
-					return provider?.Mask;
+					return _provider?.Mask;
 				}
 				}
 				set {
 				set {
-					var current = provider != null ? provider.ToString (false, false) : string.Empty;
-					provider = new MaskedTextProvider (value == string.Empty ? "&&&&&&" : value);
-					if (string.IsNullOrEmpty (current) == false) {
-						provider.Set (current);
+					var current = _provider != null ? _provider.ToString (false, false) : string.Empty;
+					_provider = new MaskedTextProvider (value == string.Empty ? "&&&&&&" : value);
+					if (!string.IsNullOrEmpty (current)) {
+						_provider.Set (current);
 					}
 					}
 				}
 				}
 			}
 			}
@@ -133,32 +152,32 @@ namespace Terminal.Gui {
 			///<inheritdoc/>
 			///<inheritdoc/>
 			public string Text {
 			public string Text {
 				get {
 				get {
-					return provider.ToString ();
+					return _provider.ToString ();
 				}
 				}
 				set {
 				set {
-					provider.Set (value);
+					_provider.Set (value);
 				}
 				}
 			}
 			}
 
 
 			///<inheritdoc/>
 			///<inheritdoc/>
-			public bool IsValid => provider.MaskCompleted;
+			public bool IsValid => _provider.MaskCompleted;
 
 
 			///<inheritdoc/>
 			///<inheritdoc/>
 			public bool Fixed => true;
 			public bool Fixed => true;
 
 
 			///<inheritdoc/>
 			///<inheritdoc/>
-			public string DisplayText => provider.ToDisplayString ();
+			public string DisplayText => _provider.ToDisplayString ();
 
 
 			///<inheritdoc/>
 			///<inheritdoc/>
 			public int Cursor (int pos)
 			public int Cursor (int pos)
 			{
 			{
 				if (pos < 0) {
 				if (pos < 0) {
 					return CursorStart ();
 					return CursorStart ();
-				} else if (pos > provider.Length) {
+				} else if (pos > _provider.Length) {
 					return CursorEnd ();
 					return CursorEnd ();
 				} else {
 				} else {
-					var p = provider.FindEditPositionFrom (pos, false);
-					if (p == -1) p = provider.FindEditPositionFrom (pos, true);
+					var p = _provider.FindEditPositionFrom (pos, false);
+					if (p == -1) p = _provider.FindEditPositionFrom (pos, true);
 					return p;
 					return p;
 				}
 				}
 			}
 			}
@@ -167,45 +186,58 @@ namespace Terminal.Gui {
 			public int CursorStart ()
 			public int CursorStart ()
 			{
 			{
 				return
 				return
-					provider.IsEditPosition (0)
+					_provider.IsEditPosition (0)
 					? 0
 					? 0
-					: provider.FindEditPositionFrom (0, true);
+					: _provider.FindEditPositionFrom (0, true);
 			}
 			}
 
 
 			///<inheritdoc/>
 			///<inheritdoc/>
 			public int CursorEnd ()
 			public int CursorEnd ()
 			{
 			{
 				return
 				return
-					provider.IsEditPosition (provider.Length - 1)
-					? provider.Length - 1
-					: provider.FindEditPositionFrom (provider.Length, false);
+					_provider.IsEditPosition (_provider.Length - 1)
+					? _provider.Length - 1
+					: _provider.FindEditPositionFrom (_provider.Length, false);
 			}
 			}
 
 
 			///<inheritdoc/>
 			///<inheritdoc/>
 			public int CursorLeft (int pos)
 			public int CursorLeft (int pos)
 			{
 			{
-				var c = provider.FindEditPositionFrom (pos - 1, false);
+				var c = _provider.FindEditPositionFrom (pos - 1, false);
 				return c == -1 ? pos : c;
 				return c == -1 ? pos : c;
 			}
 			}
 
 
 			///<inheritdoc/>
 			///<inheritdoc/>
 			public int CursorRight (int pos)
 			public int CursorRight (int pos)
 			{
 			{
-				var c = provider.FindEditPositionFrom (pos + 1, true);
+				var c = _provider.FindEditPositionFrom (pos + 1, true);
 				return c == -1 ? pos : c;
 				return c == -1 ? pos : c;
 			}
 			}
 
 
 			///<inheritdoc/>
 			///<inheritdoc/>
 			public bool Delete (int pos)
 			public bool Delete (int pos)
 			{
 			{
-				return provider.Replace (' ', pos);// .RemoveAt (pos);
+				var oldValue = Text;
+				var result = _provider.Replace (' ', pos);// .RemoveAt (pos);
+				if (result) {
+					OnTextChanged (new TextChangedEventArgs (oldValue));
+				}
+				return result;
 			}
 			}
 
 
 			///<inheritdoc/>
 			///<inheritdoc/>
 			public bool InsertAt (char ch, int pos)
 			public bool InsertAt (char ch, int pos)
 			{
 			{
-				return provider.Replace (ch, pos);
+				var oldValue = Text;
+				var result = _provider.Replace (ch, pos);
+				if (result) {
+					OnTextChanged (new TextChangedEventArgs (oldValue));
+				}
+				return result;
 			}
 			}
+
+			/// <inheritdoc/>
+			public void OnTextChanged (TextChangedEventArgs oldValue) => TextChanged?.Invoke (this, oldValue);
 		}
 		}
 		#endregion
 		#endregion
 
 
@@ -215,9 +247,12 @@ namespace Terminal.Gui {
 		/// Regex Provider for TextValidateField.
 		/// Regex Provider for TextValidateField.
 		/// </summary>
 		/// </summary>
 		public class TextRegexProvider : ITextValidateProvider {
 		public class TextRegexProvider : ITextValidateProvider {
-			Regex regex;
-			List<Rune> text;
-			List<Rune> pattern;
+			Regex _regex;
+			List<Rune> _text;
+			List<Rune> _pattern;
+
+			/// <inheritdoc/>
+			public event EventHandler<TextChangedEventArgs> TextChanged;
 
 
 			/// <summary>
 			/// <summary>
 			/// Empty Constructor.
 			/// Empty Constructor.
@@ -232,10 +267,10 @@ namespace Terminal.Gui {
 			/// </summary>
 			/// </summary>
 			public string Pattern {
 			public string Pattern {
 				get {
 				get {
-					return StringExtensions.ToString (pattern);
+					return StringExtensions.ToString (_pattern);
 				}
 				}
 				set {
 				set {
-					pattern = value.ToRuneList ();
+					_pattern = value.ToRuneList ();
 					CompileMask ();
 					CompileMask ();
 					SetupText ();
 					SetupText ();
 				}
 				}
@@ -244,10 +279,10 @@ namespace Terminal.Gui {
 			///<inheritdoc/>
 			///<inheritdoc/>
 			public string Text {
 			public string Text {
 				get {
 				get {
-					return StringExtensions.ToString (text);
+					return StringExtensions.ToString (_text);
 				}
 				}
 				set {
 				set {
-					text = value != string.Empty ? value.ToRuneList () : null;
+					_text = value != string.Empty ? value.ToRuneList () : null;
 					SetupText ();
 					SetupText ();
 				}
 				}
 			}
 			}
@@ -258,7 +293,7 @@ namespace Terminal.Gui {
 			///<inheritdoc/>
 			///<inheritdoc/>
 			public bool IsValid {
 			public bool IsValid {
 				get {
 				get {
-					return Validate (text);
+					return Validate (_text);
 				}
 				}
 			}
 			}
 
 
@@ -272,7 +307,7 @@ namespace Terminal.Gui {
 
 
 			bool Validate (List<Rune> text)
 			bool Validate (List<Rune> text)
 			{
 			{
-				var match = regex.Match (StringExtensions.ToString (text));
+				var match = _regex.Match (StringExtensions.ToString (text));
 				return match.Success;
 				return match.Success;
 			}
 			}
 
 
@@ -281,7 +316,7 @@ namespace Terminal.Gui {
 			{
 			{
 				if (pos < 0) {
 				if (pos < 0) {
 					return CursorStart ();
 					return CursorStart ();
-				} else if (pos >= text.Count) {
+				} else if (pos >= _text.Count) {
 					return CursorEnd ();
 					return CursorEnd ();
 				} else {
 				} else {
 					return pos;
 					return pos;
@@ -297,7 +332,7 @@ namespace Terminal.Gui {
 			///<inheritdoc/>
 			///<inheritdoc/>
 			public int CursorEnd ()
 			public int CursorEnd ()
 			{
 			{
-				return text.Count;
+				return _text.Count;
 			}
 			}
 
 
 			///<inheritdoc/>
 			///<inheritdoc/>
@@ -312,7 +347,7 @@ namespace Terminal.Gui {
 			///<inheritdoc/>
 			///<inheritdoc/>
 			public int CursorRight (int pos)
 			public int CursorRight (int pos)
 			{
 			{
-				if (pos < text.Count) {
+				if (pos < _text.Count) {
 					return pos + 1;
 					return pos + 1;
 				}
 				}
 				return pos;
 				return pos;
@@ -321,8 +356,10 @@ namespace Terminal.Gui {
 			///<inheritdoc/>
 			///<inheritdoc/>
 			public bool Delete (int pos)
 			public bool Delete (int pos)
 			{
 			{
-				if (text.Count > 0 && pos < text.Count) {
-					text.RemoveAt (pos);
+				if (_text.Count > 0 && pos < _text.Count) {
+					var oldValue = Text;
+					_text.RemoveAt (pos);
+					OnTextChanged (new TextChangedEventArgs (oldValue));
 				}
 				}
 				return true;
 				return true;
 			}
 			}
@@ -330,10 +367,12 @@ namespace Terminal.Gui {
 			///<inheritdoc/>
 			///<inheritdoc/>
 			public bool InsertAt (char ch, int pos)
 			public bool InsertAt (char ch, int pos)
 			{
 			{
-				var aux = text.ToList ();
+				var aux = _text.ToList ();
 				aux.Insert (pos, (Rune)ch);
 				aux.Insert (pos, (Rune)ch);
 				if (Validate (aux) || ValidateOnInput == false) {
 				if (Validate (aux) || ValidateOnInput == false) {
-					text.Insert (pos, (Rune)ch);
+					var oldValue = Text;
+					_text.Insert (pos, (Rune)ch);
+					OnTextChanged (new TextChangedEventArgs (oldValue));
 					return true;
 					return true;
 				}
 				}
 				return false;
 				return false;
@@ -341,11 +380,11 @@ namespace Terminal.Gui {
 
 
 			void SetupText ()
 			void SetupText ()
 			{
 			{
-				if (text != null && IsValid) {
+				if (_text != null && IsValid) {
 					return;
 					return;
 				}
 				}
 
 
-				text = new List<Rune> ();
+				_text = new List<Rune> ();
 			}
 			}
 
 
 			/// <summary>
 			/// <summary>
@@ -353,8 +392,11 @@ namespace Terminal.Gui {
 			/// </summary>
 			/// </summary>
 			private void CompileMask ()
 			private void CompileMask ()
 			{
 			{
-				regex = new Regex (StringExtensions.ToString (pattern), RegexOptions.Compiled);
+				_regex = new Regex (StringExtensions.ToString (_pattern), RegexOptions.Compiled);
 			}
 			}
+
+			/// <inheritdoc/>
+			public void OnTextChanged (TextChangedEventArgs oldValue) => TextChanged?.Invoke (this, oldValue);
 		}
 		}
 		#endregion
 		#endregion
 	}
 	}
@@ -364,15 +406,14 @@ namespace Terminal.Gui {
 	/// </summary>
 	/// </summary>
 	public class TextValidateField : View {
 	public class TextValidateField : View {
 
 
-		ITextValidateProvider provider;
-		int cursorPosition = 0;
+		ITextValidateProvider _provider;
+		int _cursorPosition;
+		int _defaultLength = 10;
 
 
 		/// <summary>
 		/// <summary>
 		/// Initializes a new instance of the <see cref="TextValidateField"/> class using <see cref="LayoutStyle.Computed"/> positioning.
 		/// Initializes a new instance of the <see cref="TextValidateField"/> class using <see cref="LayoutStyle.Computed"/> positioning.
 		/// </summary>
 		/// </summary>
-		public TextValidateField () : this (null)
-		{
-		}
+		public TextValidateField () : this (null) { }
 
 
 		/// <summary>
 		/// <summary>
 		/// Initializes a new instance of the <see cref="TextValidateField"/> class using <see cref="LayoutStyle.Computed"/> positioning.
 		/// Initializes a new instance of the <see cref="TextValidateField"/> class using <see cref="LayoutStyle.Computed"/> positioning.
@@ -383,10 +424,10 @@ namespace Terminal.Gui {
 				Provider = provider;
 				Provider = provider;
 			}
 			}
 
 
-			Initialize ();
+			SetInitialProperties ();
 		}
 		}
 
 
-		void Initialize ()
+		void SetInitialProperties ()
 		{
 		{
 			Height = 1;
 			Height = 1;
 			CanFocus = true;
 			CanFocus = true;
@@ -415,14 +456,14 @@ namespace Terminal.Gui {
 		/// Provider
 		/// Provider
 		/// </summary>
 		/// </summary>
 		public ITextValidateProvider Provider {
 		public ITextValidateProvider Provider {
-			get => provider;
+			get => _provider;
 			set {
 			set {
-				provider = value;
-				if (provider.Fixed == true) {
-					this.Width = provider.DisplayText == string.Empty ? 10 : Text.Length;
+				_provider = value;
+				if (_provider.Fixed) {
+					this.Width = _provider.DisplayText == string.Empty ? _defaultLength : _provider.DisplayText.Length;
 				}
 				}
+				// HomeKeyHandler already call SetNeedsDisplay
 				HomeKeyHandler ();
 				HomeKeyHandler ();
-				SetNeedsDisplay ();
 			}
 			}
 		}
 		}
 
 
@@ -431,11 +472,11 @@ namespace Terminal.Gui {
 		{
 		{
 			if (mouseEvent.Flags.HasFlag (MouseFlags.Button1Pressed)) {
 			if (mouseEvent.Flags.HasFlag (MouseFlags.Button1Pressed)) {
 
 
-				var c = provider.Cursor (mouseEvent.X - GetMargins (Frame.Width).left);
-				if (provider.Fixed == false && TextAlignment == TextAlignment.Right && Text.Length > 0) {
-					c += 1;
+				var c = _provider.Cursor (mouseEvent.X - GetMargins (Bounds.Width).left);
+				if (_provider.Fixed == false && TextAlignment == TextAlignment.Right && Text.Length > 0) {
+					c++;
 				}
 				}
-				cursorPosition = c;
+				_cursorPosition = c;
 				SetFocus ();
 				SetFocus ();
 				SetNeedsDisplay ();
 				SetNeedsDisplay ();
 				return true;
 				return true;
@@ -448,17 +489,17 @@ namespace Terminal.Gui {
 		/// </summary>
 		/// </summary>
 		public new string Text {
 		public new string Text {
 			get {
 			get {
-				if (provider == null) {
+				if (_provider == null) {
 					return string.Empty;
 					return string.Empty;
 				}
 				}
 
 
-				return provider.Text;
+				return _provider.Text;
 			}
 			}
 			set {
 			set {
-				if (provider == null) {
+				if (_provider == null) {
 					return;
 					return;
 				}
 				}
-				provider.Text = value;
+				_provider.Text = value;
 
 
 				SetNeedsDisplay ();
 				SetNeedsDisplay ();
 			}
 			}
@@ -467,15 +508,23 @@ namespace Terminal.Gui {
 		///<inheritdoc/>
 		///<inheritdoc/>
 		public override void PositionCursor ()
 		public override void PositionCursor ()
 		{
 		{
-			var (left, _) = GetMargins (Frame.Width);
+			var (left, _) = GetMargins (Bounds.Width);
 
 
-			// Fixed = true, is for inputs thar have fixed width, like masked ones.
+			// Fixed = true, is for inputs that have fixed width, like masked ones.
 			// Fixed = false, is for normal input.
 			// Fixed = false, is for normal input.
 			// When it's right-aligned and it's a normal input, the cursor behaves differently.
 			// When it's right-aligned and it's a normal input, the cursor behaves differently.
-			if (provider?.Fixed == false && TextAlignment == TextAlignment.Right) {
-				Move (cursorPosition + left - 1, 0);
+			int curPos;
+			if (_provider?.Fixed == false && TextAlignment == TextAlignment.Right) {
+				curPos = _cursorPosition + left - 1;
+				Move (curPos, 0);
+			} else {
+				curPos = _cursorPosition + left;
+				Move (curPos, 0);
+			}
+			if (curPos < 0 || curPos >= Bounds.Width) {
+				Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
 			} else {
 			} else {
-				Move (cursorPosition + left, 0);
+				Application.Driver.SetCursorVisibility (CursorVisibility.Default);
 			}
 			}
 		}
 		}
 
 
@@ -503,7 +552,7 @@ namespace Terminal.Gui {
 		///<inheritdoc/>
 		///<inheritdoc/>
 		public override void OnDrawContent (Rect contentArea)
 		public override void OnDrawContent (Rect contentArea)
 		{
 		{
-			if (provider == null) {
+			if (_provider == null) {
 				Move (0, 0);
 				Move (0, 0);
 				Driver.AddStr ("Error: ITextValidateProvider not set!");
 				Driver.AddStr ("Error: ITextValidateProvider not set!");
 				return;
 				return;
@@ -525,8 +574,8 @@ namespace Terminal.Gui {
 			// Content
 			// Content
 			Driver.SetAttribute (textColor);
 			Driver.SetAttribute (textColor);
 			// Content
 			// Content
-			for (int i = 0; i < provider.DisplayText.Length; i++) {
-				Driver.AddRune ((Rune)provider.DisplayText [i]);
+			for (int i = 0; i < _provider.DisplayText.Length; i++) {
+				Driver.AddRune ((Rune)_provider.DisplayText [i]);
 			}
 			}
 
 
 			// Right Margin
 			// Right Margin
@@ -542,10 +591,10 @@ namespace Terminal.Gui {
 		/// <returns>True if moved.</returns>
 		/// <returns>True if moved.</returns>
 		bool CursorLeft ()
 		bool CursorLeft ()
 		{
 		{
-			var current = cursorPosition;
-			cursorPosition = provider.CursorLeft (cursorPosition);
+			var current = _cursorPosition;
+			_cursorPosition = _provider.CursorLeft (_cursorPosition);
 			SetNeedsDisplay ();
 			SetNeedsDisplay ();
-			return current != cursorPosition;
+			return current != _cursorPosition;
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
@@ -554,10 +603,10 @@ namespace Terminal.Gui {
 		/// <returns>True if moved.</returns>
 		/// <returns>True if moved.</returns>
 		bool CursorRight ()
 		bool CursorRight ()
 		{
 		{
-			var current = cursorPosition;
-			cursorPosition = provider.CursorRight (cursorPosition);
+			var current = _cursorPosition;
+			_cursorPosition = _provider.CursorRight (_cursorPosition);
 			SetNeedsDisplay ();
 			SetNeedsDisplay ();
-			return current != cursorPosition;
+			return current != _cursorPosition;
 		}
 		}
 
 
 		/// <summary>
 		/// <summary>
@@ -566,11 +615,11 @@ namespace Terminal.Gui {
 		/// <returns></returns>
 		/// <returns></returns>
 		bool BackspaceKeyHandler ()
 		bool BackspaceKeyHandler ()
 		{
 		{
-			if (provider.Fixed == false && TextAlignment == TextAlignment.Right && cursorPosition <= 1) {
+			if (_provider.Fixed == false && TextAlignment == TextAlignment.Right && _cursorPosition <= 1) {
 				return false;
 				return false;
 			}
 			}
-			cursorPosition = provider.CursorLeft (cursorPosition);
-			provider.Delete (cursorPosition);
+			_cursorPosition = _provider.CursorLeft (_cursorPosition);
+			_provider.Delete (_cursorPosition);
 			SetNeedsDisplay ();
 			SetNeedsDisplay ();
 			return true;
 			return true;
 		}
 		}
@@ -581,10 +630,10 @@ namespace Terminal.Gui {
 		/// <returns></returns>
 		/// <returns></returns>
 		bool DeleteKeyHandler ()
 		bool DeleteKeyHandler ()
 		{
 		{
-			if (provider.Fixed == false && TextAlignment == TextAlignment.Right) {
-				cursorPosition = provider.CursorLeft (cursorPosition);
+			if (_provider.Fixed == false && TextAlignment == TextAlignment.Right) {
+				_cursorPosition = _provider.CursorLeft (_cursorPosition);
 			}
 			}
-			provider.Delete (cursorPosition);
+			_provider.Delete (_cursorPosition);
 			SetNeedsDisplay ();
 			SetNeedsDisplay ();
 			return true;
 			return true;
 		}
 		}
@@ -595,7 +644,7 @@ namespace Terminal.Gui {
 		/// <returns></returns>
 		/// <returns></returns>
 		bool HomeKeyHandler ()
 		bool HomeKeyHandler ()
 		{
 		{
-			cursorPosition = provider.CursorStart ();
+			_cursorPosition = _provider.CursorStart ();
 			SetNeedsDisplay ();
 			SetNeedsDisplay ();
 			return true;
 			return true;
 		}
 		}
@@ -606,7 +655,7 @@ namespace Terminal.Gui {
 		/// <returns></returns>
 		/// <returns></returns>
 		bool EndKeyHandler ()
 		bool EndKeyHandler ()
 		{
 		{
-			cursorPosition = provider.CursorEnd ();
+			_cursorPosition = _provider.CursorEnd ();
 			SetNeedsDisplay ();
 			SetNeedsDisplay ();
 			return true;
 			return true;
 		}
 		}
@@ -614,17 +663,17 @@ namespace Terminal.Gui {
 		///<inheritdoc/>
 		///<inheritdoc/>
 		public override bool OnProcessKeyDown (Key a)
 		public override bool OnProcessKeyDown (Key a)
 		{
 		{
-			if (provider == null) {
+			if (_provider == null) {
 				return false;
 				return false;
 			}
 			}
 
 
 			if (a.AsRune == default) {
 			if (a.AsRune == default) {
 				return false;
 				return false;
 			}
 			}
-			
+
 			var key = a.AsRune;
 			var key = a.AsRune;
 
 
-			var inserted = provider.InsertAt ((char)key.Value, cursorPosition);
+			var inserted = _provider.InsertAt ((char)key.Value, _cursorPosition);
 
 
 			if (inserted) {
 			if (inserted) {
 				CursorRight ();
 				CursorRight ();
@@ -638,12 +687,28 @@ namespace Terminal.Gui {
 		/// </summary>
 		/// </summary>
 		public virtual bool IsValid {
 		public virtual bool IsValid {
 			get {
 			get {
-				if (provider == null) {
+				if (_provider == null) {
 					return false;
 					return false;
 				}
 				}
 
 
-				return provider.IsValid;
+				return _provider.IsValid;
 			}
 			}
 		}
 		}
+
+		///<inheritdoc/>
+		public override bool OnEnter (View view)
+		{
+			Application.Driver.SetCursorVisibility (CursorVisibility.Default);
+
+			return base.OnEnter (view);
+		}
+
+		///<inheritdoc/>
+		public override bool OnLeave (View view)
+		{
+			Application.Driver.SetCursorVisibility (CursorVisibility.Invisible);
+
+			return base.OnLeave (view);
+		}
 	}
 	}
 }
 }

+ 34 - 12
UICatalog/Scenarios/Text.cs

@@ -7,7 +7,7 @@ using System.Text.RegularExpressions;
 using Terminal.Gui;
 using Terminal.Gui;
 using Terminal.Gui.TextValidateProviders;
 using Terminal.Gui.TextValidateProviders;
 
 
-namespace UICatalog.Scenarios; 
+namespace UICatalog.Scenarios;
 
 
 [ScenarioMetadata ("Text Input Controls", "Tests all text input controls")]
 [ScenarioMetadata ("Text Input Controls", "Tests all text input controls")]
 [ScenarioCategory ("Controls")]
 [ScenarioCategory ("Controls")]
@@ -161,12 +161,12 @@ public class Text : Scenario {
 		};
 		};
 		Win.Add (labelMirroringHexEditor);
 		Win.Add (labelMirroringHexEditor);
 
 
-			var dateField = new DateField (System.DateTime.Now) {
-				X = 1,
-				Y = Pos.Bottom (hexEditor) + 1,
-				Width = 20
-			};
-			Win.Add (dateField);
+		var dateField = new DateField (System.DateTime.Now) {
+			X = 1,
+			Y = Pos.Bottom (hexEditor) + 1,
+			Width = 20
+		};
+		Win.Add (dateField);
 
 
 		var labelMirroringDateField = new Label (dateField.Text) {
 		var labelMirroringDateField = new Label (dateField.Text) {
 			X = Pos.Right (dateField) + 1,
 			X = Pos.Right (dateField) + 1,
@@ -199,21 +199,32 @@ public class Text : Scenario {
 		_timeField.TimeChanged += TimeChanged;
 		_timeField.TimeChanged += TimeChanged;
 
 
 		// MaskedTextProvider - uses .NET MaskedTextProvider
 		// MaskedTextProvider - uses .NET MaskedTextProvider
-		var netProviderLabel = new Label ("NetMaskedTextProvider [ 999 000 LLL >LLL| AAA aaa ]") {
+		var netProviderLabel = new Label ("NetMaskedTextProvider [ 999 000 LLL >LLL |AAA aaa ]") {
 			X = Pos.Left (dateField),
 			X = Pos.Left (dateField),
 			Y = Pos.Bottom (dateField) + 1
 			Y = Pos.Bottom (dateField) + 1
 		};
 		};
 		Win.Add (netProviderLabel);
 		Win.Add (netProviderLabel);
 
 
-		var netProvider = new NetMaskedTextProvider ("999 000 LLL > LLL | AAA aaa");
+		var netProvider = new NetMaskedTextProvider ("999 000 LLL >LLL |AAA aaa");
 
 
 		var netProviderField = new TextValidateField (netProvider) {
 		var netProviderField = new TextValidateField (netProvider) {
 			X = Pos.Right (netProviderLabel) + 1,
 			X = Pos.Right (netProviderLabel) + 1,
 			Y = Pos.Y (netProviderLabel)
 			Y = Pos.Y (netProviderLabel)
 		};
 		};
-
 		Win.Add (netProviderField);
 		Win.Add (netProviderField);
 
 
+		var labelMirroringNetProviderField = new Label (netProviderField.Text) {
+			X = Pos.Right (netProviderField) + 1,
+			Y = Pos.Top (netProviderField),
+			Width = Dim.Width (netProviderField),
+			Height = Dim.Height (netProviderField)
+		};
+		Win.Add (labelMirroringNetProviderField);
+
+		netProviderField.Provider.TextChanged += (s, prev) => {
+			labelMirroringNetProviderField.Text = netProviderField.Text;
+		};
+
 		// TextRegexProvider - Regex provider implemented by Terminal.Gui
 		// TextRegexProvider - Regex provider implemented by Terminal.Gui
 		var regexProvider = new Label ("TextRegexProvider [ ^([0-9]?[0-9]?[0-9]|1000)$ ]") {
 		var regexProvider = new Label ("TextRegexProvider [ ^([0-9]?[0-9]?[0-9]|1000)$ ]") {
 			X = Pos.Left (netProviderLabel),
 			X = Pos.Left (netProviderLabel),
@@ -228,16 +239,27 @@ public class Text : Scenario {
 			Width = 30,
 			Width = 30,
 			TextAlignment = TextAlignment.Centered
 			TextAlignment = TextAlignment.Centered
 		};
 		};
-
 		Win.Add (regexProviderField);
 		Win.Add (regexProviderField);
 
 
+		var labelMirroringRegexProviderField = new Label (regexProviderField.Text) {
+			X = Pos.Right (regexProviderField) + 1,
+			Y = Pos.Top (regexProviderField),
+			Width = Dim.Width (regexProviderField),
+			Height = Dim.Height (regexProviderField)
+		};
+		Win.Add (labelMirroringRegexProviderField);
+
+		regexProviderField.Provider.TextChanged += (s, prev) => {
+			labelMirroringRegexProviderField.Text = regexProviderField.Text;
+		};
+
 		var labelAppendAutocomplete = new Label ("Append Autocomplete:") {
 		var labelAppendAutocomplete = new Label ("Append Autocomplete:") {
 			Y = Pos.Y (regexProviderField) + 2,
 			Y = Pos.Y (regexProviderField) + 2,
 			X = 1
 			X = 1
 		};
 		};
 		var appendAutocompleteTextField = new TextField {
 		var appendAutocompleteTextField = new TextField {
 			X = Pos.Right (labelAppendAutocomplete),
 			X = Pos.Right (labelAppendAutocomplete),
-			Y = Pos.Bottom (labelAppendAutocomplete),
+			Y = Pos.Top (labelAppendAutocomplete),
 			Width = Dim.Fill ()
 			Width = Dim.Fill ()
 		};
 		};
 		appendAutocompleteTextField.Autocomplete = new AppendAutocomplete (appendAutocompleteTextField);
 		appendAutocompleteTextField.Autocomplete = new AppendAutocomplete (appendAutocompleteTextField);

+ 491 - 464
UnitTests/Views/TextValidateFieldTests.cs

@@ -1,568 +1,595 @@
-using System;
-using System.Reflection;
-using System.Text.RegularExpressions;
+using System.Text.RegularExpressions;
 using Terminal.Gui.TextValidateProviders;
 using Terminal.Gui.TextValidateProviders;
 
 
 using Xunit;
 using Xunit;
 
 
-namespace Terminal.Gui.ViewsTests {
+namespace Terminal.Gui.ViewsTests;
 
 
-	// TODO: These tests shouild not rely on AutoInitShutdown / Application
+public class TextValidateField_NET_Provider_Tests {
 
 
-	public class TextValidateField_NET_Provider_Tests {
+	[Fact]
+	public void Initialized_With_Cursor_On_First_Editable_Character ()
+	{
+		//                                                            *
+		//                                                         0123456789
+		var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--")) {
+			TextAlignment = TextAlignment.Centered,
+			Width = 20
+		};
 
 
-		[Fact]
-		[AutoInitShutdown]
-		public void Initialized_With_Cursor_On_First_Editable_Character ()
-		{
-			//                                                            *
-			//                                                         0123456789
-			var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--")) {
-				TextAlignment = TextAlignment.Centered,
-				Width = 20
-			};
+		field.NewKeyDownEvent (new (KeyCode.D1));
 
 
-			field.NewKeyDownEvent (new (KeyCode.D1));
-
-			Assert.Equal ("--(1___)--", field.Provider.DisplayText);
-			Assert.Equal ("--(1   )--", field.Text);
-		}
+		Assert.Equal ("--(1___)--", field.Provider.DisplayText);
+		Assert.Equal ("--(1   )--", field.Text);
+	}
 
 
-		[Fact]
-		[AutoInitShutdown]
-		public void Input_Ilegal_Character ()
-		{
-			//                                                            *
-			//                                                         0123456789
-			var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--")) {
-				TextAlignment = TextAlignment.Centered,
-				Width = 20
-			};
+	[Fact]
+	public void Input_Ilegal_Character ()
+	{
+		//                                                            *
+		//                                                         0123456789
+		var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--")) {
+			TextAlignment = TextAlignment.Centered,
+			Width = 20
+		};
+
+		field.NewKeyDownEvent (new (KeyCode.A));
+
+		Assert.Equal ("--(    )--", field.Text);
+		Assert.Equal ("--(____)--", field.Provider.DisplayText);
+		Assert.False (field.IsValid);
+	}
 
 
-			field.NewKeyDownEvent (new (KeyCode.A));
+	[Fact]
+	public void Home_Key_First_Editable_Character ()
+	{
+		//                                                            *
+		//                                                         0123456789
+		var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--")) {
+			TextAlignment = TextAlignment.Centered,
+			Width = 20
+		};
+
+		field.NewKeyDownEvent (new (KeyCode.CursorRight));
+		field.NewKeyDownEvent (new (KeyCode.CursorRight));
+		field.NewKeyDownEvent (new (KeyCode.Home));
+
+		field.NewKeyDownEvent (new (KeyCode.D1));
+
+		Assert.Equal ("--(1___)--", field.Provider.DisplayText);
+		Assert.Equal ("--(1   )--", field.Text);
+		Assert.False (field.IsValid);
+	}
 
 
-			Assert.Equal ("--(    )--", field.Text);
-			Assert.Equal ("--(____)--", field.Provider.DisplayText);
-			Assert.False (field.IsValid);
-		}
+	[Fact]
+	public void End_Key_Last_Editable_Character ()
+	{
+		//                                                               *
+		//                                                         0123456789
+		var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--")) {
+			TextAlignment = TextAlignment.Centered,
+			Width = 20
+		};
 
 
-		[Fact]
-		[AutoInitShutdown]
-		public void Home_Key_First_Editable_Character ()
-		{
-			//                                                            *
-			//                                                         0123456789
-			var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--")) {
-				TextAlignment = TextAlignment.Centered,
-				Width = 20
-			};
+		field.NewKeyDownEvent (new (KeyCode.End));
 
 
-			field.NewKeyDownEvent (new (KeyCode.CursorRight));
-			field.NewKeyDownEvent (new (KeyCode.CursorRight));
-			field.NewKeyDownEvent (new (KeyCode.Home));
+		field.NewKeyDownEvent (new (KeyCode.D1));
 
 
-			field.NewKeyDownEvent (new (KeyCode.D1));
+		Assert.Equal ("--(___1)--", field.Provider.DisplayText);
+		Assert.Equal ("--(   1)--", field.Text);
+		Assert.False (field.IsValid);
+	}
 
 
-			Assert.Equal ("--(1___)--", field.Provider.DisplayText);
-			Assert.Equal ("--(1   )--", field.Text);
-			Assert.False (field.IsValid);
+	[Fact]
+	public void Right_Key_Stops_In_Last_Editable_Character ()
+	{
+		//                                                               *
+		//                                                         0123456789
+		var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--")) {
+			TextAlignment = TextAlignment.Centered,
+			Width = 20
+		};
+
+		for (int i = 0; i < 10; i++) {
+			field.NewKeyDownEvent (new (KeyCode.CursorRight));
 		}
 		}
+		field.NewKeyDownEvent (new (KeyCode.D1));
 
 
-		[Fact]
-		[AutoInitShutdown]
-		public void End_Key_Last_Editable_Character ()
-		{
-			//                                                               *
-			//                                                         0123456789
-			var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--")) {
-				TextAlignment = TextAlignment.Centered,
-				Width = 20
-			};
-
-			field.NewKeyDownEvent (new (KeyCode.End));
-
-			field.NewKeyDownEvent (new (KeyCode.D1));
+		Assert.Equal ("--(___1)--", field.Provider.DisplayText);
+		Assert.Equal ("--(   1)--", field.Text);
+		Assert.False (field.IsValid);
+	}
 
 
-			Assert.Equal ("--(___1)--", field.Provider.DisplayText);
-			Assert.Equal ("--(   1)--", field.Text);
-			Assert.False (field.IsValid);
+	[Fact]
+	public void Left_Key_Stops_In_First_Editable_Character ()
+	{
+		//                                                            *
+		//                                                         0123456789
+		var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--")) {
+			TextAlignment = TextAlignment.Centered,
+			Width = 20
+		};
+
+		for (int i = 0; i < 10; i++) {
+			field.NewKeyDownEvent (new (KeyCode.CursorLeft));
 		}
 		}
+		field.NewKeyDownEvent (new (KeyCode.D1));
 
 
-		[Fact]
-		[AutoInitShutdown]
-		public void Right_Key_Stops_In_Last_Editable_Character ()
-		{
-			//                                                               *
-			//                                                         0123456789
-			var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--")) {
-				TextAlignment = TextAlignment.Centered,
-				Width = 20
-			};
-
-			for (int i = 0; i < 10; i++) {
-				field.NewKeyDownEvent (new (KeyCode.CursorRight));
-			}
-			field.NewKeyDownEvent (new (KeyCode.D1));
-
-			Assert.Equal ("--(___1)--", field.Provider.DisplayText);
-			Assert.Equal ("--(   1)--", field.Text);
-			Assert.False (field.IsValid);
-		}
+		Assert.Equal ("--(1___)--", field.Provider.DisplayText);
+		Assert.Equal ("--(1   )--", field.Text);
+		Assert.False (field.IsValid);
+	}
 
 
-		[Fact]
-		[AutoInitShutdown]
-		public void Left_Key_Stops_In_First_Editable_Character ()
-		{
-			//                                                            *
-			//                                                         0123456789
-			var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--")) {
-				TextAlignment = TextAlignment.Centered,
-				Width = 20
-			};
+	[Fact]
+	public void When_Valid_Is_Valid_True ()
+	{
+		//                                                            ****
+		//                                                         0123456789
+		var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--")) {
+			TextAlignment = TextAlignment.Centered,
+			Width = 20
+		};
+
+		field.NewKeyDownEvent (new (KeyCode.D1));
+		Assert.Equal ("--(1   )--", field.Text);
+		Assert.False (field.IsValid);
+
+		field.NewKeyDownEvent (new (KeyCode.D2));
+		Assert.Equal ("--(12  )--", field.Text);
+		Assert.False (field.IsValid);
+
+		field.NewKeyDownEvent (new (KeyCode.D3));
+		Assert.Equal ("--(123 )--", field.Text);
+		Assert.False (field.IsValid);
+
+		field.NewKeyDownEvent (new (KeyCode.D4));
+		Assert.Equal ("--(1234)--", field.Text);
+		Assert.True (field.IsValid);
+	}
 
 
-			for (int i = 0; i < 10; i++) {
-				field.NewKeyDownEvent (new (KeyCode.CursorLeft));
-			}
-			field.NewKeyDownEvent (new (KeyCode.D1));
+	[Fact]
+	public void Insert_Skips_Non_Editable_Characters ()
+	{
+		//                                                            ** **
+		//                                                         01234567890
+		var field = new TextValidateField (new NetMaskedTextProvider ("--(00-00)--")) {
+			TextAlignment = TextAlignment.Centered,
+			Width = 20
+		};
+
+		field.NewKeyDownEvent (new (KeyCode.D1));
+		Assert.Equal ("--(1_-__)--", field.Provider.DisplayText);
+		Assert.False (field.IsValid);
+
+		field.NewKeyDownEvent (new (KeyCode.D2));
+		Assert.Equal ("--(12-__)--", field.Provider.DisplayText);
+		Assert.False (field.IsValid);
+
+		field.NewKeyDownEvent (new (KeyCode.D3));
+		Assert.Equal ("--(12-3_)--", field.Provider.DisplayText);
+		Assert.False (field.IsValid);
+
+		field.NewKeyDownEvent (new (KeyCode.D4));
+		Assert.Equal ("--(12-34)--", field.Provider.DisplayText);
+		Assert.True (field.IsValid);
+	}
 
 
-			Assert.Equal ("--(1___)--", field.Provider.DisplayText);
-			Assert.Equal ("--(1   )--", field.Text);
-			Assert.False (field.IsValid);
-		}
+	[Fact]
+	public void Initial_Value_Exact_Valid ()
+	{
+		//                                                            ****
+		//                                                         0123456789
+		var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--") { Text = "1234" }) {
+			TextAlignment = TextAlignment.Centered,
+			Width = 20
+		};
+
+		Assert.Equal ("--(1234)--", field.Text);
+		Assert.True (field.IsValid);
+	}
 
 
-		[Fact]
-		[AutoInitShutdown]
-		public void When_Valid_Is_Valid_True ()
-		{
-			//                                                            ****
-			//                                                         0123456789
-			var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--")) {
-				TextAlignment = TextAlignment.Centered,
-				Width = 20
-			};
+	[Fact]
+	public void Initial_Value_Bigger_Than_Mask_Discarded ()
+	{
+		//                                                            ****
+		//                                                         0123456789
+		var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--") { Text = "12345" }) {
+			TextAlignment = TextAlignment.Centered,
+			Width = 20
+		};
+
+		Assert.Equal ("--(____)--", field.Provider.DisplayText);
+		Assert.Equal ("--(    )--", field.Text);
+		Assert.False (field.IsValid);
+	}
 
 
-			field.NewKeyDownEvent (new (KeyCode.D1));
-			Assert.Equal ("--(1   )--", field.Text);
-			Assert.False (field.IsValid);
+	[Fact]
+	public void Initial_Value_Smaller_Than_Mask_Accepted ()
+	{
+		//                                                            ****
+		//                                                         0123456789
+		var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--") { Text = "123" }) {
+			TextAlignment = TextAlignment.Centered,
+			Width = 20
+		};
+
+		Assert.Equal ("--(123_)--", field.Provider.DisplayText);
+		Assert.Equal ("--(123 )--", field.Text);
+		Assert.False (field.IsValid);
+	}
 
 
-			field.NewKeyDownEvent (new (KeyCode.D2));
-			Assert.Equal ("--(12  )--", field.Text);
-			Assert.False (field.IsValid);
+	[Fact]
+	public void Delete_Key_Doesnt_Move_Cursor ()
+	{
+		//                                                            ****
+		//                                                         0123456789
+		var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--") { Text = "1234" }) {
+			TextAlignment = TextAlignment.Centered,
+			Width = 20
+		};
 
 
-			field.NewKeyDownEvent (new (KeyCode.D3));
-			Assert.Equal ("--(123 )--", field.Text);
-			Assert.False (field.IsValid);
+		Assert.Equal ("--(1234)--", field.Provider.DisplayText);
+		Assert.True (field.IsValid);
 
 
-			field.NewKeyDownEvent (new (KeyCode.D4));
-			Assert.Equal ("--(1234)--", field.Text);
-			Assert.True (field.IsValid);
-		}
+		field.NewKeyDownEvent (new (KeyCode.Delete));
+		field.NewKeyDownEvent (new (KeyCode.Delete));
+		field.NewKeyDownEvent (new (KeyCode.Delete));
 
 
-		[Fact]
-		[AutoInitShutdown]
-		public void Insert_Skips_Non_Editable_Characters ()
-		{
-			//                                                            ** **
-			//                                                         01234567890
-			var field = new TextValidateField (new NetMaskedTextProvider ("--(00-00)--")) {
-				TextAlignment = TextAlignment.Centered,
-				Width = 20
-			};
+		Assert.Equal ("--(_234)--", field.Provider.DisplayText);
+		Assert.False (field.IsValid);
 
 
-			field.NewKeyDownEvent (new (KeyCode.D1));
-			Assert.Equal ("--(1_-__)--", field.Provider.DisplayText);
-			Assert.False (field.IsValid);
+		field.NewKeyDownEvent (new (KeyCode.CursorRight));
+		field.NewKeyDownEvent (new (KeyCode.CursorRight));
 
 
-			field.NewKeyDownEvent (new (KeyCode.D2));
-			Assert.Equal ("--(12-__)--", field.Provider.DisplayText);
-			Assert.False (field.IsValid);
+		field.NewKeyDownEvent (new (KeyCode.Delete));
+		field.NewKeyDownEvent (new (KeyCode.Delete));
+		field.NewKeyDownEvent (new (KeyCode.Delete));
 
 
-			field.NewKeyDownEvent (new (KeyCode.D3));
-			Assert.Equal ("--(12-3_)--", field.Provider.DisplayText);
-			Assert.False (field.IsValid);
+		Assert.Equal ("--(_2_4)--", field.Provider.DisplayText);
+		Assert.False (field.IsValid);
+	}
 
 
-			field.NewKeyDownEvent (new (KeyCode.D4));
-			Assert.Equal ("--(12-34)--", field.Provider.DisplayText);
-			Assert.True (field.IsValid);
-		}
+	[Fact]
+	public void Backspace_Key_Deletes_Previous_Character ()
+	{
+		//                                                            ****
+		//                                                         0123456789
+		var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--") { Text = "1234" }) {
+			TextAlignment = TextAlignment.Centered,
+			Width = 20
+		};
+
+		// Go to the end.
+		field.NewKeyDownEvent (new (KeyCode.End));
+
+		field.NewKeyDownEvent (new (KeyCode.Backspace));
+		Assert.Equal ("--(12_4)--", field.Provider.DisplayText);
+		Assert.False (field.IsValid);
+
+		field.NewKeyDownEvent (new (KeyCode.Backspace));
+		Assert.Equal ("--(1__4)--", field.Provider.DisplayText);
+		Assert.False (field.IsValid);
+
+		field.NewKeyDownEvent (new (KeyCode.Backspace));
+		Assert.Equal ("--(___4)--", field.Provider.DisplayText);
+		Assert.False (field.IsValid);
+
+		// One more
+		field.NewKeyDownEvent (new (KeyCode.Backspace));
+		Assert.Equal ("--(___4)--", field.Provider.DisplayText);
+		Assert.False (field.IsValid);
+	}
 
 
-		[Fact]
-		[AutoInitShutdown]
-		public void Initial_Value_Exact_Valid ()
-		{
-			//                                                            ****
-			//                                                         0123456789
-			var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--") { Text = "1234" }) {
-				TextAlignment = TextAlignment.Centered,
-				Width = 20
-			};
+	[Fact]
+	public void Set_Text_After_Initialization ()
+	{
+		//                                                            ****
+		//                                                         0123456789
+		var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--")) {
+			TextAlignment = TextAlignment.Left,
+			Width = 30
+		};
 
 
-			Assert.Equal ("--(1234)--", field.Text);
-			Assert.True (field.IsValid);
-		}
+		field.Text = "1234";
 
 
-		[Fact]
-		[AutoInitShutdown]
-		public void Initial_Value_Bigger_Than_Mask_Discarded ()
-		{
-			//                                                            ****
-			//                                                         0123456789
-			var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--") { Text = "12345" }) {
-				TextAlignment = TextAlignment.Centered,
-				Width = 20
-			};
+		Assert.Equal ("--(1234)--", field.Text);
+		Assert.True (field.IsValid);
+	}
 
 
-			Assert.Equal ("--(____)--", field.Provider.DisplayText);
-			Assert.Equal ("--(    )--", field.Text);
-			Assert.False (field.IsValid);
-		}
+	[Fact]
+	public void Changing_The_Mask_Tries_To_Keep_The_Previous_Text ()
+	{
+		//                                                            ****
+		//                                                         0123456789
+		var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--")) {
+			TextAlignment = TextAlignment.Left,
+			Width = 30
+		};
+
+		field.Text = "1234";
+		Assert.Equal ("--(1234)--", field.Text);
+		Assert.True (field.IsValid);
+
+		var provider = field.Provider as NetMaskedTextProvider;
+		provider.Mask = "--------(00000000)--------";
+		Assert.Equal ("--------(1234____)--------", field.Provider.DisplayText);
+		Assert.False (field.IsValid);
+	}
 
 
-		[Fact]
-		[AutoInitShutdown]
-		public void Initial_Value_Smaller_Than_Mask_Accepted ()
-		{
-			//                                                            ****
-			//                                                         0123456789
-			var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--") { Text = "123" }) {
-				TextAlignment = TextAlignment.Centered,
-				Width = 20
-			};
+	[Fact]
+	public void MouseClick_Right_X_Greater_Than_Text_Width_Goes_To_Last_Editable_Position ()
+	{
+		//                                                            ****
+		//                                                         0123456789
+		var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--")) {
+			TextAlignment = TextAlignment.Left,
+			Width = 30
+		};
 
 
-			Assert.Equal ("--(123_)--", field.Provider.DisplayText);
-			Assert.Equal ("--(123 )--", field.Text);
-			Assert.False (field.IsValid);
-		}
+		field.NewKeyDownEvent (new (KeyCode.D1));
 
 
-		[Fact]
-		[AutoInitShutdown]
-		public void Delete_Key_Doesnt_Move_Cursor ()
-		{
-			//                                                            ****
-			//                                                         0123456789
-			var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--") { Text = "1234" }) {
-				TextAlignment = TextAlignment.Centered,
-				Width = 20
-			};
+		Assert.Equal ("--(1___)--", field.Provider.DisplayText);
+		Assert.False (field.IsValid);
+		Assert.Equal ("--(1   )--", field.Provider.Text);
 
 
-			Assert.Equal ("--(1234)--", field.Provider.DisplayText);
-			Assert.True (field.IsValid);
+		field.MouseEvent (new MouseEvent () { X = 25, Flags = MouseFlags.Button1Pressed });
 
 
-			field.NewKeyDownEvent (new (KeyCode.Delete));
-			field.NewKeyDownEvent (new (KeyCode.Delete));
-			field.NewKeyDownEvent (new (KeyCode.Delete));
+		field.NewKeyDownEvent (new (KeyCode.D1));
 
 
-			Assert.Equal ("--(_234)--", field.Provider.DisplayText);
-			Assert.False (field.IsValid);
+		Assert.Equal ("--(1__1)--", field.Provider.DisplayText);
+		Assert.False (field.IsValid);
+		Assert.Equal ("--(1  1)--", field.Provider.Text);
+	}
 
 
-			field.NewKeyDownEvent (new (KeyCode.CursorRight));
-			field.NewKeyDownEvent (new (KeyCode.CursorRight));
+	[Fact]
+	public void Default_Width_Is_Always_Equal_To_The_Provider_DisplayText_Length ()
+	{
+		// 9-Digit or space, optional. 0-Digit, required. L-Letter, required.
+		// > Shift up. Converts all characters that follow to uppercase.
+		// | Disable a previous shift up or shift down.
+		// A-Alphanumeric, required. a-Alphanumeric, optional.
+		var field = new TextValidateField (new NetMaskedTextProvider ("999 000 LLL >LLL |AAA aaa"));
+
+		Assert.Equal (field.Bounds.Width, field.Provider.DisplayText.Length);
+		Assert.NotEqual (field.Provider.DisplayText.Length, field.Provider.Text.Length);
+		Assert.Equal (new string (' ', field.Text.Length), field.Provider.Text);
+	}
 
 
-			field.NewKeyDownEvent (new (KeyCode.Delete));
-			field.NewKeyDownEvent (new (KeyCode.Delete));
-			field.NewKeyDownEvent (new (KeyCode.Delete));
+	[Fact]
+	public void OnTextChanged_TextChanged_Event ()
+	{
+		var wasTextChanged = false;
 
 
-			Assert.Equal ("--(_2_4)--", field.Provider.DisplayText);
-			Assert.False (field.IsValid);
-		}
+		var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--")) {
+			TextAlignment = TextAlignment.Left,
+			Width = 30
+		};
 
 
-		[Fact]
-		[AutoInitShutdown]
-		public void Backspace_Key_Deletes_Previous_Character ()
-		{
-			//                                                            ****
-			//                                                         0123456789
-			var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--") { Text = "1234" }) {
-				TextAlignment = TextAlignment.Centered,
-				Width = 20
-			};
+		field.Provider.TextChanged += (sender, e) => wasTextChanged = true;
 
 
-			// Go to the end.
-			field.NewKeyDownEvent (new (KeyCode.End));
+		field.NewKeyDownEvent (new (KeyCode.D1));
 
 
-			field.NewKeyDownEvent (new (KeyCode.Backspace));
-			Assert.Equal ("--(12_4)--", field.Provider.DisplayText);
-			Assert.False (field.IsValid);
+		Assert.Equal ("--(1___)--", field.Provider.DisplayText);
+		Assert.False (field.IsValid);
+		Assert.Equal ("--(1   )--", field.Provider.Text);
+		Assert.True (wasTextChanged);
+	}
+}
 
 
-			field.NewKeyDownEvent (new (KeyCode.Backspace));
-			Assert.Equal ("--(1__4)--", field.Provider.DisplayText);
-			Assert.False (field.IsValid);
+public class TextValidateField_Regex_Provider_Tests {
 
 
-			field.NewKeyDownEvent (new (KeyCode.Backspace));
-			Assert.Equal ("--(___4)--", field.Provider.DisplayText);
-			Assert.False (field.IsValid);
+	[Fact]
+	public void Input_Without_Validate_On_Input ()
+	{
+		var field = new TextValidateField (new TextRegexProvider ("^[0-9][0-9][0-9]$") { ValidateOnInput = false }) {
+			Width = 20
+		};
 
 
-			// One more
-			field.NewKeyDownEvent (new (KeyCode.Backspace));
-			Assert.Equal ("--(___4)--", field.Provider.DisplayText);
-			Assert.False (field.IsValid);
-		}
+		field.NewKeyDownEvent (new (KeyCode.D1));
+		Assert.Equal ("1", field.Text);
+		Assert.False (field.IsValid);
 
 
-		[Fact]
-		[AutoInitShutdown]
-		public void Set_Text_After_Initialization ()
-		{
-			//                                                            ****
-			//                                                         0123456789
-			var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--")) {
-				TextAlignment = TextAlignment.Left,
-				Width = 30
-			};
+		field.NewKeyDownEvent (new (KeyCode.D2));
+		Assert.Equal ("12", field.Text);
+		Assert.False (field.IsValid);
 
 
-			field.Text = "1234";
+		field.NewKeyDownEvent (new (KeyCode.D3));
+		Assert.Equal ("123", field.Text);
+		Assert.True (field.IsValid);
 
 
-			Assert.Equal ("--(1234)--", field.Text);
-			Assert.True (field.IsValid);
-		}
+		field.NewKeyDownEvent (new (KeyCode.D4));
+		Assert.Equal ("1234", field.Text);
+		Assert.False (field.IsValid);
+	}
 
 
-		[Fact]
-		[AutoInitShutdown]
-		public void Changing_The_Mask_Tries_To_Keep_The_Previous_Text ()
-		{
-			//                                                            ****
-			//                                                         0123456789
-			var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--")) {
-				TextAlignment = TextAlignment.Left,
-				Width = 30
-			};
+	[Fact]
+	public void Input_With_Validate_On_Input_Set_Text ()
+	{
+		var field = new TextValidateField (new TextRegexProvider ("^[0-9][0-9][0-9]$")) {
+			Width = 20
+		};
+
+		// Input dosen't validates the pattern.
+		field.NewKeyDownEvent (new (KeyCode.D1));
+		Assert.Equal ("", field.Text);
+		Assert.False (field.IsValid);
+
+		// Dosen't match
+		field.Text = "12356";
+		Assert.Equal ("", field.Text);
+		Assert.False (field.IsValid);
+
+		// Yes.
+		field.Text = "123";
+		Assert.Equal ("123", field.Text);
+		Assert.True (field.IsValid);
+	}
 
 
-			field.Text = "1234";
-			Assert.Equal ("--(1234)--", field.Text);
-			Assert.True (field.IsValid);
+	[Fact]
+	public void Text_With_All_Charset ()
+	{
+		var field = new TextValidateField (new TextRegexProvider ("^[0-9][0-9][0-9]$")) {
+			Width = 20
+		};
 
 
-			var provider = field.Provider as NetMaskedTextProvider;
-			provider.Mask = "--------(00000000)--------";
-			Assert.Equal ("--------(1234____)--------", field.Provider.DisplayText);
-			Assert.False (field.IsValid);
+		var text = "";
+		for (int i = 0; i < 255; i++) {
+			text += (char)i;
 		}
 		}
 
 
-		[Fact]
-		[AutoInitShutdown]
-		public void MouseClick_Right_X_Greater_Than_Text_Width_Goes_To_Last_Editable_Position ()
-		{
-			//                                                            ****
-			//                                                         0123456789
-			var field = new TextValidateField (new NetMaskedTextProvider ("--(0000)--")) {
-				TextAlignment = TextAlignment.Left,
-				Width = 30
-			};
-
-			field.NewKeyDownEvent (new (KeyCode.D1));
+		field.Text = text;
 
 
-			Assert.Equal ("--(1___)--", field.Provider.DisplayText);
-			Assert.False (field.IsValid);
-
-			field.MouseEvent (new MouseEvent () { X = 25, Flags = MouseFlags.Button1Pressed });
+		Assert.False (field.IsValid);
+	}
 
 
-			field.NewKeyDownEvent (new (KeyCode.D1));
+	[Fact]
+	public void Mask_With_Invalid_Pattern_Exception ()
+	{
+		// Regex Exception
+		// Maybe it's not the right behaviour.
 
 
-			Assert.Equal ("--(1__1)--", field.Provider.DisplayText);
-			Assert.False (field.IsValid);
+		var mask = "";
+		for (int i = 0; i < 255; i++) {
+			mask += (char)i;
 		}
 		}
-	}
-
-	public class TextValidateField_Regex_Provider_Tests {
 
 
-		[Fact]
-		[AutoInitShutdown]
-		public void Input_Without_Validate_On_Input ()
-		{
-			var field = new TextValidateField (new TextRegexProvider ("^[0-9][0-9][0-9]$") { ValidateOnInput = false }) {
+		try {
+			var field = new TextValidateField (new TextRegexProvider (mask)) {
 				Width = 20
 				Width = 20
 			};
 			};
-
-			field.NewKeyDownEvent (new (KeyCode.D1));
-			Assert.Equal ("1", field.Text);
-			Assert.False (field.IsValid);
-
-			field.NewKeyDownEvent (new (KeyCode.D2));
-			Assert.Equal ("12", field.Text);
-			Assert.False (field.IsValid);
-
-			field.NewKeyDownEvent (new (KeyCode.D3));
-			Assert.Equal ("123", field.Text);
-			Assert.True (field.IsValid);
-
-			field.NewKeyDownEvent (new (KeyCode.D4));
-			Assert.Equal ("1234", field.Text);
-			Assert.False (field.IsValid);
+		} catch (RegexParseException ex) {
+			Assert.True (true, ex.Message);
+			return;
 		}
 		}
+		Assert.True (false);
+	}
 
 
-		[Fact]
-		[AutoInitShutdown]
-		public void Input_With_Validate_On_Input_Set_Text ()
-		{
-			var field = new TextValidateField (new TextRegexProvider ("^[0-9][0-9][0-9]$")) {
-				Width = 20
-			};
+	[Fact]
+	public void Home_Key_First_Editable_Character ()
+	{
+		// Range 0 to 1000
+		// Accepts 001 too.
+		var field = new TextValidateField (new TextRegexProvider ("^[0-9]?[0-9]?[0-9]|1000$")) {
+			Width = 20
+		};
 
 
-			// Input dosen't validates the pattern.
-			field.NewKeyDownEvent (new (KeyCode.D1));
-			Assert.Equal ("", field.Text);
-			Assert.False (field.IsValid);
+		field.NewKeyDownEvent (new (KeyCode.D1));
+		field.NewKeyDownEvent (new (KeyCode.D0));
+		field.NewKeyDownEvent (new (KeyCode.D0));
+		field.NewKeyDownEvent (new (KeyCode.D0));
 
 
-			// Dosen't match
-			field.Text = "12356";
-			Assert.Equal ("", field.Text);
-			Assert.False (field.IsValid);
+		Assert.Equal ("1000", field.Text);
+		Assert.True (field.IsValid);
 
 
-			// Yes.
-			field.Text = "123";
-			Assert.Equal ("123", field.Text);
-			Assert.True (field.IsValid);
-		}
+		// HOME KEY
+		field.NewKeyDownEvent (new (KeyCode.Home));
 
 
-		[Fact]
-		[AutoInitShutdown]
-		public void Text_With_All_Charset ()
-		{
-			var field = new TextValidateField (new TextRegexProvider ("^[0-9][0-9][0-9]$")) {
-				Width = 20
-			};
+		// DELETE
+		field.NewKeyDownEvent (new (KeyCode.Delete));
 
 
-			var text = "";
-			for (int i = 0; i < 255; i++) {
-				text += (char)i;
-			}
+		Assert.Equal ("000", field.Text);
+		Assert.True (field.IsValid);
+	}
 
 
-			field.Text = text;
+	[Fact]
+	public void End_Key_End_Of_Input ()
+	{
+		// Exactly 5 numbers
+		var field = new TextValidateField (new TextRegexProvider ("^[0-9]{5}$") { ValidateOnInput = false }) {
+			Width = 20
+		};
 
 
-			Assert.False (field.IsValid);
+		for (int i = 0; i < 4; i++) {
+			field.NewKeyDownEvent (new (KeyCode.D0));
 		}
 		}
 
 
-		[Fact]
-		[AutoInitShutdown]
-		public void Mask_With_Invalid_Pattern_Exception ()
-		{
-			// Regex Exception
-			// Maybe it's not the right behaviour.
-
-			var mask = "";
-			for (int i = 0; i < 255; i++) {
-				mask += (char)i;
-			}
-
-			try {
-				var field = new TextValidateField (new TextRegexProvider (mask)) {
-					Width = 20
-				};
-			} catch (RegexParseException ex) {
-				Assert.True (true, ex.Message);
-				return;
-			}
-			Assert.True (false);
-		}
+		Assert.Equal ("0000", field.Text);
+		Assert.False (field.IsValid);
 
 
-		[Fact]
-		[AutoInitShutdown]
-		public void Home_Key_First_Editable_Character ()
-		{
-			// Range 0 to 1000
-			// Accepts 001 too.
-			var field = new TextValidateField (new TextRegexProvider ("^[0-9]?[0-9]?[0-9]|1000$")) {
-				Width = 20
-			};
+		// HOME KEY
+		field.NewKeyDownEvent (new (KeyCode.Home));
 
 
-			field.NewKeyDownEvent (new (KeyCode.D1));
-			field.NewKeyDownEvent (new (KeyCode.D0));
-			field.NewKeyDownEvent (new (KeyCode.D0));
-			field.NewKeyDownEvent (new (KeyCode.D0));
+		// END KEY
+		field.NewKeyDownEvent (new (KeyCode.End));
 
 
-			Assert.Equal ("1000", field.Text);
-			Assert.True (field.IsValid);
+		// Insert 9
+		field.NewKeyDownEvent (new (KeyCode.D9));
 
 
-			// HOME KEY
-			field.NewKeyDownEvent (new (KeyCode.Home));
+		Assert.Equal ("00009", field.Text);
+		Assert.True (field.IsValid);
 
 
-			// DELETE
-			field.NewKeyDownEvent (new (KeyCode.Delete));
+		// Insert 9
+		field.NewKeyDownEvent (new (KeyCode.D9));
 
 
-			Assert.Equal ("000", field.Text);
-			Assert.True (field.IsValid);
-		}
+		Assert.Equal ("000099", field.Text);
+		Assert.False (field.IsValid);
+	}
 
 
-		[Fact]
-		[AutoInitShutdown]
-		public void End_Key_End_Of_Input ()
-		{
-			// Exactly 5 numbers
-			var field = new TextValidateField (new TextRegexProvider ("^[0-9]{5}$") { ValidateOnInput = false }) {
-				Width = 20
-			};
+	[Fact]
+	public void Right_Key_Stops_At_End_And_Insert ()
+	{
+		var field = new TextValidateField (new TextRegexProvider ("^[0-9][0-9][0-9]$") { ValidateOnInput = false }) {
+			TextAlignment = TextAlignment.Centered,
+			Width = 20
+		};
 
 
-			for (int i = 0; i < 4; i++) {
-				field.NewKeyDownEvent (new (KeyCode.D0));
-			}
+		field.Text = "123";
 
 
-			Assert.Equal ("0000", field.Text);
-			Assert.False (field.IsValid);
+		for (int i = 0; i < 10; i++) {
+			field.NewKeyDownEvent (new (KeyCode.CursorRight));
+		}
 
 
-			// HOME KEY
-			field.NewKeyDownEvent (new (KeyCode.Home));
+		Assert.Equal ("123", field.Text);
+		Assert.True (field.IsValid);
 
 
-			// END KEY
-			field.NewKeyDownEvent (new (KeyCode.End));
+		// Insert 4
+		field.NewKeyDownEvent (new (KeyCode.D4));
 
 
-			// Insert 9
-			field.NewKeyDownEvent (new (KeyCode.D9));
+		Assert.Equal ("1234", field.Text);
+		Assert.False (field.IsValid);
+	}
 
 
-			Assert.Equal ("00009", field.Text);
-			Assert.True (field.IsValid);
+	[Fact]
+	public void Left_Key_Stops_At_Start_And_Insert ()
+	{
+		var field = new TextValidateField (new TextRegexProvider ("^[0-9][0-9][0-9]$") { ValidateOnInput = false }) {
+			TextAlignment = TextAlignment.Centered,
+			Width = 20
+		};
 
 
-			// Insert 9
-			field.NewKeyDownEvent (new (KeyCode.D9));
+		field.Text = "123";
 
 
-			Assert.Equal ("000099", field.Text);
-			Assert.False (field.IsValid);
+		for (int i = 0; i < 10; i++) {
+			field.NewKeyDownEvent (new (KeyCode.CursorLeft));
 		}
 		}
 
 
-		[Fact]
-		[AutoInitShutdown]
-		public void Right_Key_Stops_At_End_And_Insert ()
-		{
-			var field = new TextValidateField (new TextRegexProvider ("^[0-9][0-9][0-9]$") { ValidateOnInput = false }) {
-				TextAlignment = TextAlignment.Centered,
-				Width = 20
-			};
-
-			field.Text = "123";
-
-			for (int i = 0; i < 10; i++) {
-				field.NewKeyDownEvent (new (KeyCode.CursorRight));
-			}
+		Assert.Equal ("123", field.Text);
+		Assert.True (field.IsValid);
 
 
-			Assert.Equal ("123", field.Text);
-			Assert.True (field.IsValid);
+		// Insert 4
+		field.NewKeyDownEvent (new (KeyCode.D4));
 
 
-			// Insert 4
-			field.NewKeyDownEvent (new (KeyCode.D4));
-
-			Assert.Equal ("1234", field.Text);
-			Assert.False (field.IsValid);
-		}
-
-		[Fact]
-		[AutoInitShutdown]
-		public void Left_Key_Stops_At_Start_And_Insert ()
-		{
-			var field = new TextValidateField (new TextRegexProvider ("^[0-9][0-9][0-9]$") { ValidateOnInput = false }) {
-				TextAlignment = TextAlignment.Centered,
-				Width = 20
-			};
+		Assert.Equal ("4123", field.Text);
+		Assert.False (field.IsValid);
+	}
 
 
-			field.Text = "123";
+	[Fact]
+	public void OnTextChanged_TextChanged_Event ()
+	{
+		var wasTextChanged = false;
 
 
-			for (int i = 0; i < 10; i++) {
-				field.NewKeyDownEvent (new (KeyCode.CursorLeft));
-			}
+		var field = new TextValidateField (new TextRegexProvider ("^[0-9][0-9][0-9]$") { ValidateOnInput = false }) {
+			TextAlignment = TextAlignment.Centered,
+			Width = 20
+		};
 
 
-			Assert.Equal ("123", field.Text);
-			Assert.True (field.IsValid);
+		field.Provider.TextChanged += (sender, e) => wasTextChanged = true;
 
 
-			// Insert 4
-			field.NewKeyDownEvent (new (KeyCode.D4));
+		field.NewKeyDownEvent (new (KeyCode.D1));
 
 
-			Assert.Equal ("4123", field.Text);
-			Assert.False (field.IsValid);
-		}
+		Assert.Equal ("1", field.Provider.DisplayText);
+		Assert.False (field.IsValid);
+		Assert.Equal ("1", field.Provider.Text);
+		Assert.True (wasTextChanged);
 	}
 	}
 }
 }