浏览代码

Fixes #2465 - Simplify/Enforce LayoutStyle.Absolute when X, Y, Width, and/or Height are null or Absolute() (#2467)

* Merged v2_develop; updated API docs

* Code cleanup

* Fixed code that was using Dim/Pos before IsInit

* Fixed ComboBox using Bounds before IsInitalized and grabbing focus when it shouldn't

* Fixed ComboBox tests. Fixed FileDialog

* Fixed all !IsInitalized warnings

* Fixed AllviewsTester

* Fixed CharMap scenario

* Fixed ColorPicker (hack)

* Fixed CoputedLayout and Csv Editor

* Imrpoved warning

* Fixed more warnings

* Fixed GetTextFormatterSizeNeededForTextAndHotKey

* Fixed AllViewsTester

* AllViewsTester code cleanup

* AllViewsTester code cleanup

* AllViewsTester fixed for realz

* Decided Fill was better than Percent for default
Tig 1 年之前
父节点
当前提交
bc41d9bc09
共有 32 个文件被更改,包括 3430 次插入3414 次删除
  1. 129 57
      Terminal.Gui/View/Layout/ViewLayout.cs
  2. 438 451
      Terminal.Gui/View/View.cs
  3. 448 440
      Terminal.Gui/View/ViewDrawing.cs
  4. 3 2
      Terminal.Gui/View/ViewSubViews.cs
  5. 212 216
      Terminal.Gui/View/ViewText.cs
  6. 6 2
      Terminal.Gui/Views/ColorPicker.cs
  7. 682 710
      Terminal.Gui/Views/ComboBox.cs
  8. 5 2
      Terminal.Gui/Views/FileDialog.cs
  9. 4 2
      Terminal.Gui/Views/TabView.cs
  10. 3 0
      Terminal.Gui/Views/TextField.cs
  11. 1 0
      UICatalog/Scenarios/ASCIICustomButton.cs
  12. 354 385
      UICatalog/Scenarios/AllViewsTester.cs
  13. 25 25
      UICatalog/Scenarios/CharacterMap.cs
  14. 0 1
      UICatalog/Scenarios/ClassExplorer.cs
  15. 1 0
      UICatalog/Scenarios/ColorPicker.cs
  16. 11 3
      UICatalog/Scenarios/ComputedLayout.cs
  17. 420 419
      UICatalog/Scenarios/CsvEditor.cs
  18. 0 1
      UICatalog/Scenarios/GraphViewExample.cs
  19. 0 1
      UICatalog/Scenarios/InteractiveTree.cs
  20. 0 1
      UICatalog/Scenarios/LineViewExample.cs
  21. 0 1
      UICatalog/Scenarios/ListColumns.cs
  22. 0 1
      UICatalog/Scenarios/MultiColouredTable.cs
  23. 1 2
      UICatalog/Scenarios/Notepad.cs
  24. 0 1
      UICatalog/Scenarios/ProcessTable.cs
  25. 5 5
      UICatalog/Scenarios/Progress.cs
  26. 3 1
      UICatalog/Scenarios/Sliders.cs
  27. 0 1
      UICatalog/Scenarios/TabViewExample.cs
  28. 1 2
      UICatalog/Scenarios/TableEditor.cs
  29. 0 1
      UICatalog/Scenarios/TreeUseCases.cs
  30. 334 336
      UICatalog/Scenarios/TreeViewFileSystem.cs
  31. 337 345
      UnitTests/View/Layout/AbsoluteLayoutTests.cs
  32. 7 0
      UnitTests/Views/ComboBoxTests.cs

+ 129 - 57
Terminal.Gui/View/Layout/ViewLayout.cs

@@ -30,22 +30,31 @@ public partial class View {
 	Rect _frame;
 
 	/// <summary>
-	/// Gets or sets the frame for the view. The frame is relative to the <see cref="SuperView"/>'s <see cref="Bounds"/>.
+	/// Gets or sets location and size of the view. The frame is relative to the <see cref="SuperView"/>'s <see cref="Bounds"/>.
 	/// </summary>
-	/// <value>The frame.</value>
+	/// <value>The rectangle describing the location and size of the view, in coordinates relative to the <see cref="SuperView"/>.</value>
 	/// <remarks>
 	/// <para>
-	///    Change the Frame when using the <see cref="Terminal.Gui.LayoutStyle.Absolute"/> layout style to move or resize views. 
+	/// Change the Frame when using the <see cref="LayoutStyle.Absolute"/> layout style to move or resize views.
 	/// </para>
 	/// <para>
-	///    Altering the Frame of a view will trigger the redrawing of the
-	///    view as well as the redrawing of the affected regions of the <see cref="SuperView"/>.
+	/// Altering the Frame will change <see cref="LayoutStyle"/> to <see cref="LayoutStyle.Absolute"/>.
+	/// Additionally, <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> will be set
+	/// to the values of the Frame (using <see cref="Pos.PosAbsolute"/> and <see cref="Dim.DimAbsolute"/>).
+	/// </para>
+	/// <para>
+	/// Altering the Frame will eventually (when the view is next drawn) cause the <see cref="LayoutSubview(View, Rect)"/>
+	/// and <see cref="OnDrawContent(Rect)"/> methods to be called.
 	/// </para>
 	/// </remarks>
 	public virtual Rect Frame {
 		get => _frame;
 		set {
 			_frame = new Rect (value.X, value.Y, Math.Max (value.Width, 0), Math.Max (value.Height, 0));
+			//X = _frame.X;
+			//Y = _frame.Y;
+			//Width = _frame.Width;
+			//Height = _frame.Height;
 			if (IsInitialized || LayoutStyle == LayoutStyle.Absolute) {
 				LayoutFrames ();
 				TextFormatter.Size = GetTextFormatterSizeNeededForTextAndHotKey ();
@@ -161,7 +170,7 @@ public partial class View {
 	/// Helper to get the X and Y offset of the Bounds from the Frame. This is the sum of the Left and Top properties of
 	/// <see cref="Margin"/>, <see cref="Border"/> and <see cref="Padding"/>.
 	/// </summary>
-	public Point GetBoundsOffset () => new Point (Padding?.Thickness.GetInside (Padding.Frame).X ?? 0, Padding?.Thickness.GetInside (Padding.Frame).Y ?? 0);
+	public Point GetBoundsOffset () => new (Padding?.Thickness.GetInside (Padding.Frame).X ?? 0, Padding?.Thickness.GetInside (Padding.Frame).Y ?? 0);
 
 	/// <summary>
 	/// Creates the view's <see cref="Frame"/> objects. This internal method is overridden by Frame to do nothing
@@ -171,7 +180,9 @@ public partial class View {
 	{
 		void ThicknessChangedHandler (object sender, EventArgs e)
 		{
-			LayoutFrames ();
+			if (IsInitialized) {
+				LayoutFrames ();
+			}
 			SetNeedsLayout ();
 			SetNeedsDisplay ();
 		}
@@ -207,41 +218,74 @@ public partial class View {
 
 	/// <summary>
 	/// Controls how the View's <see cref="Frame"/> is computed during <see cref="LayoutSubviews"/>. If the style is set to
-	/// <see cref="LayoutStyle.Absolute"/>, 
-	/// LayoutSubviews does not change the <see cref="Frame"/>. If the style is <see cref="LayoutStyle.Computed"/>
-	/// the <see cref="Frame"/> is updated using
+	/// <see cref="LayoutStyle.Absolute"/>, LayoutSubviews does not change the <see cref="Frame"/>.
+	/// If the style is <see cref="LayoutStyle.Computed"/> the <see cref="Frame"/> is updated using
 	/// the <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> properties.
 	/// </summary>
+	/// <remarks>
+	/// <para>
+	/// Setting this property to <see cref="LayoutStyle.Absolute"/> will cause <see cref="Frame"/> to determine the
+	/// size and position of the view. <see cref="X"/> and <see cref="Y"/> will be set to <see cref="Dim.DimAbsolute"/> using <see cref="Frame"/>.
+	/// </para>
+	/// <para>
+	/// Setting this property to <see cref="LayoutStyle.Computed"/> will cause the view to use the <see cref="LayoutSubviews"/> method to 
+	/// size and position of the view. If either of the <see cref="X"/> and <see cref="Y"/> properties are `null` they will be set to <see cref="Pos.PosAbsolute"/> using
+	/// the current value of <see cref="Frame"/>. 
+	/// If either of the <see cref="Width"/> and <see cref="Height"/> properties are `null` they will be set to <see cref="Dim.DimAbsolute"/> using <see cref="Frame"/>.
+	/// </para>
+	/// </remarks>
 	/// <value>The layout style.</value>
 	public LayoutStyle LayoutStyle {
-		get => _layoutStyle;
+		get {
+			return _layoutStyle;
+			//if ((X == null || X is Pos.PosAbsolute) && (Y == null || Y is Pos.PosAbsolute) &&
+			//(Width == null || Width is Dim.DimAbsolute) && (Height == null || Height is Dim.DimAbsolute)) {
+			//	return LayoutStyle.Absolute;
+			//} else {
+			//	return LayoutStyle.Computed;
+			//}
+		}
 		set {
 			_layoutStyle = value;
+			//switch (_layoutStyle) {
+			//case LayoutStyle.Absolute:
+			//	X = Frame.X;
+			//	Y = Frame.Y;
+			//	Width = Frame.Width;
+			//	Height = Frame.Height;
+			//	break;
+
+			//case LayoutStyle.Computed:
+			//	X ??= Frame.X;
+			//	Y ??= Frame.Y;
+			//	Width ??= Frame.Width;
+			//	Height ??= Frame.Height;
+			//	break;
+			//}
 			SetNeedsLayout ();
 		}
 	}
 
 	/// <summary>
-	/// The view's content area.
-	/// <para>
-	/// SubViews are positioned relative to Bounds.
-	/// </para>
+	/// The bounds represent the View-relative rectangle used for this view; the area inside of the view where subviews and content are presented.
+	/// </summary>
+	/// <value>The rectangle describing the location and size of the area where the views' subviews and content are drawn.</value>
+	/// <remarks>
 	/// <para>
-	/// Drawing is clipped to Bounds (<see cref="Draw()"/> clips drawing to Bounds.<see cref="Rect.Size">Size</see>).
+	/// If <see cref="LayoutStyle"/> is <see cref="LayoutStyle.Computed"/> the value of Bounds is indeterminate until the 
+	/// view has been initialized (<see creft="IsInitialized"/> is true) and <see cref="LayoutSubviews"/> has been called.
 	/// </para>
 	/// <para>
-	/// Mouse events are reported relative to Bounds.
+	/// Updates to the Bounds updates <see cref="Frame"/>, and has the same side effects as updating the <see cref="Frame"/>.
 	/// </para>
-	/// </summary>
-	/// <value>The view's content area.</value>
-	/// <remarks>
 	/// <para>
-	/// The <see cref="Rect.Location"/> of Bounds is always (0, 0). To obtain the offset of the Bounds from the Frame use 
-	/// <see cref="GetBoundsOffset"/>.
+	/// Altering the Bounds will eventually (when the view is next drawn) cause the <see cref="LayoutSubview(View, Rect)"/>
+	/// and <see cref="OnDrawContent(Rect)"/> methods to be called.
 	/// </para>
 	/// <para>
-	/// When using <see cref="LayoutStyle.Computed"/>, Bounds is not valid until after the view has been initialized (after <see cref="EndInit"/> has been called and <see cref="Initialized"/>
-	/// has fired). Accessing this property before the view is initialized is considered an error./>
+	/// Because <see cref="Bounds"/> coordinates are relative to the upper-left corner of the <see cref="View"/>, 
+	/// the coordinates of the upper-left corner of the rectangle returned by this property are (0,0). 
+	/// Use this property to obtain the size of the area of the view for tasks such as drawing the view's contents.
 	/// </para>
 	/// </remarks>
 	public virtual Rect Bounds {
@@ -249,7 +293,6 @@ public partial class View {
 #if DEBUG
 			if (LayoutStyle == LayoutStyle.Computed && !IsInitialized) {
 				Debug.WriteLine ($"WARNING: Bounds is being accessed before the View has been initialized. This is likely a bug in {this}");
-				Debug.WriteLine ($"The Frame is set before the View has been initialized. So it isn't a bug.Is by design.");
 			}
 #endif // DEBUG
 			//var frameRelativeBounds = Padding?.Thickness.GetInside (Padding.Frame) ?? new Rect (default, Frame.Size);
@@ -280,19 +323,28 @@ public partial class View {
 	Pos _x, _y;
 
 	/// <summary>
-	/// Gets or sets the X position for the view (the column). Only used if the <see cref="LayoutStyle"/> is <see cref="Terminal.Gui.LayoutStyle.Computed"/>.
+	/// Gets or sets the X position for the view (the column). 
 	/// </summary>
-	/// <value>The X Position.</value>
+	/// <value>The <see cref="Pos"/> object representing the X position.</value>
 	/// <remarks>
 	/// <para>
-	/// If <see cref="LayoutStyle"/> is <see cref="Terminal.Gui.LayoutStyle.Absolute"/> changing this property has no effect and its value is indeterminate.
+	/// If <see cref="LayoutStyle"/> is <see cref="LayoutStyle.Computed"/> the value is indeterminate until the 
+	/// view has been initialized (<see creft="IsInitialized"/> is true) and <see cref="LayoutSubviews"/> has been called.
+	/// </para>
+	/// <para>
+	/// Changing this property will eventually (when the view is next drawn) cause the <see cref="LayoutSubview(View, Rect)"/> and
+	/// <see cref="OnDrawContent(Rect)"/> methods to be called.
+	/// </para>
+	/// <para>
+	/// If <see cref="LayoutStyle"/> is <see cref="LayoutStyle.Absolute"/> changing this property will cause the <see cref="Frame"/> to be updated. If 
+	/// the new value is not of type <see cref="Pos.PosAbsolute"/> the <see cref="LayoutStyle"/> will change to <see cref="LayoutStyle.Computed"/>.
 	/// </para>
 	/// <para>
 	/// <see langword="null"/> is the same as <c>Pos.Absolute(0)</c>.
 	/// </para>
 	/// </remarks>
 	public Pos X {
-		get => VerifyIsInitialized (_x);
+		get => VerifyIsInitialized (_x, nameof(X));
 		set {
 			// BUGBUG: null is the sames a Pos.Absolute(0). Should we be explicit and set it?
 
@@ -306,21 +358,29 @@ public partial class View {
 		}
 	}
 
-
 	/// <summary>
-	/// Gets or sets the Y position for the view (the row). Only used if the <see cref="LayoutStyle"/> is <see cref="Terminal.Gui.LayoutStyle.Computed"/>.
+	/// Gets or sets the Y position for the view (the row). 
 	/// </summary>
-	/// <value>The X Position.</value>
+	/// <value>The <see cref="Pos"/> object representing the Y position.</value>
 	/// <remarks>
 	/// <para>
-	/// If <see cref="LayoutStyle"/> is <see cref="Terminal.Gui.LayoutStyle.Absolute"/> changing this property has no effect and its value is indeterminate.
+	/// If <see cref="LayoutStyle"/> is <see cref="LayoutStyle.Computed"/> the value is indeterminate until the 
+	/// view has been initialized (<see creft="IsInitialized"/> is true) and <see cref="LayoutSubviews"/> has been called.
+	/// </para>
+	/// <para>
+	/// Changing this property will eventually (when the view is next drawn) cause the <see cref="LayoutSubview(View, Rect)"/> and
+	/// <see cref="OnDrawContent(Rect)"/> methods to be called.
+	/// </para>
+	/// <para>
+	/// If <see cref="LayoutStyle"/> is <see cref="LayoutStyle.Absolute"/> changing this property will cause the <see cref="Frame"/> to be updated. If 
+	/// the new value is not of type <see cref="Pos.PosAbsolute"/> the <see cref="LayoutStyle"/> will change to <see cref="LayoutStyle.Computed"/>.
 	/// </para>
 	/// <para>
 	/// <see langword="null"/> is the same as <c>Pos.Absolute(0)</c>.
 	/// </para>
 	/// </remarks>
 	public Pos Y {
-		get => VerifyIsInitialized (_y);
+		get => VerifyIsInitialized (_y, nameof(Y));
 		set {
 			// BUGBUG: null is the sames a Pos.Absolute(0). Should we be explicit and set it?
 
@@ -333,23 +393,29 @@ public partial class View {
 			OnResizeNeeded ();
 		}
 	}
+
 	Dim _width, _height;
 
 	/// <summary>
-	/// Gets or sets the width of the view. Only used when <see cref="LayoutStyle"/> is <see cref="Terminal.Gui.LayoutStyle.Computed"/>.
+	/// Gets or sets the width of the view. 
 	/// </summary>
-	/// <value>The width.</value>
+	/// <value>The <see cref="Dim"/> object representing the width of the view (the number of columns).</value>
 	/// <remarks>
 	/// <para>
-	/// If <see cref="LayoutStyle"/> is <see cref="Terminal.Gui.LayoutStyle.Absolute"/> changing this property
-	/// has no effect and its value is indeterminate. 
+	/// If <see cref="LayoutStyle"/> is <see cref="LayoutStyle.Computed"/> the value is indeterminate until the 
+	/// view has been initialized (<see creft="IsInitialized"/> is true) and <see cref="LayoutSubviews"/> has been called.
 	/// </para>
 	/// <para>
-	/// <see langword="null"/> is the same as <c>Dim.Fill (0)</c>.
+	/// Changing this property will eventually (when the view is next drawn) cause the <see cref="LayoutSubview(View, Rect)"/>
+	/// and <see cref="OnDrawContent(Rect)"/> methods to be called.
+	/// </para>
+	/// <para>
+	/// If <see cref="LayoutStyle"/> is <see cref="LayoutStyle.Absolute"/> changing this property will cause the <see cref="Frame"/> to be updated. If 
+	/// the new value is not of type <see cref="Dim.DimAbsolute"/> the <see cref="LayoutStyle"/> will change to <see cref="LayoutStyle.Computed"/>.
 	/// </para>
 	/// </remarks>
 	public Dim Width {
-		get => VerifyIsInitialized (_width);
+		get => VerifyIsInitialized (_width, nameof (Width));
 		set {
 			// BUGBUG: null is the sames a Dim.Fill(0). Should we be explicit and set it?
 			if (ValidatePosDim) {
@@ -372,20 +438,25 @@ public partial class View {
 	}
 
 	/// <summary>
-	/// Gets or sets the height of the view. Only used when <see cref="LayoutStyle"/> is <see cref="Terminal.Gui.LayoutStyle.Computed"/>.
+	/// Gets or sets the height of the view. 
 	/// </summary>
-	/// <value>The width.</value>
+	/// <value>The <see cref="Dim"/> object representing the height of the view (the number of rows).</value>
 	/// <remarks>
 	/// <para>
-	/// If <see cref="LayoutStyle"/> is <see cref="Terminal.Gui.LayoutStyle.Absolute"/> changing this property
-	/// has no effect and its value is indeterminate. 
+	/// If <see cref="LayoutStyle"/> is <see cref="LayoutStyle.Computed"/> the value is indeterminate until the 
+	/// view has been initialized (<see creft="IsInitialized"/> is true) and <see cref="LayoutSubviews"/> has been called.
 	/// </para>
 	/// <para>
-	/// <see langword="null"/> is the same as <c>Dim.Fill (0)</c>.
+	/// Changing this property will eventually (when the view is next drawn) cause the <see cref="LayoutSubview(View, Rect)"/>
+	/// and <see cref="OnDrawContent(Rect)"/> methods to be called.
+	/// </para>
+	/// <para>
+	/// If <see cref="LayoutStyle"/> is <see cref="LayoutStyle.Absolute"/> changing this property will cause the <see cref="Frame"/> to be updated. If 
+	/// the new value is not of type <see cref="Dim.DimAbsolute"/> the <see cref="LayoutStyle"/> will change to <see cref="LayoutStyle.Computed"/>.
 	/// </para>
 	/// </remarks>
 	public Dim Height {
-		get => VerifyIsInitialized (_height);
+		get => VerifyIsInitialized (_height, nameof (Height));
 		set {
 			// BUGBUG: null is the sames a Dim.Fill(0). Should we be explicit and set it?
 			if (ValidatePosDim) {
@@ -408,22 +479,22 @@ public partial class View {
 	}
 
 	// Diagnostics to highlight when X or Y is read before the view has been initialized
-	Pos VerifyIsInitialized (Pos pos)
+	Pos VerifyIsInitialized (Pos pos, string member)
 	{
 #if DEBUG
 		if (LayoutStyle == LayoutStyle.Computed && !IsInitialized) {
-			Debug.WriteLine ($"WARNING: \"{this}\" has not been initialized; position is indeterminate {pos}. This is likely a bug.");
+			Debug.WriteLine ($"WARNING: \"{this}\" has not been initialized; {member} is indeterminate {pos}. This is potentially a bug.");
 		}
 #endif // DEBUG
 		return pos;
 	}
 
 	// Diagnostics to highlight when Width or Height is read before the view has been initialized
-	Dim VerifyIsInitialized (Dim dim)
+	Dim VerifyIsInitialized (Dim dim, string member)
 	{
 #if DEBUG
 		if (LayoutStyle == LayoutStyle.Computed && !IsInitialized) {
-			Debug.WriteLine ($"WARNING: \"{this}\" has not been initialized; dimension is indeterminate: {dim}. This is likely a bug.");
+			Debug.WriteLine ($"WARNING: \"{this}\" has not been initialized; {member} is indeterminate: {dim}. This is potentially a bug.");
 		}
 #endif // DEBUG		
 		return dim;
@@ -658,7 +729,7 @@ public partial class View {
 					newDimension = d.Anchor (dimension);
 					newDimension = AutoSize && autosize > newDimension ? autosize : newDimension;
 					break;
-					
+
 				case Dim.DimFill:
 				default:
 					newDimension = Math.Max (d.Anchor (dimension - location), 0);
@@ -803,7 +874,7 @@ public partial class View {
 		// BUGBUG: This should really only work on initialized subviews
 		foreach (var v in from.InternalSubviews /*.Where(v => v.IsInitialized)*/) {
 			nNodes.Add (v);
-			if (v._layoutStyle != LayoutStyle.Computed) {
+			if (v.LayoutStyle != LayoutStyle.Computed) {
 				continue;
 			}
 			CollectPos (v.X, v, ref nNodes, ref nEdges);
@@ -896,7 +967,6 @@ public partial class View {
 			Margin.Width = Frame.Size.Width;
 			Margin.Height = Frame.Size.Height;
 			Margin.SetNeedsLayout ();
-			Margin.LayoutSubviews ();
 			Margin.SetNeedsDisplay ();
 		}
 
@@ -908,7 +978,6 @@ public partial class View {
 			Border.Width = border.Size.Width;
 			Border.Height = border.Size.Height;
 			Border.SetNeedsLayout ();
-			Border.LayoutSubviews ();
 			Border.SetNeedsDisplay ();
 		}
 
@@ -920,7 +989,6 @@ public partial class View {
 			Padding.Width = padding.Size.Width;
 			Padding.Height = padding.Size.Height;
 			Padding.SetNeedsLayout ();
-			Padding.LayoutSubviews ();
 			Padding.SetNeedsDisplay ();
 		}
 	}
@@ -930,7 +998,13 @@ public partial class View {
 	/// response to the container view or terminal resizing.
 	/// </summary>
 	/// <remarks>
+	/// <para>
+	/// The position and dimensions of the view are indeterminate until the view has been initialized. Therefore,
+	/// the behavior of this method is indeterminate if <see cref="IsInitialized"/> is <see langword="false"/>.
+	/// </para>
+	/// <para>
 	/// Raises the <see cref="LayoutComplete"/> event) before it returns.
+	/// </para>
 	/// </remarks>
 	public virtual void LayoutSubviews ()
 	{
@@ -1027,8 +1101,6 @@ public partial class View {
 				Width = newFrameSize.Width;
 			}
 		}
-		// BUGBUG: This call may be redundant
-		TextFormatter.Size = GetTextFormatterSizeNeededForTextAndHotKey ();
 		return boundsChanged;
 	}
 

+ 438 - 451
Terminal.Gui/View/View.cs

@@ -1,527 +1,514 @@
 using System;
-using System.Collections.Generic;
 using System.ComponentModel;
-using System.Linq;
-using System.Text;
 
-namespace Terminal.Gui {
-	#region API Docs
+namespace Terminal.Gui;
+
+#region API Docs
+/// <summary>
+/// View is the base class for all views on the screen and represents a visible element that can render itself and 
+/// contains zero or more nested views, called SubViews. View provides basic functionality for layout, positioning,
+/// and drawing. In addition, View provides keyboard and mouse event handling.
+/// </summary>
+/// <remarks>
+/// <list type="table">
+///	<listheader>
+///	<term>Term</term><description>Definition</description>
+///	</listheader>
+///	<item>
+///	<term>SubView</term><description>A View that is contained in another view and will be rendered as part of the containing view's ContentArea. 
+/// SubViews are added to another view via the <see cref="View.Add(View)"/>` method. A View may only be a SubView of a single View. </description>
+///	</item>
+///	<item>
+///		<term>SuperView</term><description>The View that is a container for SubViews.</description>
+///	</item>
+/// </list>
+/// <para>
+/// Focus is a concept that is used to describe which View is currently receiving user input. Only Views that are
+/// <see cref="Enabled"/>, <see cref="Visible"/>, and <see cref="CanFocus"/> will receive focus.
+/// </para>
+/// <para>
+///    Views that are focusable should implement the <see cref="PositionCursor"/> to make sure that
+///    the cursor is placed in a location that makes sense. Unix terminals do not have
+///    a way of hiding the cursor, so it can be distracting to have the cursor left at
+///    the last focused view. So views should make sure that they place the cursor
+///    in a visually sensible place.
+/// </para>
+/// <para>
+///    The View defines the base functionality for user interface elements in Terminal.Gui. Views
+///    can contain one or more subviews, can respond to user input and render themselves on the screen.
+/// </para>
+/// <para>
+///    Views supports two layout styles: <see cref="LayoutStyle.Absolute"/> or <see cref="LayoutStyle.Computed"/>. 
+///    The choice as to which layout style is used by the View 
+///    is determined when the View is initialized. To create a View using Absolute layout, call a constructor that takes a
+///    Rect parameter to specify the absolute position and size (the View.<see cref="View.Frame "/>). To create a View 
+///    using Computed layout use a constructor that does not take a Rect parameter and set the X, Y, Width and Height 
+///    properties on the view. Both approaches use coordinates that are relative to the container they are being added to. 
+/// </para>
+/// <para>
+///    To switch between Absolute and Computed layout, use the <see cref="LayoutStyle"/> property. 
+/// </para>
+/// <para>
+///    Computed layout is more flexible and supports dynamic console apps where controls adjust layout
+///    as the terminal resizes or other Views change size or position. The X, Y, Width and Height 
+///    properties are Dim and Pos objects that dynamically update the position of a view.
+///    The X and Y properties are of type <see cref="Pos"/>
+///    and you can use either absolute positions, percentages or anchor
+///    points. The Width and Height properties are of type
+///    <see cref="Dim"/> and can use absolute position,
+///    percentages and anchors. These are useful as they will take
+///    care of repositioning views when view's frames are resized or
+///    if the terminal size changes.
+/// </para>
+/// <para>
+///    Absolute layout requires specifying coordinates and sizes of Views explicitly, and the
+///    View will typically stay in a fixed position and size. To change the position and size use the
+///    <see cref="Frame"/> property.
+/// </para>
+/// <para>
+///    Subviews (child views) can be added to a View by calling the <see cref="Add(View)"/> method. 
+///    The container of a View can be accessed with the <see cref="SuperView"/> property.
+/// </para>
+/// <para>
+///    To flag a region of the View's <see cref="Bounds"/> to be redrawn call <see cref="SetNeedsDisplay(Rect)"/>. 
+///    To flag the entire view for redraw call <see cref="SetNeedsDisplay()"/>.
+/// </para>
+/// <para>
+///    The <see cref="LayoutSubviews"/> method is invoked when the size or layout of a view has
+///    changed. The default processing system will keep the size and dimensions
+///    for views that use the <see cref="LayoutStyle.Absolute"/>, and will recompute the
+///    frames for the vies that use <see cref="LayoutStyle.Computed"/>.
+/// </para>
+/// <para>
+///    Views have a <see cref="ColorScheme"/> property that defines the default colors that subviews
+///    should use for rendering. This ensures that the views fit in the context where
+///    they are being used, and allows for themes to be plugged in. For example, the
+///    default colors for windows and Toplevels uses a blue background, while it uses
+///    a white background for dialog boxes and a red background for errors.
+/// </para>
+/// <para>
+///    Subclasses should not rely on <see cref="ColorScheme"/> being
+///    set at construction time. If a <see cref="ColorScheme"/> is not set on a view, the view will inherit the
+///    value from its <see cref="SuperView"/> and the value might only be valid once a view has been
+///    added to a SuperView. 
+/// </para>
+/// <para>
+///    By using  <see cref="ColorScheme"/> applications will work both
+///    in color as well as black and white displays.
+/// </para>
+/// <para>
+///     Views can also opt-in to more sophisticated initialization
+///     by implementing overrides to <see cref="ISupportInitialize.BeginInit"/> and
+///     <see cref="ISupportInitialize.EndInit"/> which will be called
+///     when the view is added to a <see cref="SuperView"/>. 
+/// </para>
+/// <para>
+///     If first-run-only initialization is preferred, overrides to <see cref="ISupportInitializeNotification"/>
+///     can be implemented, in which case the <see cref="ISupportInitialize"/>
+///     methods will only be called if <see cref="ISupportInitializeNotification.IsInitialized"/>
+///     is <see langword="false"/>. This allows proper <see cref="View"/> inheritance hierarchies
+///     to override base class layout code optimally by doing so only on first run,
+///     instead of on every run.
+///   </para>
+/// <para>
+///	See <see href="../docs/keyboard.md">for an overview of View keyboard handling.</see>
+/// </para>	/// </remarks>
+#endregion API Docs
+
+public partial class View : Responder, ISupportInitializeNotification {
+	#region Constructors and Initialization
 	/// <summary>
-	/// View is the base class for all views on the screen and represents a visible element that can render itself and 
-	/// contains zero or more nested views, called SubViews. View provides basic functionality for layout, positioning,
-	/// and drawing. In addition, View provides keyboard and mouse event handling.
+	/// Initializes a new instance of a <see cref="Terminal.Gui.LayoutStyle.Absolute"/> <see cref="View"/> class with the absolute
+	/// dimensions specified in the <paramref name="frame"/> parameter. 
+	/// </summary>
+	/// <param name="frame">The region covered by this view.</param>
+	/// <remarks>
+	/// This constructor initialize a View with a <see cref="LayoutStyle"/> of <see cref="Terminal.Gui.LayoutStyle.Absolute"/>.
+	/// Use <see cref="View"/> to initialize a View with  <see cref="LayoutStyle"/> of <see cref="Terminal.Gui.LayoutStyle.Computed"/> 
+	/// </remarks>
+	public View (Rect frame) : this (frame, null) { }
+
+	/// <summary>
+	///   Initializes a new instance of <see cref="View"/> using <see cref="Terminal.Gui.LayoutStyle.Computed"/> layout.
 	/// </summary>
 	/// <remarks>
-	/// <list type="table">
-	///	<listheader>
-	///	<term>Term</term><description>Definition</description>
-	///	</listheader>
-	///	<item>
-	///	<term>SubView</term><description>A View that is contained in another view and will be rendered as part of the containing view's ContentArea. 
-	/// SubViews are added to another view via the <see cref="View.Add(View)"/>` method. A View may only be a SubView of a single View. </description>
-	///	</item>
-	///	<item>
-	///		<term>SuperView</term><description>The View that is a container for SubViews.</description>
-	///	</item>
-	/// </list>
-	/// <para>
-	/// Focus is a concept that is used to describe which View is currently receiving user input. Only Views that are
-	/// <see cref="Enabled"/>, <see cref="Visible"/>, and <see cref="CanFocus"/> will receive focus.
-	/// </para>
-	/// <para>
-	///    Views that are focusable should implement the <see cref="PositionCursor"/> to make sure that
-	///    the cursor is placed in a location that makes sense. Unix terminals do not have
-	///    a way of hiding the cursor, so it can be distracting to have the cursor left at
-	///    the last focused view. So views should make sure that they place the cursor
-	///    in a visually sensible place.
-	/// </para>
-	/// <para>
-	///    The View defines the base functionality for user interface elements in Terminal.Gui. Views
-	///    can contain one or more subviews, can respond to user input and render themselves on the screen.
-	/// </para>
 	/// <para>
-	///    Views supports two layout styles: <see cref="LayoutStyle.Absolute"/> or <see cref="LayoutStyle.Computed"/>. 
-	///    The choice as to which layout style is used by the View 
-	///    is determined when the View is initialized. To create a View using Absolute layout, call a constructor that takes a
-	///    Rect parameter to specify the absolute position and size (the View.<see cref="View.Frame "/>). To create a View 
-	///    using Computed layout use a constructor that does not take a Rect parameter and set the X, Y, Width and Height 
-	///    properties on the view. Both approaches use coordinates that are relative to the container they are being added to. 
+	///   Use <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> properties to dynamically control the size and location of the view.
+	///   The <see cref="View"/> will be created using <see cref="Terminal.Gui.LayoutStyle.Computed"/>
+	///   coordinates. The initial size (<see cref="View.Frame"/>) will be 
+	///   adjusted to fit the contents of <see cref="Text"/>, including newlines ('\n') for multiple lines. 
 	/// </para>
 	/// <para>
-	///    To switch between Absolute and Computed layout, use the <see cref="LayoutStyle"/> property. 
+	///   If <see cref="Height"/> is greater than one, word wrapping is provided.
 	/// </para>
 	/// <para>
-	///    Computed layout is more flexible and supports dynamic console apps where controls adjust layout
-	///    as the terminal resizes or other Views change size or position. The X, Y, Width and Height 
-	///    properties are Dim and Pos objects that dynamically update the position of a view.
-	///    The X and Y properties are of type <see cref="Pos"/>
-	///    and you can use either absolute positions, percentages or anchor
-	///    points. The Width and Height properties are of type
-	///    <see cref="Dim"/> and can use absolute position,
-	///    percentages and anchors. These are useful as they will take
-	///    care of repositioning views when view's frames are resized or
-	///    if the terminal size changes.
+	///   This constructor initialize a View with a <see cref="LayoutStyle"/> of <see cref="Terminal.Gui.LayoutStyle.Computed"/>. 
+	///   Use <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> properties to dynamically control the size and location of the view.
 	/// </para>
+	/// </remarks>
+	public View () : this (string.Empty, TextDirection.LeftRight_TopBottom) { }
+
+	/// <summary>
+	///   Initializes a new instance of <see cref="View"/> using <see cref="Terminal.Gui.LayoutStyle.Absolute"/> layout.
+	/// </summary>
+	/// <remarks>
 	/// <para>
-	///    Absolute layout requires specifying coordinates and sizes of Views explicitly, and the
-	///    View will typically stay in a fixed position and size. To change the position and size use the
-	///    <see cref="Frame"/> property.
+	///   The <see cref="View"/> will be created at the given
+	///   coordinates with the given string. The size (<see cref="View.Frame"/>) will be 
+	///   adjusted to fit the contents of <see cref="Text"/>, including newlines ('\n') for multiple lines. 
 	/// </para>
 	/// <para>
-	///    Subviews (child views) can be added to a View by calling the <see cref="Add(View)"/> method. 
-	///    The container of a View can be accessed with the <see cref="SuperView"/> property.
+	///   No line wrapping is provided.
 	/// </para>
+	/// </remarks>
+	/// <param name="x">column to locate the View.</param>
+	/// <param name="y">row to locate the View.</param>
+	/// <param name="text">text to initialize the <see cref="Text"/> property with.</param>
+	public View (int x, int y, string text) : this (TextFormatter.CalcRect (x, y, text), text) { }
+
+	/// <summary>
+	///   Initializes a new instance of <see cref="View"/> using <see cref="Terminal.Gui.LayoutStyle.Absolute"/> layout.
+	/// </summary>
+	/// <remarks>
 	/// <para>
-	///    To flag a region of the View's <see cref="Bounds"/> to be redrawn call <see cref="SetNeedsDisplay(Rect)"/>. 
-	///    To flag the entire view for redraw call <see cref="SetNeedsDisplay()"/>.
+	///   The <see cref="View"/> will be created at the given
+	///   coordinates with the given string. The initial size (<see cref="View.Frame"/>) will be 
+	///   adjusted to fit the contents of <see cref="Text"/>, including newlines ('\n') for multiple lines. 
 	/// </para>
 	/// <para>
-	///    The <see cref="LayoutSubviews"/> method is invoked when the size or layout of a view has
-	///    changed. The default processing system will keep the size and dimensions
-	///    for views that use the <see cref="LayoutStyle.Absolute"/>, and will recompute the
-	///    frames for the vies that use <see cref="LayoutStyle.Computed"/>.
+	///   If <c>rect.Height</c> is greater than one, word wrapping is provided.
 	/// </para>
+	/// </remarks>
+	/// <param name="rect">Location.</param>
+	/// <param name="text">text to initialize the <see cref="Text"/> property with.</param>
+	public View (Rect rect, string text) => SetInitialProperties (text, rect, LayoutStyle.Absolute, TextDirection.LeftRight_TopBottom);
+
+	/// <summary>
+	///   Initializes a new instance of <see cref="View"/> using <see cref="Terminal.Gui.LayoutStyle.Computed"/> layout.
+	/// </summary>
+	/// <remarks>
 	/// <para>
-	///    Views have a <see cref="ColorScheme"/> property that defines the default colors that subviews
-	///    should use for rendering. This ensures that the views fit in the context where
-	///    they are being used, and allows for themes to be plugged in. For example, the
-	///    default colors for windows and Toplevels uses a blue background, while it uses
-	///    a white background for dialog boxes and a red background for errors.
+	///   The <see cref="View"/> will be created using <see cref="Terminal.Gui.LayoutStyle.Computed"/>
+	///   coordinates with the given string. The initial size (<see cref="View.Frame"/>) will be 
+	///   adjusted to fit the contents of <see cref="Text"/>, including newlines ('\n') for multiple lines. 
 	/// </para>
 	/// <para>
-	///    Subclasses should not rely on <see cref="ColorScheme"/> being
-	///    set at construction time. If a <see cref="ColorScheme"/> is not set on a view, the view will inherit the
-	///    value from its <see cref="SuperView"/> and the value might only be valid once a view has been
-	///    added to a SuperView. 
+	///   If <see cref="Height"/> is greater than one, word wrapping is provided.
 	/// </para>
+	/// </remarks>
+	/// <param name="text">text to initialize the <see cref="Text"/> property with.</param>
+	/// <param name="direction">The text direction.</param>
+	public View (string text, TextDirection direction = TextDirection.LeftRight_TopBottom) => SetInitialProperties (text, Rect.Empty, LayoutStyle.Computed, direction);
+
+	// TODO: v2 - Remove constructors with parameters
+	/// <summary>
+	/// Private helper to set the initial properties of the View that were provided via constructors.
+	/// </summary>
+	/// <param name="text"></param>
+	/// <param name="rect"></param>
+	/// <param name="layoutStyle"></param>
+	/// <param name="direction"></param>
+	void SetInitialProperties (string text, Rect rect, LayoutStyle layoutStyle = LayoutStyle.Computed,
+				TextDirection direction = TextDirection.LeftRight_TopBottom)
+	{
+		TextFormatter = new TextFormatter ();
+		TextFormatter.HotKeyChanged += TextFormatter_HotKeyChanged;
+		TextDirection = direction;
+
+		CanFocus = false;
+		TabIndex = -1;
+		TabStop = false;
+		LayoutStyle = layoutStyle;
+
+		Text = text == null ? string.Empty : text;
+		LayoutStyle = layoutStyle;
+		Frame = rect.IsEmpty ? TextFormatter.CalcRect (0, 0, text, direction) : rect;
+		OnResizeNeeded ();
+
+		AddCommands ();
+
+		CreateFrames ();
+	}
+
+	/// <summary>
+	/// Get or sets if  the <see cref="View"/> has been initialized (via <see cref="ISupportInitialize.BeginInit"/> 
+	/// and <see cref="ISupportInitialize.EndInit"/>).
+	/// </summary>
 	/// <para>
-	///    By using  <see cref="ColorScheme"/> applications will work both
-	///    in color as well as black and white displays.
-	/// </para>
+	///     If first-run-only initialization is preferred, overrides to <see cref="ISupportInitializeNotification.IsInitialized"/>
+	///     can be implemented, in which case the <see cref="ISupportInitialize"/>
+	///     methods will only be called if <see cref="ISupportInitializeNotification.IsInitialized"/>
+	///     is <see langword="false"/>. This allows proper <see cref="View"/> inheritance hierarchies
+	///     to override base class layout code optimally by doing so only on first run,
+	///     instead of on every run.
+	///   </para>
+	public virtual bool IsInitialized { get; set; }
+
+	/// <summary>
+	///  Signals the View that initialization is starting. See <see cref="ISupportInitialize"/>.
+	/// </summary>
+	/// <remarks>
 	/// <para>
-	///     Views can also opt-in to more sophisticated initialization
+	///     Views can opt-in to more sophisticated initialization
 	///     by implementing overrides to <see cref="ISupportInitialize.BeginInit"/> and
 	///     <see cref="ISupportInitialize.EndInit"/> which will be called
 	///     when the view is added to a <see cref="SuperView"/>. 
 	/// </para>
 	/// <para>
 	///     If first-run-only initialization is preferred, overrides to <see cref="ISupportInitializeNotification"/>
-	///     can be implemented, in which case the <see cref="ISupportInitialize"/>
+	///     can be implemented too, in which case the <see cref="ISupportInitialize"/>
 	///     methods will only be called if <see cref="ISupportInitializeNotification.IsInitialized"/>
 	///     is <see langword="false"/>. This allows proper <see cref="View"/> inheritance hierarchies
 	///     to override base class layout code optimally by doing so only on first run,
 	///     instead of on every run.
 	///   </para>
-	/// <para>
-	///	See <see href="../docs/keyboard.md">for an overview of View keyboard handling.</see>
-	/// </para>	/// </remarks>
-	#endregion API Docs
-	public partial class View : Responder, ISupportInitializeNotification {
-
-		#region Constructors and Initialization
-
-		/// <summary>
-		/// Initializes a new instance of a <see cref="Terminal.Gui.LayoutStyle.Absolute"/> <see cref="View"/> class with the absolute
-		/// dimensions specified in the <paramref name="frame"/> parameter. 
-		/// </summary>
-		/// <param name="frame">The region covered by this view.</param>
-		/// <remarks>
-		/// This constructor initialize a View with a <see cref="LayoutStyle"/> of <see cref="Terminal.Gui.LayoutStyle.Absolute"/>.
-		/// Use <see cref="View"/> to initialize a View with  <see cref="LayoutStyle"/> of <see cref="Terminal.Gui.LayoutStyle.Computed"/> 
-		/// </remarks>
-		public View (Rect frame) : this (frame, null) { }
-
-		/// <summary>
-		///   Initializes a new instance of <see cref="View"/> using <see cref="Terminal.Gui.LayoutStyle.Computed"/> layout.
-		/// </summary>
-		/// <remarks>
-		/// <para>
-		///   Use <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> properties to dynamically control the size and location of the view.
-		///   The <see cref="View"/> will be created using <see cref="Terminal.Gui.LayoutStyle.Computed"/>
-		///   coordinates. The initial size (<see cref="View.Frame"/>) will be 
-		///   adjusted to fit the contents of <see cref="Text"/>, including newlines ('\n') for multiple lines. 
-		/// </para>
-		/// <para>
-		///   If <see cref="Height"/> is greater than one, word wrapping is provided.
-		/// </para>
-		/// <para>
-		///   This constructor initialize a View with a <see cref="LayoutStyle"/> of <see cref="Terminal.Gui.LayoutStyle.Computed"/>. 
-		///   Use <see cref="X"/>, <see cref="Y"/>, <see cref="Width"/>, and <see cref="Height"/> properties to dynamically control the size and location of the view.
-		/// </para>
-		/// </remarks>
-		public View () : this (text: string.Empty, direction: TextDirection.LeftRight_TopBottom) { }
-
-		/// <summary>
-		///   Initializes a new instance of <see cref="View"/> using <see cref="Terminal.Gui.LayoutStyle.Absolute"/> layout.
-		/// </summary>
-		/// <remarks>
-		/// <para>
-		///   The <see cref="View"/> will be created at the given
-		///   coordinates with the given string. The size (<see cref="View.Frame"/>) will be 
-		///   adjusted to fit the contents of <see cref="Text"/>, including newlines ('\n') for multiple lines. 
-		/// </para>
-		/// <para>
-		///   No line wrapping is provided.
-		/// </para>
-		/// </remarks>
-		/// <param name="x">column to locate the View.</param>
-		/// <param name="y">row to locate the View.</param>
-		/// <param name="text">text to initialize the <see cref="Text"/> property with.</param>
-		public View (int x, int y, string text) : this (TextFormatter.CalcRect (x, y, text), text) { }
-
-		/// <summary>
-		///   Initializes a new instance of <see cref="View"/> using <see cref="Terminal.Gui.LayoutStyle.Absolute"/> layout.
-		/// </summary>
-		/// <remarks>
-		/// <para>
-		///   The <see cref="View"/> will be created at the given
-		///   coordinates with the given string. The initial size (<see cref="View.Frame"/>) will be 
-		///   adjusted to fit the contents of <see cref="Text"/>, including newlines ('\n') for multiple lines. 
-		/// </para>
-		/// <para>
-		///   If <c>rect.Height</c> is greater than one, word wrapping is provided.
-		/// </para>
-		/// </remarks>
-		/// <param name="rect">Location.</param>
-		/// <param name="text">text to initialize the <see cref="Text"/> property with.</param>
-		public View (Rect rect, string text)
-		{
-			SetInitialProperties (text, rect, LayoutStyle.Absolute, TextDirection.LeftRight_TopBottom);
-		}
+	/// </remarks>
+	public virtual void BeginInit ()
+	{
+		if (!IsInitialized) {
+			_oldCanFocus = CanFocus;
+			_oldTabIndex = _tabIndex;
 
-		/// <summary>
-		///   Initializes a new instance of <see cref="View"/> using <see cref="Terminal.Gui.LayoutStyle.Computed"/> layout.
-		/// </summary>
-		/// <remarks>
-		/// <para>
-		///   The <see cref="View"/> will be created using <see cref="Terminal.Gui.LayoutStyle.Computed"/>
-		///   coordinates with the given string. The initial size (<see cref="View.Frame"/>) will be 
-		///   adjusted to fit the contents of <see cref="Text"/>, including newlines ('\n') for multiple lines. 
-		/// </para>
-		/// <para>
-		///   If <see cref="Height"/> is greater than one, word wrapping is provided.
-		/// </para>
-		/// </remarks>
-		/// <param name="text">text to initialize the <see cref="Text"/> property with.</param>
-		/// <param name="direction">The text direction.</param>
-		public View (string text, TextDirection direction = TextDirection.LeftRight_TopBottom)
-		{
-			SetInitialProperties (text, Rect.Empty, LayoutStyle.Computed, direction);
-		}
 
-		// TODO: v2 - Remove constructors with parameters
-		/// <summary>
-		/// Private helper to set the initial properties of the View that were provided via constructors.
-		/// </summary>
-		/// <param name="text"></param>
-		/// <param name="rect"></param>
-		/// <param name="layoutStyle"></param>
-		/// <param name="direction"></param>
-		void SetInitialProperties (string text, Rect rect, LayoutStyle layoutStyle = LayoutStyle.Computed,
-		    TextDirection direction = TextDirection.LeftRight_TopBottom)
-		{
-			TextFormatter = new TextFormatter ();
-			TextFormatter.HotKeyChanged += TextFormatter_HotKeyChanged;
-			TextDirection = direction;
-
-			CanFocus = false;
-			TabIndex = -1;
-			TabStop = false;
-			LayoutStyle = layoutStyle;
-
-			Text = text == null ? string.Empty : text;
-			LayoutStyle = layoutStyle;
-			Frame = rect.IsEmpty ? TextFormatter.CalcRect (0, 0, text, direction) : rect;
-			OnResizeNeeded ();
-
-			AddCommands ();
-
-			CreateFrames ();
-
-			LayoutFrames ();
-		}
+			// TODO: Figure out why ScrollView and other tests fail if this call is put here 
+			// instead of the constructor.
+			//InitializeFrames ();
 
-		/// <summary>
-		/// Get or sets if  the <see cref="View"/> has been initialized (via <see cref="ISupportInitialize.BeginInit"/> 
-		/// and <see cref="ISupportInitialize.EndInit"/>).
-		/// </summary>
-		/// <para>
-		///     If first-run-only initialization is preferred, overrides to <see cref="ISupportInitializeNotification.IsInitialized"/>
-		///     can be implemented, in which case the <see cref="ISupportInitialize"/>
-		///     methods will only be called if <see cref="ISupportInitializeNotification.IsInitialized"/>
-		///     is <see langword="false"/>. This allows proper <see cref="View"/> inheritance hierarchies
-		///     to override base class layout code optimally by doing so only on first run,
-		///     instead of on every run.
-		///   </para>
-		public virtual bool IsInitialized { get; set; }
-
-		/// <summary>
-		///  Signals the View that initialization is starting. See <see cref="ISupportInitialize"/>.
-		/// </summary>
-		/// <remarks>
-		/// <para>
-		///     Views can opt-in to more sophisticated initialization
-		///     by implementing overrides to <see cref="ISupportInitialize.BeginInit"/> and
-		///     <see cref="ISupportInitialize.EndInit"/> which will be called
-		///     when the view is added to a <see cref="SuperView"/>. 
-		/// </para>
-		/// <para>
-		///     If first-run-only initialization is preferred, overrides to <see cref="ISupportInitializeNotification"/>
-		///     can be implemented too, in which case the <see cref="ISupportInitialize"/>
-		///     methods will only be called if <see cref="ISupportInitializeNotification.IsInitialized"/>
-		///     is <see langword="false"/>. This allows proper <see cref="View"/> inheritance hierarchies
-		///     to override base class layout code optimally by doing so only on first run,
-		///     instead of on every run.
-		///   </para>
-		/// </remarks>
-		public virtual void BeginInit ()
-		{
-			if (!IsInitialized) {
-				_oldCanFocus = CanFocus;
-				_oldTabIndex = _tabIndex;
-
-				// BUGBUG: These should move to EndInit as they access Bounds causing debug spew.
-				UpdateTextDirection (TextDirection);
-				UpdateTextFormatterText ();
-				SetHotKey ();
-
-				// TODO: Figure out why ScrollView and other tests fail if this call is put here 
-				// instead of the constructor.
-				//InitializeFrames ();
-
-			} else {
-				//throw new InvalidOperationException ("The view is already initialized.");
+		} else {
+			//throw new InvalidOperationException ("The view is already initialized.");
 
-			}
+		}
 
-			if (_subviews?.Count > 0) {
-				foreach (var view in _subviews) {
-					if (!view.IsInitialized) {
-						view.BeginInit ();
-					}
+		if (_subviews?.Count > 0) {
+			foreach (var view in _subviews) {
+				if (!view.IsInitialized) {
+					view.BeginInit ();
 				}
 			}
 		}
+	}
 
-		/// <summary>
-		///  Signals the View that initialization is ending. See <see cref="ISupportInitialize"/>.
-		/// </summary>
-		public void EndInit ()
-		{
-			IsInitialized = true;
-			OnResizeNeeded ();
-			if (_subviews != null) {
-				foreach (var view in _subviews) {
-					if (!view.IsInitialized) {
-						view.EndInit ();
-					}
+	/// <summary>
+	///  Signals the View that initialization is ending. See <see cref="ISupportInitialize"/>.
+	/// </summary>
+	public void EndInit ()
+	{
+		IsInitialized = true;
+		// These calls were moved from BeginInit as they access Bounds which is indeterminate until EndInit is called.
+		UpdateTextDirection (TextDirection);
+		UpdateTextFormatterText ();
+		SetHotKey ();
+
+		OnResizeNeeded ();
+		if (_subviews != null) {
+			foreach (var view in _subviews) {
+				if (!view.IsInitialized) {
+					view.EndInit ();
 				}
 			}
-			Initialized?.Invoke (this, EventArgs.Empty);
 		}
-		#endregion Constructors and Initialization
-
-		/// <summary>
-		/// Points to the current driver in use by the view, it is a convenience property
-		/// for simplifying the development of new views.
-		/// </summary>
-		public static ConsoleDriver Driver => Application.Driver;
-
-		/// <summary>
-		/// Gets or sets arbitrary data for the view.
-		/// </summary>
-		/// <remarks>This property is not used internally.</remarks>
-		public object Data { get; set; }
-
-		/// <summary>
-		/// Gets or sets an identifier for the view;
-		/// </summary>
-		/// <value>The identifier.</value>
-		/// <remarks>The id should be unique across all Views that share a SuperView.</remarks>
-		public string Id { get; set; } = "";
-
-		string _title = string.Empty;
-		/// <summary>
-		/// The title to be displayed for this <see cref="View"/>. The title will be displayed if <see cref="Border"/>.<see cref="Thickness.Top"/>
-		/// is greater than 0.
-		/// </summary>
-		/// <value>The title.</value>
-		public string Title {
-			get => _title;
-			set {
-				if (!OnTitleChanging (_title, value)) {
-					var old = _title;
-					_title = value;
-					SetNeedsDisplay ();
+		Initialized?.Invoke (this, EventArgs.Empty);
+	}
+	#endregion Constructors and Initialization
+
+	/// <summary>
+	/// Points to the current driver in use by the view, it is a convenience property
+	/// for simplifying the development of new views.
+	/// </summary>
+	public static ConsoleDriver Driver => Application.Driver;
+
+	/// <summary>
+	/// Gets or sets arbitrary data for the view.
+	/// </summary>
+	/// <remarks>This property is not used internally.</remarks>
+	public object Data { get; set; }
+
+	/// <summary>
+	/// Gets or sets an identifier for the view;
+	/// </summary>
+	/// <value>The identifier.</value>
+	/// <remarks>The id should be unique across all Views that share a SuperView.</remarks>
+	public string Id { get; set; } = "";
+
+	string _title = string.Empty;
+
+	/// <summary>
+	/// The title to be displayed for this <see cref="View"/>. The title will be displayed if <see cref="Border"/>.<see cref="Thickness.Top"/>
+	/// is greater than 0.
+	/// </summary>
+	/// <value>The title.</value>
+	public string Title {
+		get => _title;
+		set {
+			if (!OnTitleChanging (_title, value)) {
+				string old = _title;
+				_title = value;
+				SetNeedsDisplay ();
 #if DEBUG
-					if (_title != null && string.IsNullOrEmpty (Id)) {
-						Id = _title.ToString ();
-					}
-#endif // DEBUG
-					OnTitleChanged (old, _title);
+				if (_title != null && string.IsNullOrEmpty (Id)) {
+					Id = _title.ToString ();
 				}
+#endif // DEBUG
+				OnTitleChanged (old, _title);
 			}
 		}
+	}
 
-		/// <summary>
-		/// Called before the <see cref="View.Title"/> changes. Invokes the <see cref="TitleChanging"/> event, which can be cancelled.
-		/// </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>
-		/// <returns>`true` if an event handler canceled the Title change.</returns>
-		public virtual bool OnTitleChanging (string oldTitle, string newTitle)
-		{
-			var args = new TitleEventArgs (oldTitle, newTitle);
-			TitleChanging?.Invoke (this, args);
-			return args.Cancel;
-		}
+	/// <summary>
+	/// Called before the <see cref="View.Title"/> changes. Invokes the <see cref="TitleChanging"/> event, which can be cancelled.
+	/// </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>
+	/// <returns>`true` if an event handler canceled the Title change.</returns>
+	public virtual bool OnTitleChanging (string oldTitle, string newTitle)
+	{
+		var args = new TitleEventArgs (oldTitle, newTitle);
+		TitleChanging?.Invoke (this, args);
+		return args.Cancel;
+	}
 
-		/// <summary>
-		/// Event fired when the <see cref="View.Title"/> is changing. Set <see cref="TitleEventArgs.Cancel"/> to 
-		/// `true` to cancel the Title change.
-		/// </summary>
-		public event EventHandler<TitleEventArgs> TitleChanging;
-
-		/// <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)
-		{
-			var args = new TitleEventArgs (oldTitle, newTitle);
-			TitleChanged?.Invoke (this, args);
-		}
+	/// <summary>
+	/// Event fired when the <see cref="View.Title"/> is changing. Set <see cref="TitleEventArgs.Cancel"/> to 
+	/// `true` to cancel the Title change.
+	/// </summary>
+	public event EventHandler<TitleEventArgs> TitleChanging;
 
-		/// <summary>
-		/// Event fired after the <see cref="View.Title"/> has been changed. 
-		/// </summary>
-		public event EventHandler<TitleEventArgs> TitleChanged;
-
-		/// <summary>
-		/// Event fired when the <see cref="Enabled"/> value is being changed.
-		/// </summary>
-		public event EventHandler EnabledChanged;
-
-		/// <inheritdoc/>
-		public override void OnEnabledChanged () => EnabledChanged?.Invoke (this, EventArgs.Empty);
-
-		bool _oldEnabled;
-
-		/// <inheritdoc/>
-		public override bool Enabled {
-			get => base.Enabled;
-			set {
-				if (base.Enabled != value) {
-					if (value) {
-						if (SuperView == null || SuperView?.Enabled == true) {
-							base.Enabled = value;
-						}
-					} else {
+	/// <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)
+	{
+		var args = new TitleEventArgs (oldTitle, newTitle);
+		TitleChanged?.Invoke (this, args);
+	}
+
+	/// <summary>
+	/// Event fired after the <see cref="View.Title"/> has been changed. 
+	/// </summary>
+	public event EventHandler<TitleEventArgs> TitleChanged;
+
+	/// <summary>
+	/// Event fired when the <see cref="Enabled"/> value is being changed.
+	/// </summary>
+	public event EventHandler EnabledChanged;
+
+	/// <inheritdoc/>
+	public override void OnEnabledChanged () => EnabledChanged?.Invoke (this, EventArgs.Empty);
+
+	bool _oldEnabled;
+
+	/// <inheritdoc/>
+	public override bool Enabled {
+		get => base.Enabled;
+		set {
+			if (base.Enabled != value) {
+				if (value) {
+					if (SuperView == null || SuperView?.Enabled == true) {
 						base.Enabled = value;
 					}
-					if (!value && HasFocus) {
-						SetHasFocus (false, this);
-					}
-					OnEnabledChanged ();
-					SetNeedsDisplay ();
-
-					if (_subviews != null) {
-						foreach (var view in _subviews) {
-							if (!value) {
-								view._oldEnabled = view.Enabled;
-								view.Enabled = false;
-							} else {
-								view.Enabled = view._oldEnabled;
-								view._addingView = false;
-							}
+				} else {
+					base.Enabled = value;
+				}
+				if (!value && HasFocus) {
+					SetHasFocus (false, this);
+				}
+				OnEnabledChanged ();
+				SetNeedsDisplay ();
+
+				if (_subviews != null) {
+					foreach (var view in _subviews) {
+						if (!value) {
+							view._oldEnabled = view.Enabled;
+							view.Enabled = false;
+						} else {
+							view.Enabled = view._oldEnabled;
+							view._addingView = false;
 						}
 					}
 				}
 			}
 		}
+	}
 
-		/// <summary>
-		/// Event fired when the <see cref="Visible"/> value is being changed.
-		/// </summary>
-		public event EventHandler VisibleChanged;
-
-		/// <inheritdoc/>
-		public override void OnVisibleChanged () => VisibleChanged?.Invoke (this, EventArgs.Empty);
-
-		/// <summary>
-		/// Gets or sets whether a view is cleared if the <see cref="Visible"/> property is <see langword="false"/>.
-		/// </summary>
-		public bool ClearOnVisibleFalse { get; set; } = true;
-
-		/// <inheritdoc/>>
-		public override bool Visible {
-			get => base.Visible;
-			set {
-				if (base.Visible != value) {
-					base.Visible = value;
-					if (!value) {
-						if (HasFocus) {
-							SetHasFocus (false, this);
-						}
-						if (ClearOnVisibleFalse) {
-							Clear ();
-						}
+	/// <summary>
+	/// Event fired when the <see cref="Visible"/> value is being changed.
+	/// </summary>
+	public event EventHandler VisibleChanged;
+
+	/// <inheritdoc/>
+	public override void OnVisibleChanged () => VisibleChanged?.Invoke (this, EventArgs.Empty);
+
+	/// <summary>
+	/// Gets or sets whether a view is cleared if the <see cref="Visible"/> property is <see langword="false"/>.
+	/// </summary>
+	public bool ClearOnVisibleFalse { get; set; } = true;
+
+	/// <inheritdoc/>>
+	public override bool Visible {
+		get => base.Visible;
+		set {
+			if (base.Visible != value) {
+				base.Visible = value;
+				if (!value) {
+					if (HasFocus) {
+						SetHasFocus (false, this);
+					}
+					if (ClearOnVisibleFalse) {
+						Clear ();
 					}
-					OnVisibleChanged ();
-					SetNeedsDisplay ();
 				}
+				OnVisibleChanged ();
+				SetNeedsDisplay ();
 			}
 		}
+	}
 
-		bool CanBeVisible (View view)
-		{
-			if (!view.Visible) {
+	bool CanBeVisible (View view)
+	{
+		if (!view.Visible) {
+			return false;
+		}
+		for (var c = view.SuperView; c != null; c = c.SuperView) {
+			if (!c.Visible) {
 				return false;
 			}
-			for (var c = view.SuperView; c != null; c = c.SuperView) {
-				if (!c.Visible) {
-					return false;
-				}
-			}
-
-			return true;
 		}
 
-		/// <summary>
-		/// Pretty prints the View
-		/// </summary>
-		/// <returns></returns>
-		public override string ToString ()
-		{
-			return $"{GetType ().Name}({Id}){Frame}";
-		}
-
-		/// <inheritdoc/>
-		protected override void Dispose (bool disposing)
-		{
-			LineCanvas.Dispose ();
-
-			Margin?.Dispose ();
-			Margin = null;
-			Border?.Dispose ();
-			Border = null;
-			Padding?.Dispose ();
-			Padding = null;
-
-			_height = null;
-			_width = null;
-			_x = null;
-			_y = null;
-
-			for (var i = InternalSubviews.Count - 1; i >= 0; i--) {
-				var subview = InternalSubviews [i];
-				Remove (subview);
-				subview.Dispose ();
-			}
+		return true;
+	}
 
-			base.Dispose (disposing);
-			System.Diagnostics.Debug.Assert (InternalSubviews.Count == 0);
+	/// <summary>
+	/// Pretty prints the View
+	/// </summary>
+	/// <returns></returns>
+	public override string ToString () => $"{GetType ().Name}({Id}){Frame}";
+
+	/// <inheritdoc/>
+	protected override void Dispose (bool disposing)
+	{
+		LineCanvas.Dispose ();
+
+		Margin?.Dispose ();
+		Margin = null;
+		Border?.Dispose ();
+		Border = null;
+		Padding?.Dispose ();
+		Padding = null;
+
+		_height = null;
+		_width = null;
+		_x = null;
+		_y = null;
+
+		for (int i = InternalSubviews.Count - 1; i >= 0; i--) {
+			var subview = InternalSubviews [i];
+			Remove (subview);
+			subview.Dispose ();
 		}
+
+		base.Dispose (disposing);
+		System.Diagnostics.Debug.Assert (InternalSubviews.Count == 0);
 	}
-}
+}

+ 448 - 440
Terminal.Gui/View/ViewDrawing.cs

@@ -3,509 +3,517 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 
-namespace Terminal.Gui {
-	public partial class View {
-
-		ColorScheme _colorScheme;
-
-		/// <summary>
-		/// The color scheme for this view, if it is not defined, it returns the <see cref="SuperView"/>'s
-		/// color scheme. 
-		/// </summary>
-		public virtual ColorScheme ColorScheme {
-			get {
-				if (_colorScheme == null) {
-					return SuperView?.ColorScheme;
-				}
-				return _colorScheme;
-			}
-			set {
-				if (_colorScheme != value) {
-					_colorScheme = value;
-					SetNeedsDisplay ();
-				}
+namespace Terminal.Gui;
+
+public partial class View {
+	ColorScheme _colorScheme;
+
+	/// <summary>
+	/// The color scheme for this view, if it is not defined, it returns the <see cref="SuperView"/>'s
+	/// color scheme. 
+	/// </summary>
+	public virtual ColorScheme ColorScheme {
+		get {
+			if (_colorScheme == null) {
+				return SuperView?.ColorScheme;
 			}
+			return _colorScheme;
 		}
-
-		/// <summary>
-		/// Determines the current <see cref="ColorScheme"/> based on the <see cref="Enabled"/> value.
-		/// </summary>
-		/// <returns><see cref="Terminal.Gui.ColorScheme.Normal"/> if <see cref="Enabled"/> is <see langword="true"/>
-		/// or <see cref="Terminal.Gui.ColorScheme.Disabled"/> if <see cref="Enabled"/> is <see langword="false"/>.
-		/// If it's overridden can return other values.</returns>
-		public virtual Attribute GetNormalColor ()
-		{
-			ColorScheme cs = ColorScheme;
-			if (ColorScheme == null) {
-				cs = new ColorScheme ();
+		set {
+			if (_colorScheme != value) {
+				_colorScheme = value;
+				SetNeedsDisplay ();
 			}
-			return Enabled ? cs.Normal : cs.Disabled;
 		}
+	}
 
-		/// <summary>
-		/// Determines the current <see cref="ColorScheme"/> based on the <see cref="Enabled"/> value.
-		/// </summary>
-		/// <returns><see cref="Terminal.Gui.ColorScheme.Focus"/> if <see cref="Enabled"/> is <see langword="true"/>
-		/// or <see cref="Terminal.Gui.ColorScheme.Disabled"/> if <see cref="Enabled"/> is <see langword="false"/>.
-		/// If it's overridden can return other values.</returns>
-		public virtual Attribute GetFocusColor ()
-		{
-			return Enabled ? ColorScheme.Focus : ColorScheme.Disabled;
+	/// <summary>
+	/// Determines the current <see cref="ColorScheme"/> based on the <see cref="Enabled"/> value.
+	/// </summary>
+	/// <returns><see cref="Terminal.Gui.ColorScheme.Normal"/> if <see cref="Enabled"/> is <see langword="true"/>
+	/// or <see cref="Terminal.Gui.ColorScheme.Disabled"/> if <see cref="Enabled"/> is <see langword="false"/>.
+	/// If it's overridden can return other values.</returns>
+	public virtual Attribute GetNormalColor ()
+	{
+		var cs = ColorScheme;
+		if (ColorScheme == null) {
+			cs = new ColorScheme ();
 		}
+		return Enabled ? cs.Normal : cs.Disabled;
+	}
 
-		/// <summary>
-		/// Determines the current <see cref="ColorScheme"/> based on the <see cref="Enabled"/> value.
-		/// </summary>
-		/// <returns><see cref="Terminal.Gui.ColorScheme.HotNormal"/> if <see cref="Enabled"/> is <see langword="true"/>
-		/// or <see cref="Terminal.Gui.ColorScheme.Disabled"/> if <see cref="Enabled"/> is <see langword="false"/>.
-		/// If it's overridden can return other values.</returns>
-		public virtual Attribute GetHotNormalColor ()
-		{
-			return Enabled ? ColorScheme.HotNormal : ColorScheme.Disabled;
+	/// <summary>
+	/// Determines the current <see cref="ColorScheme"/> based on the <see cref="Enabled"/> value.
+	/// </summary>
+	/// <returns><see cref="Terminal.Gui.ColorScheme.Focus"/> if <see cref="Enabled"/> is <see langword="true"/>
+	/// or <see cref="Terminal.Gui.ColorScheme.Disabled"/> if <see cref="Enabled"/> is <see langword="false"/>.
+	/// If it's overridden can return other values.</returns>
+	public virtual Attribute GetFocusColor () => Enabled ? ColorScheme.Focus : ColorScheme.Disabled;
+
+	/// <summary>
+	/// Determines the current <see cref="ColorScheme"/> based on the <see cref="Enabled"/> value.
+	/// </summary>
+	/// <returns><see cref="Terminal.Gui.ColorScheme.HotNormal"/> if <see cref="Enabled"/> is <see langword="true"/>
+	/// or <see cref="Terminal.Gui.ColorScheme.Disabled"/> if <see cref="Enabled"/> is <see langword="false"/>.
+	/// If it's overridden can return other values.</returns>
+	public virtual Attribute GetHotNormalColor () => Enabled ? ColorScheme.HotNormal : ColorScheme.Disabled;
+
+	/// <summary>
+	/// Displays the specified character in the specified column and row of the View.
+	/// </summary>
+	/// <param name="col">Column (view-relative).</param>
+	/// <param name="row">Row (view-relative).</param>
+	/// <param name="ch">Ch.</param>
+	public void AddRune (int col, int row, Rune ch)
+	{
+		if (row < 0 || col < 0) {
+			return;
 		}
-
-		/// <summary>
-		/// Displays the specified character in the specified column and row of the View.
-		/// </summary>
-		/// <param name="col">Column (view-relative).</param>
-		/// <param name="row">Row (view-relative).</param>
-		/// <param name="ch">Ch.</param>
-		public void AddRune (int col, int row, Rune ch)
-		{
-			if (row < 0 || col < 0) {
-				return;
-			}
-			if (row > _frame.Height - 1 || col > _frame.Width - 1) {
-				return;
-			}
-			Move (col, row);
-			Driver.AddRune (ch);
+		if (row > _frame.Height - 1 || col > _frame.Width - 1) {
+			return;
 		}
+		Move (col, row);
+		Driver.AddRune (ch);
+	}
 
-		/// <summary>
-		/// Clears <see cref="NeedsDisplay"/> and <see cref="SubViewNeedsDisplay"/>.
-		/// </summary>
-		protected void ClearNeedsDisplay ()
-		{
-			_needsDisplayRect = Rect.Empty;
-			_subViewNeedsDisplay = false;
-		}
+	/// <summary>
+	/// Clears <see cref="NeedsDisplay"/> and <see cref="SubViewNeedsDisplay"/>.
+	/// </summary>
+	protected void ClearNeedsDisplay ()
+	{
+		_needsDisplayRect = Rect.Empty;
+		_subViewNeedsDisplay = false;
+	}
 
-		// The view-relative region that needs to be redrawn. Marked internal for unit tests.
-		internal Rect _needsDisplayRect = Rect.Empty;
-
-		/// <summary>
-		/// Gets or sets whether the view needs to be redrawn.
-		/// </summary>
-		public bool NeedsDisplay {
-			get => _needsDisplayRect != Rect.Empty;
-			set {
-				if (value) {
-					SetNeedsDisplay ();
-				} else {
-					ClearNeedsDisplay ();
-				}
+	// The view-relative region that needs to be redrawn. Marked internal for unit tests.
+	internal Rect _needsDisplayRect = Rect.Empty;
+
+	/// <summary>
+	/// Gets or sets whether the view needs to be redrawn.
+	/// </summary>
+	public bool NeedsDisplay {
+		get => _needsDisplayRect != Rect.Empty;
+		set {
+			if (value) {
+				SetNeedsDisplay ();
+			} else {
+				ClearNeedsDisplay ();
 			}
 		}
+	}
 
-		/// <summary>
-		/// Sets the area of this view needing to be redrawn to <see cref="Bounds"/>.
-		/// </summary>
-		public void SetNeedsDisplay ()
-		{
-			if (!IsInitialized) {
-				return;
-			}
+	/// <summary>
+	/// Sets the area of this view needing to be redrawn to <see cref="Bounds"/>.
+	/// </summary>
+	/// <remarks>
+	/// If the view has not been initialized (<see cref="IsInitialized"/> is <see langword="false"/>),
+	/// this method does nothing.
+	/// </remarks>
+	public void SetNeedsDisplay ()
+	{
+		if (IsInitialized) {
 			SetNeedsDisplay (Bounds);
 		}
+	}
 
-		/// <summary>
-		/// Expands the area of this view needing to be redrawn to include <paramref name="region"/>.
-		/// </summary>
-		/// <param name="region">The view-relative region that needs to be redrawn.</param>
-		public void SetNeedsDisplay (Rect region)
-		{
-			if (_needsDisplayRect.IsEmpty) {
-				_needsDisplayRect = region;
-			} else {
-				var x = Math.Min (_needsDisplayRect.X, region.X);
-				var y = Math.Min (_needsDisplayRect.Y, region.Y);
-				var w = Math.Max (_needsDisplayRect.Width, region.Width);
-				var h = Math.Max (_needsDisplayRect.Height, region.Height);
-				_needsDisplayRect = new Rect (x, y, w, h);
-			}
-			_superView?.SetSubViewNeedsDisplay ();
-
-			if (_needsDisplayRect.X < Bounds.X ||
-				_needsDisplayRect.Y < Bounds.Y ||
-				_needsDisplayRect.Width > Bounds.Width ||
-				_needsDisplayRect.Height > Bounds.Height) {
-				Margin?.SetNeedsDisplay (Margin.Bounds);
-				Border?.SetNeedsDisplay (Border.Bounds);
-				Padding?.SetNeedsDisplay (Padding.Bounds);
-			}
+	/// <summary>
+	/// Expands the area of this view needing to be redrawn to include <paramref name="region"/>.
+	/// </summary>
+	/// <remarks>
+	/// If the view has not been initialized (<see cref="IsInitialized"/> is <see langword="false"/>),
+	/// the area to be redrawn will be the <paramref name="region"/>.
+	/// </remarks>
+	/// <param name="region">The Bounds-relative region that needs to be redrawn.</param>
+	public void SetNeedsDisplay (Rect region)
+	{
+		if (!IsInitialized) {
+			_needsDisplayRect = region;
+			return;
+		}
+		if (_needsDisplayRect.IsEmpty) {
+			_needsDisplayRect = region;
+		} else {
+			int x = Math.Min (_needsDisplayRect.X, region.X);
+			int y = Math.Min (_needsDisplayRect.Y, region.Y);
+			int w = Math.Max (_needsDisplayRect.Width, region.Width);
+			int h = Math.Max (_needsDisplayRect.Height, region.Height);
+			_needsDisplayRect = new Rect (x, y, w, h);
+		}
+		_superView?.SetSubViewNeedsDisplay ();
+
+		if (_needsDisplayRect.X < Bounds.X ||
+		_needsDisplayRect.Y < Bounds.Y ||
+		_needsDisplayRect.Width > Bounds.Width ||
+		_needsDisplayRect.Height > Bounds.Height) {
+			Margin?.SetNeedsDisplay (Margin.Bounds);
+			Border?.SetNeedsDisplay (Border.Bounds);
+			Padding?.SetNeedsDisplay (Padding.Bounds);
+		}
 
-			if (_subviews == null) {
-				return;
-			}
+		if (_subviews == null) {
+			return;
+		}
 
-			foreach (var subview in _subviews) {
-				if (subview.Frame.IntersectsWith (region)) {
-					var subviewRegion = Rect.Intersect (subview.Frame, region);
-					subviewRegion.X -= subview.Frame.X;
-					subviewRegion.Y -= subview.Frame.Y;
-					subview.SetNeedsDisplay (subviewRegion);
-				}
+		foreach (var subview in _subviews) {
+			if (subview.Frame.IntersectsWith (region)) {
+				var subviewRegion = Rect.Intersect (subview.Frame, region);
+				subviewRegion.X -= subview.Frame.X;
+				subviewRegion.Y -= subview.Frame.Y;
+				subview.SetNeedsDisplay (subviewRegion);
 			}
 		}
+	}
 
-		/// <summary>
-		/// Gets whether any Subviews need to be redrawn.
-		/// </summary>
-		public bool SubViewNeedsDisplay {
-			get => _subViewNeedsDisplay;
+	/// <summary>
+	/// Gets whether any Subviews need to be redrawn.
+	/// </summary>
+	public bool SubViewNeedsDisplay => _subViewNeedsDisplay;
+
+	bool _subViewNeedsDisplay;
+
+	/// <summary>
+	/// Indicates that any Subviews (in the <see cref="Subviews"/> list) need to be repainted.
+	/// </summary>
+	public void SetSubViewNeedsDisplay ()
+	{
+		_subViewNeedsDisplay = true;
+		if (_superView != null && !_superView._subViewNeedsDisplay) {
+			_superView.SetSubViewNeedsDisplay ();
 		}
+	}
 
-		bool _subViewNeedsDisplay;
+	/// <summary>
+	///   Clears the <see cref="Bounds"/> with the normal background color.
+	/// </summary>
+	/// <remarks>
+	///   <para>
+	///     This clears the Bounds used by this view.
+	///   </para>
+	/// </remarks>
+	public void Clear ()
+	{
+		if (IsInitialized) {
+			Clear (BoundsToScreen (Bounds));
+		}
 
-		/// <summary>
-		/// Indicates that any Subviews (in the <see cref="Subviews"/> list) need to be repainted.
-		/// </summary>
-		public void SetSubViewNeedsDisplay ()
-		{
-			_subViewNeedsDisplay = true;
-			if (_superView != null && !_superView._subViewNeedsDisplay) {
-				_superView.SetSubViewNeedsDisplay ();
-			}
+	}
+
+	// BUGBUG: This version of the Clear API should be removed. We should have a tenet that says 
+	// "View APIs only deal with View-relative coords". This is only used by ComboBox which can
+	// be refactored to use the View-relative version.
+	/// <summary>
+	///   Clears the specified screen-relative rectangle with the normal background. 
+	/// </summary>
+	/// <remarks>
+	/// </remarks>
+	/// <param name="regionScreen">The screen-relative rectangle to clear.</param>
+	public void Clear (Rect regionScreen)
+	{
+		if (Driver == null) {
+			return;
 		}
+		var prev = Driver.SetAttribute (GetNormalColor ());
+		Driver.FillRect (regionScreen);
+		Driver.SetAttribute (prev);
+	}
+
+	// Clips a rectangle in screen coordinates to the dimensions currently available on the screen
+	internal Rect ScreenClip (Rect regionScreen)
+	{
+		int x = regionScreen.X < 0 ? 0 : regionScreen.X;
+		int y = regionScreen.Y < 0 ? 0 : regionScreen.Y;
+		int w = regionScreen.X + regionScreen.Width >= Driver.Cols ? Driver.Cols - regionScreen.X : regionScreen.Width;
+		int h = regionScreen.Y + regionScreen.Height >= Driver.Rows ? Driver.Rows - regionScreen.Y : regionScreen.Height;
+
+		return new Rect (x, y, w, h);
+	}
+
+	/// <summary>
+	/// Expands the <see cref="ConsoleDriver"/>'s clip region to include <see cref="Bounds"/>.
+	/// </summary>
+	/// <returns>The current screen-relative clip region, which can be then re-applied by setting <see cref="ConsoleDriver.Clip"/>.</returns>
+	/// <remarks>
+	/// <para>
+	/// If <see cref="ConsoleDriver.Clip"/> and <see cref="Bounds"/> do not intersect, the clip region will be set to <see cref="Rect.Empty"/>.
+	/// </para>
+	/// </remarks>
+	public Rect ClipToBounds ()
+	{
+		var previous = Driver.Clip;
+		Driver.Clip = Rect.Intersect (previous, BoundsToScreen (Bounds));
+		return previous;
+	}
 
-		/// <summary>
-		///   Clears the <see cref="Bounds"/> with the normal background color.
-		/// </summary>
-		/// <remarks>
-		///   <para>
-		///     This clears the Bounds used by this view.
-		///   </para>
-		/// </remarks>
-		public void Clear () => Clear (BoundsToScreen(Bounds));
-
-		// BUGBUG: This version of the Clear API should be removed. We should have a tenet that says 
-		// "View APIs only deal with View-relative coords". This is only used by ComboBox which can
-		// be refactored to use the View-relative version.
-		/// <summary>
-		///   Clears the specified screen-relative rectangle with the normal background. 
-		/// </summary>
-		/// <remarks>
-		/// </remarks>
-		/// <param name="regionScreen">The screen-relative rectangle to clear.</param>
-		public void Clear (Rect regionScreen)
-		{
-			if (Driver == null) {
-				return;
+	/// <summary>
+	/// Utility function to draw strings that contain a hotkey.
+	/// </summary>
+	/// <param name="text">String to display, the hotkey specifier before a letter flags the next letter as the hotkey.</param>
+	/// <param name="hotColor">Hot color.</param>
+	/// <param name="normalColor">Normal color.</param>
+	/// <remarks>
+	/// <para>The hotkey is any character following the hotkey specifier, which is the underscore ('_') character by default.</para>
+	/// <para>The hotkey specifier can be changed via <see cref="HotKeySpecifier"/></para>
+	/// </remarks>
+	public void DrawHotString (string text, Attribute hotColor, Attribute normalColor)
+	{
+		var hotkeySpec = HotKeySpecifier == (Rune)0xffff ? (Rune)'_' : HotKeySpecifier;
+		Application.Driver.SetAttribute (normalColor);
+		foreach (char rune in text) {
+			if (rune == hotkeySpec.Value) {
+				Application.Driver.SetAttribute (hotColor);
+				continue;
 			}
-			var prev = Driver.SetAttribute (GetNormalColor ());
-			Driver.FillRect (regionScreen);
-			Driver.SetAttribute (prev);
+			Application.Driver.AddRune ((Rune)rune);
+			Application.Driver.SetAttribute (normalColor);
 		}
+	}
 
-		// Clips a rectangle in screen coordinates to the dimensions currently available on the screen
-		internal Rect ScreenClip (Rect regionScreen)
-		{
-			var x = regionScreen.X < 0 ? 0 : regionScreen.X;
-			var y = regionScreen.Y < 0 ? 0 : regionScreen.Y;
-			var w = regionScreen.X + regionScreen.Width >= Driver.Cols ? Driver.Cols - regionScreen.X : regionScreen.Width;
-			var h = regionScreen.Y + regionScreen.Height >= Driver.Rows ? Driver.Rows - regionScreen.Y : regionScreen.Height;
-
-			return new Rect (x, y, w, h);
-		}		
-
-		/// <summary>
-		/// Expands the <see cref="ConsoleDriver"/>'s clip region to include <see cref="Bounds"/>.
-		/// </summary>
-		/// <returns>The current screen-relative clip region, which can be then re-applied by setting <see cref="ConsoleDriver.Clip"/>.</returns>
-		/// <remarks>
-		/// <para>
-		/// If <see cref="ConsoleDriver.Clip"/> and <see cref="Bounds"/> do not intersect, the clip region will be set to <see cref="Rect.Empty"/>.
-		/// </para>
-		/// </remarks>
-		public Rect ClipToBounds ()
-		{
-			var previous = Driver.Clip;
-			Driver.Clip = Rect.Intersect (previous, BoundsToScreen (Bounds));
-			return previous;
+	/// <summary>
+	/// Utility function to draw strings that contains a hotkey using a <see cref="ColorScheme"/> and the "focused" state.
+	/// </summary>
+	/// <param name="text">String to display, the underscore before a letter flags the next letter as the hotkey.</param>
+	/// <param name="focused">If set to <see langword="true"/> this uses the focused colors from the color scheme, otherwise the regular ones.</param>
+	/// <param name="scheme">The color scheme to use.</param>
+	public void DrawHotString (string text, bool focused, ColorScheme scheme)
+	{
+		if (focused) {
+			DrawHotString (text, scheme.HotFocus, scheme.Focus);
+		} else {
+			DrawHotString (text, Enabled ? scheme.HotNormal : scheme.Disabled, Enabled ? scheme.Normal : scheme.Disabled);
 		}
+	}
 
-		/// <summary>
-		/// Utility function to draw strings that contain a hotkey.
-		/// </summary>
-		/// <param name="text">String to display, the hotkey specifier before a letter flags the next letter as the hotkey.</param>
-		/// <param name="hotColor">Hot color.</param>
-		/// <param name="normalColor">Normal color.</param>
-		/// <remarks>
-		/// <para>The hotkey is any character following the hotkey specifier, which is the underscore ('_') character by default.</para>
-		/// <para>The hotkey specifier can be changed via <see cref="HotKeySpecifier"/></para>
-		/// </remarks>
-		public void DrawHotString (string text, Attribute hotColor, Attribute normalColor)
-		{
-			var hotkeySpec = HotKeySpecifier == (Rune)0xffff ? (Rune)'_' : HotKeySpecifier;
-			Application.Driver.SetAttribute (normalColor);
-			foreach (var rune in text) {
-				if (rune == hotkeySpec.Value) {
-					Application.Driver.SetAttribute (hotColor);
-					continue;
-				}
-				Application.Driver.AddRune ((Rune)rune);
-				Application.Driver.SetAttribute (normalColor);
-			}
+	/// <summary>
+	/// This moves the cursor to the specified column and row in the view.
+	/// </summary>
+	/// <returns>The move.</returns>
+	/// <param name="col">The column to move to, in view-relative coordinates.</param>
+	/// <param name="row">the row to move to, in view-relative coordinates.</param>
+	public void Move (int col, int row)
+	{
+		if (Driver.Rows == 0) {
+			return;
 		}
 
-		/// <summary>
-		/// Utility function to draw strings that contains a hotkey using a <see cref="ColorScheme"/> and the "focused" state.
-		/// </summary>
-		/// <param name="text">String to display, the underscore before a letter flags the next letter as the hotkey.</param>
-		/// <param name="focused">If set to <see langword="true"/> this uses the focused colors from the color scheme, otherwise the regular ones.</param>
-		/// <param name="scheme">The color scheme to use.</param>
-		public void DrawHotString (string text, bool focused, ColorScheme scheme)
-		{
-			if (focused)
-				DrawHotString (text, scheme.HotFocus, scheme.Focus);
-			else
-				DrawHotString (text, Enabled ? scheme.HotNormal : scheme.Disabled, Enabled ? scheme.Normal : scheme.Disabled);
-		}
+		BoundsToScreen (col, row, out int rCol, out int rRow, false);
+		Driver.Move (rCol, rRow);
+	}
 
-		/// <summary>
-		/// This moves the cursor to the specified column and row in the view.
-		/// </summary>
-		/// <returns>The move.</returns>
-		/// <param name="col">The column to move to, in view-relative coordinates.</param>
-		/// <param name="row">the row to move to, in view-relative coordinates.</param>
-		public void Move (int col, int row)
-		{
-			if (Driver.Rows == 0) {
-				return;
-			}
-			
-			BoundsToScreen (col, row, out var rCol, out var rRow, false);
-			Driver.Move (rCol, rRow);
+	/// <summary>
+	/// The canvas that any line drawing that is to be shared by subviews of this view should add lines to.
+	/// </summary>
+	/// <remarks><see cref="Border"/> adds border lines to this LineCanvas.</remarks>
+	public LineCanvas LineCanvas { get; } = new ();
+
+	/// <summary>
+	/// Gets or sets whether this View will use it's SuperView's <see cref="LineCanvas"/> for
+	/// rendering any border lines. If <see langword="true"/> the rendering of any borders drawn
+	/// by this Frame will be done by it's parent's SuperView. If <see langword="false"/> (the default)
+	/// this View's <see cref="OnDrawFrames()"/> method will be called to render the borders.
+	/// </summary>
+	public virtual bool SuperViewRendersLineCanvas { get; set; } = false;
+
+	// TODO: Make this cancelable
+	/// <summary>
+	/// Prepares <see cref="View.LineCanvas"/>. If <see cref="SuperViewRendersLineCanvas"/> is true, only the <see cref="LineCanvas"/> of 
+	/// this view's subviews will be rendered. If <see cref="SuperViewRendersLineCanvas"/> is false (the default), this 
+	/// method will cause the <see cref="LineCanvas"/> be prepared to be rendered.
+	/// </summary>
+	/// <returns></returns>
+	public virtual bool OnDrawFrames ()
+	{
+		if (!IsInitialized) {
+			return false;
 		}
-		/// <summary>
-		/// The canvas that any line drawing that is to be shared by subviews of this view should add lines to.
-		/// </summary>
-		/// <remarks><see cref="Border"/> adds border lines to this LineCanvas.</remarks>
-		public LineCanvas LineCanvas { get; } = new LineCanvas ();
-
-		/// <summary>
-		/// Gets or sets whether this View will use it's SuperView's <see cref="LineCanvas"/> for
-		/// rendering any border lines. If <see langword="true"/> the rendering of any borders drawn
-		/// by this Frame will be done by it's parent's SuperView. If <see langword="false"/> (the default)
-		/// this View's <see cref="OnDrawFrames()"/> method will be called to render the borders.
-		/// </summary>
-		public virtual bool SuperViewRendersLineCanvas { get; set; } = false;
-
-		// TODO: Make this cancelable
-		/// <summary>
-		/// Prepares <see cref="View.LineCanvas"/>. If <see cref="SuperViewRendersLineCanvas"/> is true, only the <see cref="LineCanvas"/> of 
-		/// this view's subviews will be rendered. If <see cref="SuperViewRendersLineCanvas"/> is false (the default), this 
-		/// method will cause the <see cref="LineCanvas"/> be prepared to be rendered.
-		/// </summary>
-		/// <returns></returns>
-		public virtual bool OnDrawFrames ()
-		{
-			if (!IsInitialized) {
-				return false;
-			}
 
-			// Each of these renders lines to either this View's LineCanvas 
-			// Those lines will be finally rendered in OnRenderLineCanvas
-			Margin?.OnDrawContent (Margin.Bounds);
-			Border?.OnDrawContent (Border.Bounds);
-			Padding?.OnDrawContent (Padding.Bounds);
+		// Each of these renders lines to either this View's LineCanvas 
+		// Those lines will be finally rendered in OnRenderLineCanvas
+		Margin?.OnDrawContent (Margin.Bounds);
+		Border?.OnDrawContent (Border.Bounds);
+		Padding?.OnDrawContent (Padding.Bounds);
 
-			return true;
+		return true;
+	}
+
+	/// <summary>
+	/// Draws the view. Causes the following virtual methods to be called (along with their related events): 
+	/// <see cref="OnDrawContent"/>, <see cref="OnDrawContentComplete"/>.
+	/// </summary>
+	/// <remarks>
+	/// <para>
+	///    Always use <see cref="Bounds"/> (view-relative) when calling <see cref="OnDrawContent(Rect)"/>, NOT <see cref="Frame"/> (superview-relative).
+	/// </para>
+	/// <para>
+	///    Views should set the color that they want to use on entry, as otherwise this will inherit
+	///    the last color that was set globally on the driver.
+	/// </para>
+	/// <para>
+	///    Overrides of <see cref="OnDrawContent(Rect)"/> must ensure they do not set <c>Driver.Clip</c> to a clip region
+	///    larger than the <ref name="Bounds"/> property, as this will cause the driver to clip the entire region.
+	/// </para>
+	/// </remarks>
+	public void Draw ()
+	{
+		if (!CanBeVisible (this)) {
+			return;
 		}
+		OnDrawFrames ();
 
-		/// <summary>
-		/// Draws the view. Causes the following virtual methods to be called (along with their related events): 
-		/// <see cref="OnDrawContent"/>, <see cref="OnDrawContentComplete"/>.
-		/// </summary>
-		/// <remarks>
-		/// <para>
-		///    Always use <see cref="Bounds"/> (view-relative) when calling <see cref="OnDrawContent(Rect)"/>, NOT <see cref="Frame"/> (superview-relative).
-		/// </para>
-		/// <para>
-		///    Views should set the color that they want to use on entry, as otherwise this will inherit
-		///    the last color that was set globally on the driver.
-		/// </para>
-		/// <para>
-		///    Overrides of <see cref="OnDrawContent(Rect)"/> must ensure they do not set <c>Driver.Clip</c> to a clip region
-		///    larger than the <ref name="Bounds"/> property, as this will cause the driver to clip the entire region.
-		/// </para>
-		/// </remarks>
-		public void Draw ()
-		{
-			if (!CanBeVisible (this)) {
-				return;
-			}
-			OnDrawFrames ();
+		var prevClip = ClipToBounds ();
 
-			var prevClip = ClipToBounds ();
+		if (ColorScheme != null) {
+			//Driver.SetAttribute (HasFocus ? GetFocusColor () : GetNormalColor ());
+			Driver.SetAttribute (GetNormalColor ());
+		}
 
-			if (ColorScheme != null) {
-				//Driver.SetAttribute (HasFocus ? GetFocusColor () : GetNormalColor ());
-				Driver.SetAttribute (GetNormalColor ());
-			}
+		// Invoke DrawContentEvent
+		var dev = new DrawEventArgs (Bounds);
+		DrawContent?.Invoke (this, dev);
 
-			// Invoke DrawContentEvent
-			var dev = new DrawEventArgs (Bounds);
-			DrawContent?.Invoke (this, dev);
+		if (!dev.Cancel) {
+			OnDrawContent (Bounds);
+		}
 
-			if (!dev.Cancel) {
-				OnDrawContent (Bounds);
-			}
+		Driver.Clip = prevClip;
 
-			Driver.Clip = prevClip;
+		OnRenderLineCanvas ();
+		// Invoke DrawContentCompleteEvent
+		OnDrawContentComplete (Bounds);
 
-			OnRenderLineCanvas ();
-			// Invoke DrawContentCompleteEvent
-			OnDrawContentComplete (Bounds);
+		// BUGBUG: v2 - We should be able to use View.SetClip here and not have to resort to knowing Driver details.
+		ClearLayoutNeeded ();
+		ClearNeedsDisplay ();
+	}
 
-			// BUGBUG: v2 - We should be able to use View.SetClip here and not have to resort to knowing Driver details.
-			ClearLayoutNeeded ();
-			ClearNeedsDisplay ();
+	// TODO: Make this cancelable
+	/// <summary>
+	/// Renders <see cref="View.LineCanvas"/>. If <see cref="SuperViewRendersLineCanvas"/> is true, only the <see cref="LineCanvas"/> of 
+	/// this view's subviews will be rendered. If <see cref="SuperViewRendersLineCanvas"/> is false (the default), this 
+	/// method will cause the <see cref="LineCanvas"/> to be rendered.
+	/// </summary>
+	/// <returns></returns>
+	public virtual bool OnRenderLineCanvas ()
+	{
+		if (!IsInitialized) {
+			return false;
 		}
 
-		// TODO: Make this cancelable
-		/// <summary>
-		/// Renders <see cref="View.LineCanvas"/>. If <see cref="SuperViewRendersLineCanvas"/> is true, only the <see cref="LineCanvas"/> of 
-		/// this view's subviews will be rendered. If <see cref="SuperViewRendersLineCanvas"/> is false (the default), this 
-		/// method will cause the <see cref="LineCanvas"/> to be rendered.
-		/// </summary>
-		/// <returns></returns>
-		public virtual bool OnRenderLineCanvas ()
-		{
-			if (!IsInitialized) {
-				return false;
+		// If we have a SuperView, it'll render our frames.
+		if (!SuperViewRendersLineCanvas && LineCanvas.Bounds != Rect.Empty) {
+			foreach (var p in LineCanvas.GetCellMap ()) {
+				// Get the entire map
+				Driver.SetAttribute (p.Value.Attribute ?? ColorScheme.Normal);
+				Driver.Move (p.Key.X, p.Key.Y);
+				// TODO: #2616 - Support combining sequences that don't normalize
+				Driver.AddRune (p.Value.Rune);
 			}
+			LineCanvas.Clear ();
+		}
 
-			// If we have a SuperView, it'll render our frames.
-			if (!SuperViewRendersLineCanvas && LineCanvas.Bounds != Rect.Empty) {
-				foreach (var p in LineCanvas.GetCellMap ()) { // Get the entire map
-					Driver.SetAttribute (p.Value.Attribute ?? ColorScheme.Normal);
-					Driver.Move (p.Key.X, p.Key.Y);
-					// TODO: #2616 - Support combining sequences that don't normalize
-					Driver.AddRune (p.Value.Rune);
-				}
-				LineCanvas.Clear ();
+		if (Subviews.Any (s => s.SuperViewRendersLineCanvas)) {
+			foreach (var subview in Subviews.Where (s => s.SuperViewRendersLineCanvas == true)) {
+				// Combine the LineCanvas'
+				LineCanvas.Merge (subview.LineCanvas);
+				subview.LineCanvas.Clear ();
 			}
 
-			if (Subviews.Any (s => s.SuperViewRendersLineCanvas)) {
-				foreach (var subview in Subviews.Where (s => s.SuperViewRendersLineCanvas == true)) {
-					// Combine the LineCanvas'
-					LineCanvas.Merge (subview.LineCanvas);
-					subview.LineCanvas.Clear ();
-				}
-
-				foreach (var p in LineCanvas.GetCellMap ()) { // Get the entire map
-					Driver.SetAttribute (p.Value.Attribute ?? ColorScheme.Normal);
-					Driver.Move (p.Key.X, p.Key.Y);
-					// TODO: #2616 - Support combining sequences that don't normalize
-					Driver.AddRune (p.Value.Rune);
-				}
-				LineCanvas.Clear ();
+			foreach (var p in LineCanvas.GetCellMap ()) {
+				// Get the entire map
+				Driver.SetAttribute (p.Value.Attribute ?? ColorScheme.Normal);
+				Driver.Move (p.Key.X, p.Key.Y);
+				// TODO: #2616 - Support combining sequences that don't normalize
+				Driver.AddRune (p.Value.Rune);
 			}
-
-			return true;
+			LineCanvas.Clear ();
 		}
 
-		/// <summary>
-		/// Event invoked when the content area of the View is to be drawn.
-		/// </summary>
-		/// <remarks>
-		/// <para>
-		/// Will be invoked before any subviews added with <see cref="Add(View)"/> have been drawn.
-		/// </para>
-		/// <para>
-		/// Rect provides the view-relative rectangle describing the currently visible viewport into the <see cref="View"/>.
-		/// </para>
-		/// </remarks>
-		public event EventHandler<DrawEventArgs> DrawContent;
-
-		/// <summary>
-		/// Enables overrides to draw infinitely scrolled content and/or a background behind added controls. 
-		/// </summary>
-		/// <param name="contentArea">The view-relative rectangle describing the currently visible viewport into the <see cref="View"/></param>
-		/// <remarks>
-		/// This method will be called before any subviews added with <see cref="Add(View)"/> have been drawn. 
-		/// </remarks>
-		public virtual void OnDrawContent (Rect contentArea)
-		{
-			if (NeedsDisplay) {
-				if (SuperView != null) {
-					Clear (BoundsToScreen (Bounds));
-				}
+		return true;
+	}
 
-				if (!string.IsNullOrEmpty (TextFormatter.Text)) {
-					if (TextFormatter != null) {
-						TextFormatter.NeedsFormat = true;
-					}
-				}
-				// This should NOT clear 
-				TextFormatter?.Draw (BoundsToScreen (Bounds), HasFocus ? GetFocusColor () : GetNormalColor (),
-					HasFocus ? ColorScheme.HotFocus : GetHotNormalColor (),
-					Rect.Empty, false);
-				SetSubViewNeedsDisplay ();
+	/// <summary>
+	/// Event invoked when the content area of the View is to be drawn.
+	/// </summary>
+	/// <remarks>
+	/// <para>
+	/// Will be invoked before any subviews added with <see cref="Add(View)"/> have been drawn.
+	/// </para>
+	/// <para>
+	/// Rect provides the view-relative rectangle describing the currently visible viewport into the <see cref="View"/>.
+	/// </para>
+	/// </remarks>
+	public event EventHandler<DrawEventArgs> DrawContent;
+
+	/// <summary>
+	/// Enables overrides to draw infinitely scrolled content and/or a background behind added controls. 
+	/// </summary>
+	/// <param name="contentArea">The view-relative rectangle describing the currently visible viewport into the <see cref="View"/></param>
+	/// <remarks>
+	/// This method will be called before any subviews added with <see cref="Add(View)"/> have been drawn. 
+	/// </remarks>
+	public virtual void OnDrawContent (Rect contentArea)
+	{
+		if (NeedsDisplay) {
+			if (SuperView != null) {
+				Clear (BoundsToScreen (Bounds));
 			}
 
-			// Draw subviews
-			// TODO: Implement OnDrawSubviews (cancelable);
-			if (_subviews != null && SubViewNeedsDisplay) {
-				var subviewsNeedingDraw = _subviews.Where (
-					view => view.Visible &&
-						(view.NeedsDisplay ||
-						view.SubViewNeedsDisplay ||
-						view.LayoutNeeded)
-					);
-
-				foreach (var view in subviewsNeedingDraw) {
-					//view.Frame.IntersectsWith (bounds)) {
-					// && (view.Frame.IntersectsWith (bounds) || bounds.X < 0 || bounds.Y < 0)) {
-					if (view.LayoutNeeded) {
-						view.LayoutSubviews ();
-					}
-
-					// Draw the subview
-					// Use the view's bounds (view-relative; Location will always be (0,0)
-					//if (view.Visible && view.Frame.Width > 0 && view.Frame.Height > 0) {
-					view.Draw ();
-					//}
+			if (!string.IsNullOrEmpty (TextFormatter.Text)) {
+				if (TextFormatter != null) {
+					TextFormatter.NeedsFormat = true;
 				}
 			}
+			// This should NOT clear 
+			TextFormatter?.Draw (BoundsToScreen (Bounds), HasFocus ? GetFocusColor () : GetNormalColor (),
+				HasFocus ? ColorScheme.HotFocus : GetHotNormalColor (),
+				Rect.Empty, false);
+			SetSubViewNeedsDisplay ();
 		}
 
-		/// <summary>
-		/// Event invoked when the content area of the View is completed drawing.
-		/// </summary>
-		/// <remarks>
-		/// <para>
-		/// Will be invoked after any subviews removed with <see cref="Remove(View)"/> have been completed drawing.
-		/// </para>
-		/// <para>
-		/// Rect provides the view-relative rectangle describing the currently visible viewport into the <see cref="View"/>.
-		/// </para>
-		/// </remarks>
-		public event EventHandler<DrawEventArgs> DrawContentComplete;
-
-		/// <summary>
-		/// Enables overrides after completed drawing infinitely scrolled content and/or a background behind removed controls.
-		/// </summary>
-		/// <param name="contentArea">The view-relative rectangle describing the currently visible viewport into the <see cref="View"/></param>
-		/// <remarks>
-		/// This method will be called after any subviews removed with <see cref="Remove(View)"/> have been completed drawing.
-		/// </remarks>
-		public virtual void OnDrawContentComplete (Rect contentArea)
-		{
-			DrawContentComplete?.Invoke (this, new DrawEventArgs (contentArea));
-		}
+		// Draw subviews
+		// TODO: Implement OnDrawSubviews (cancelable);
+		if (_subviews != null && SubViewNeedsDisplay) {
+			var subviewsNeedingDraw = _subviews.Where (
+				view => view.Visible &&
+					(view.NeedsDisplay ||
+					view.SubViewNeedsDisplay ||
+					view.LayoutNeeded)
+			);
+
+			foreach (var view in subviewsNeedingDraw) {
+				//view.Frame.IntersectsWith (bounds)) {
+				// && (view.Frame.IntersectsWith (bounds) || bounds.X < 0 || bounds.Y < 0)) {
+				if (view.LayoutNeeded) {
+					view.LayoutSubviews ();
+				}
 
+				// Draw the subview
+				// Use the view's bounds (view-relative; Location will always be (0,0)
+				//if (view.Visible && view.Frame.Width > 0 && view.Frame.Height > 0) {
+				view.Draw ();
+				//}
+			}
+		}
 	}
+
+	/// <summary>
+	/// Event invoked when the content area of the View is completed drawing.
+	/// </summary>
+	/// <remarks>
+	/// <para>
+	/// Will be invoked after any subviews removed with <see cref="Remove(View)"/> have been completed drawing.
+	/// </para>
+	/// <para>
+	/// Rect provides the view-relative rectangle describing the currently visible viewport into the <see cref="View"/>.
+	/// </para>
+	/// </remarks>
+	public event EventHandler<DrawEventArgs> DrawContentComplete;
+
+	/// <summary>
+	/// Enables overrides after completed drawing infinitely scrolled content and/or a background behind removed controls.
+	/// </summary>
+	/// <param name="contentArea">The view-relative rectangle describing the currently visible viewport into the <see cref="View"/></param>
+	/// <remarks>
+	/// This method will be called after any subviews removed with <see cref="Remove(View)"/> have been completed drawing.
+	/// </remarks>
+	public virtual void OnDrawContentComplete (Rect contentArea) => DrawContentComplete?.Invoke (this, new DrawEventArgs (contentArea));
 }

+ 3 - 2
Terminal.Gui/View/ViewSubViews.cs

@@ -82,14 +82,15 @@ namespace Terminal.Gui {
 				view._oldEnabled = true;
 				view.Enabled = false;
 			}
-			SetNeedsLayout ();
-			SetNeedsDisplay ();
 
 			OnAdded (new SuperViewChangedEventArgs (this, view));
 			if (IsInitialized && !view.IsInitialized) {
 				view.BeginInit ();
 				view.EndInit ();
 			}
+
+			SetNeedsLayout ();
+			SetNeedsDisplay ();
 		}
 
 		/// <summary>

+ 212 - 216
Terminal.Gui/View/ViewText.cs

@@ -1,260 +1,256 @@
-using System.Text;
-using System;
+using System;
 using System.Collections.Generic;
 
-namespace Terminal.Gui {
+namespace Terminal.Gui;
 
-	public partial class View {
-		string _text;
+public partial class View {
+	string _text;
 
-		/// <summary>
-		///   The text displayed by the <see cref="View"/>.
-		/// </summary>
-		/// <remarks>
-		/// <para>
-		///  The text will be drawn before any subviews are drawn.
-		/// </para>
-		/// <para>
-		///  The text will be drawn starting at the view origin (0, 0) and will be formatted according
-		///  to <see cref="TextAlignment"/> and <see cref="TextDirection"/>. 
-		/// </para>
-		/// <para>
-		///  The text will word-wrap to additional lines if it does not fit horizontally. If <see cref="Bounds"/>'s height
-		///  is 1, the text will be clipped.	
-		///  </para>
-		/// <para>
-		///  Set the <see cref="HotKeySpecifier"/> to enable hotkey support. To disable hotkey support set <see cref="HotKeySpecifier"/> to
-		///  <c>(Rune)0xffff</c>.
-		/// </para>
-		/// </remarks>
-		public virtual string Text {
-			get => _text;
-			set {
-				_text = value;
-				SetHotKey ();
-				UpdateTextFormatterText ();
-				//TextFormatter.Format ();
-				OnResizeNeeded ();
+	/// <summary>
+	///   The text displayed by the <see cref="View"/>.
+	/// </summary>
+	/// <remarks>
+	/// <para>
+	///  The text will be drawn before any subviews are drawn.
+	/// </para>
+	/// <para>
+	///  The text will be drawn starting at the view origin (0, 0) and will be formatted according
+	///  to <see cref="TextAlignment"/> and <see cref="TextDirection"/>. 
+	/// </para>
+	/// <para>
+	///  The text will word-wrap to additional lines if it does not fit horizontally. If <see cref="Bounds"/>'s height
+	///  is 1, the text will be clipped.	
+	///  </para>
+	/// <para>
+	///  Set the <see cref="HotKeySpecifier"/> to enable hotkey support. To disable hotkey support set <see cref="HotKeySpecifier"/> to
+	///  <c>(Rune)0xffff</c>.
+	/// </para>
+	/// </remarks>
+	public virtual string Text {
+		get => _text;
+		set {
+			_text = value;
+			SetHotKey ();
+			UpdateTextFormatterText ();
+			//TextFormatter.Format ();
+			OnResizeNeeded ();
 
 #if DEBUG
-				if (_text != null && string.IsNullOrEmpty (Id)) {
-					Id = _text;
-				}
-#endif
+			if (_text != null && string.IsNullOrEmpty (Id)) {
+				Id = _text;
 			}
+#endif
 		}
+	}
 
-		/// <summary>
-		/// Gets or sets the <see cref="Gui.TextFormatter"/> used to format <see cref="Text"/>.
-		/// </summary>
-		public TextFormatter TextFormatter { get; set; }
+	/// <summary>
+	/// Gets or sets the <see cref="Gui.TextFormatter"/> used to format <see cref="Text"/>.
+	/// </summary>
+	public TextFormatter TextFormatter { get; set; }
 
-		/// <summary>
-		/// Can be overridden if the <see cref="Terminal.Gui.TextFormatter.Text"/> has
-		///  different format than the default.
-		/// </summary>
-		protected virtual void UpdateTextFormatterText ()
-		{
-			if (TextFormatter != null) {
-				TextFormatter.Text = _text;
-			}
+	/// <summary>
+	/// Can be overridden if the <see cref="Terminal.Gui.TextFormatter.Text"/> has
+	///  different format than the default.
+	/// </summary>
+	protected virtual void UpdateTextFormatterText ()
+	{
+		if (TextFormatter != null) {
+			TextFormatter.Text = _text;
 		}
+	}
 
-		/// <summary>
-		/// Gets or sets whether trailing spaces at the end of word-wrapped lines are preserved
-		/// or not when <see cref="TextFormatter.WordWrap"/> is enabled. 
-		/// If <see langword="true"/> trailing spaces at the end of wrapped lines will be removed when 
-		/// <see cref="Text"/> is formatted for display. The default is <see langword="false"/>.
-		/// </summary>
-		public virtual bool PreserveTrailingSpaces {
-			get => TextFormatter.PreserveTrailingSpaces;
-			set {
-				if (TextFormatter.PreserveTrailingSpaces != value) {
-					TextFormatter.PreserveTrailingSpaces = value;
-					TextFormatter.NeedsFormat = true;
-				}
+	/// <summary>
+	/// Gets or sets whether trailing spaces at the end of word-wrapped lines are preserved
+	/// or not when <see cref="TextFormatter.WordWrap"/> is enabled. 
+	/// If <see langword="true"/> trailing spaces at the end of wrapped lines will be removed when 
+	/// <see cref="Text"/> is formatted for display. The default is <see langword="false"/>.
+	/// </summary>
+	public virtual bool PreserveTrailingSpaces {
+		get => TextFormatter.PreserveTrailingSpaces;
+		set {
+			if (TextFormatter.PreserveTrailingSpaces != value) {
+				TextFormatter.PreserveTrailingSpaces = value;
+				TextFormatter.NeedsFormat = true;
 			}
 		}
+	}
 
-		/// <summary>
-		/// Gets or sets how the View's <see cref="Text"/> is aligned horizontally when drawn. Changing this property will redisplay the <see cref="View"/>.
-		/// </summary>
-		/// <value>The text alignment.</value>
-		public virtual TextAlignment TextAlignment {
-			get => TextFormatter.Alignment;
-			set {
-				TextFormatter.Alignment = value;
-				UpdateTextFormatterText ();
-				OnResizeNeeded ();
-			}
+	/// <summary>
+	/// Gets or sets how the View's <see cref="Text"/> is aligned horizontally when drawn. Changing this property will redisplay the <see cref="View"/>.
+	/// </summary>
+	/// <value>The text alignment.</value>
+	public virtual TextAlignment TextAlignment {
+		get => TextFormatter.Alignment;
+		set {
+			TextFormatter.Alignment = value;
+			UpdateTextFormatterText ();
+			OnResizeNeeded ();
 		}
+	}
 
-		/// <summary>
-		/// Gets or sets how the View's <see cref="Text"/> is aligned vertically when drawn. Changing this property will redisplay the <see cref="View"/>.
-		/// </summary>
-		/// <value>The text alignment.</value>
-		public virtual VerticalTextAlignment VerticalTextAlignment {
-			get => TextFormatter.VerticalAlignment;
-			set {
-				TextFormatter.VerticalAlignment = value;
-				SetNeedsDisplay ();
-			}
+	/// <summary>
+	/// Gets or sets how the View's <see cref="Text"/> is aligned vertically when drawn. Changing this property will redisplay the <see cref="View"/>.
+	/// </summary>
+	/// <value>The text alignment.</value>
+	public virtual VerticalTextAlignment VerticalTextAlignment {
+		get => TextFormatter.VerticalAlignment;
+		set {
+			TextFormatter.VerticalAlignment = value;
+			SetNeedsDisplay ();
 		}
+	}
 
-		/// <summary>
-		/// Gets or sets the direction of the View's <see cref="Text"/>. Changing this property will redisplay the <see cref="View"/>.
-		/// </summary>
-		/// <value>The text alignment.</value>
-		public virtual TextDirection TextDirection {
-			get => TextFormatter.Direction;
-			set {
-				UpdateTextDirection (value);
-				TextFormatter.Direction = value;
-			}
+	/// <summary>
+	/// Gets or sets the direction of the View's <see cref="Text"/>. Changing this property will redisplay the <see cref="View"/>.
+	/// </summary>
+	/// <value>The text alignment.</value>
+	public virtual TextDirection TextDirection {
+		get => TextFormatter.Direction;
+		set {
+			UpdateTextDirection (value);
+			TextFormatter.Direction = value;
 		}
+	}
 
-		private void UpdateTextDirection (TextDirection newDirection)
-		{
-			var directionChanged = TextFormatter.IsHorizontalDirection (TextFormatter.Direction)
-			    != TextFormatter.IsHorizontalDirection (newDirection);
-			TextFormatter.Direction = newDirection;
+	void UpdateTextDirection (TextDirection newDirection)
+	{
+		bool directionChanged = TextFormatter.IsHorizontalDirection (TextFormatter.Direction)
+					!= TextFormatter.IsHorizontalDirection (newDirection);
+		TextFormatter.Direction = newDirection;
 
-			var isValidOldAutoSize = AutoSize && IsValidAutoSize (out var _);
+		bool isValidOldAutoSize = AutoSize && IsValidAutoSize (out var _);
 
-			UpdateTextFormatterText ();
+		UpdateTextFormatterText ();
 
-			if ((!ValidatePosDim && directionChanged && AutoSize)
-			    || (ValidatePosDim && directionChanged && AutoSize && isValidOldAutoSize)) {
-				OnResizeNeeded ();
-			} else if (directionChanged && IsAdded) {
-				ResizeBoundsToFit (Bounds.Size);
-				// BUGBUG: I think this call is redundant.
-				SetFrameToFitText ();
-			} else {
-				SetFrameToFitText ();
-			}
-			TextFormatter.Size = GetTextFormatterSizeNeededForTextAndHotKey ();
-			SetNeedsDisplay ();
+		if (!ValidatePosDim && directionChanged && AutoSize
+		|| ValidatePosDim && directionChanged && AutoSize && isValidOldAutoSize) {
+			OnResizeNeeded ();
+		} else if (directionChanged && IsAdded) {
+			ResizeBoundsToFit (Bounds.Size);
+			// BUGBUG: I think this call is redundant.
+			SetFrameToFitText ();
+		} else {
+			SetFrameToFitText ();
 		}
+		TextFormatter.Size = GetTextFormatterSizeNeededForTextAndHotKey ();
+		SetNeedsDisplay ();
+	}
 
 
-		/// <summary>
-		/// Sets the size of the View to the minimum width or height required to fit <see cref="Text"/>. 
-		/// </summary>
-		/// <returns><see langword="true"/> if the size was changed; <see langword="false"/> if <see cref="AutoSize"/> == <see langword="true"/> or
-		/// <see cref="Text"/> will not fit.</returns>
-		/// <remarks>
-		/// Always returns <see langword="false"/> if <see cref="AutoSize"/> is <see langword="true"/> or
-		/// if <see cref="Height"/> (Horizontal) or <see cref="Width"/> (Vertical) are not not set or zero.
-		/// Does not take into account word wrapping.
-		/// </remarks>
-		bool SetFrameToFitText ()
+	/// <summary>
+	/// Sets the size of the View to the minimum width or height required to fit <see cref="Text"/>. 
+	/// </summary>
+	/// <returns><see langword="true"/> if the size was changed; <see langword="false"/> if <see cref="AutoSize"/> == <see langword="true"/> or
+	/// <see cref="Text"/> will not fit.</returns>
+	/// <remarks>
+	/// Always returns <see langword="false"/> if <see cref="AutoSize"/> is <see langword="true"/> or
+	/// if <see cref="Height"/> (Horizontal) or <see cref="Width"/> (Vertical) are not not set or zero.
+	/// Does not take into account word wrapping.
+	/// </remarks>
+	bool SetFrameToFitText ()
+	{
+		// BUGBUG: This API is broken - should not assume Frame.Height == Bounds.Height
+		// <summary>
+		// Gets the minimum dimensions required to fit the View's <see cref="Text"/>, factoring in <see cref="TextDirection"/>.
+		// </summary>
+		// <param name="sizeRequired">The minimum dimensions required.</param>
+		// <returns><see langword="true"/> if the dimensions fit within the View's <see cref="Bounds"/>, <see langword="false"/> otherwise.</returns>
+		// <remarks>
+		// Always returns <see langword="false"/> if <see cref="AutoSize"/> is <see langword="true"/> or
+		// if <see cref="Height"/> (Horizontal) or <see cref="Width"/> (Vertical) are not not set or zero.
+		// Does not take into account word wrapping.
+		// </remarks>
+		bool GetMinimumSizeOfText (out Size sizeRequired)
 		{
-			// BUGBUG: This API is broken - should not assume Frame.Height == Bounds.Height
-			// <summary>
-			// Gets the minimum dimensions required to fit the View's <see cref="Text"/>, factoring in <see cref="TextDirection"/>.
-			// </summary>
-			// <param name="sizeRequired">The minimum dimensions required.</param>
-			// <returns><see langword="true"/> if the dimensions fit within the View's <see cref="Bounds"/>, <see langword="false"/> otherwise.</returns>
-			// <remarks>
-			// Always returns <see langword="false"/> if <see cref="AutoSize"/> is <see langword="true"/> or
-			// if <see cref="Height"/> (Horizontal) or <see cref="Width"/> (Vertical) are not not set or zero.
-			// Does not take into account word wrapping.
-			// </remarks>
-			bool GetMinimumSizeOfText (out Size sizeRequired)
-			{
-				if (!IsInitialized) {
-					sizeRequired = new Size (0, 0);
-					return false;
-				}
-				sizeRequired = Bounds.Size;
-
-				if (!AutoSize && !string.IsNullOrEmpty (TextFormatter.Text)) {
-					switch (TextFormatter.IsVerticalDirection (TextDirection)) {
-					case true:
-						int colWidth = TextFormatter.GetSumMaxCharWidth (new List<string> { TextFormatter.Text }, 0, 1);
-						// TODO: v2 - This uses frame.Width; it should only use Bounds
-						if (_frame.Width < colWidth &&
-						(Width == null ||
-						Bounds.Width >= 0 &&
-						Width is Dim.DimAbsolute &&
-						Width.Anchor (0) >= 0 &&
-						Width.Anchor (0) < colWidth)) {
-							sizeRequired = new Size (colWidth, Bounds.Height);
-							return true;
-						}
-						break;
-					default:
-						if (_frame.Height < 1 &&
-						(Height == null ||
-						Height is Dim.DimAbsolute &&
-						Height.Anchor (0) == 0)) {
-							sizeRequired = new Size (Bounds.Width, 1);
-							return true;
-						}
-						break;
-					}
-				}
+			if (!IsInitialized) {
+				sizeRequired = new Size (0, 0);
 				return false;
 			}
+			sizeRequired = Bounds.Size;
 
-			if (GetMinimumSizeOfText (out var size)) {
-				_frame = new Rect (_frame.Location, size);
-				return true;
+			if (!AutoSize && !string.IsNullOrEmpty (TextFormatter.Text)) {
+				switch (TextFormatter.IsVerticalDirection (TextDirection)) {
+				case true:
+					int colWidth = TextFormatter.GetSumMaxCharWidth (new List<string> { TextFormatter.Text }, 0, 1);
+					// TODO: v2 - This uses frame.Width; it should only use Bounds
+					if (_frame.Width < colWidth &&
+					(Width == null ||
+					Bounds.Width >= 0 &&
+					Width is Dim.DimAbsolute &&
+					Width.Anchor (0) >= 0 &&
+					Width.Anchor (0) < colWidth)) {
+						sizeRequired = new Size (colWidth, Bounds.Height);
+						return true;
+					}
+					break;
+				default:
+					if (_frame.Height < 1 &&
+					(Height == null ||
+					Height is Dim.DimAbsolute &&
+					Height.Anchor (0) == 0)) {
+						sizeRequired = new Size (Bounds.Width, 1);
+						return true;
+					}
+					break;
+				}
 			}
 			return false;
 		}
 
-		/// <summary>
-		/// Gets the width or height of the <see cref="Terminal.Gui.TextFormatter.HotKeySpecifier"/> characters 
-		/// in the <see cref="Text"/> property.
-		/// </summary>
-		/// <remarks>
-		/// Only the first hotkey specifier found in <see cref="Text"/> is supported.
-		/// </remarks>
-		/// <param name="isWidth">If <see langword="true"/> (the default) the width required for the hotkey specifier is returned. Otherwise the height is returned.</param>
-		/// <returns>The number of characters required for the <see cref="Terminal.Gui.TextFormatter.HotKeySpecifier"/>. If the text direction specified
-		/// by <see cref="TextDirection"/> does not match the <paramref name="isWidth"/> parameter, <c>0</c> is returned.</returns>
-		public int GetHotKeySpecifierLength (bool isWidth = true)
-		{
-			if (isWidth) {
-				return TextFormatter.IsHorizontalDirection (TextDirection) &&
-				    TextFormatter.Text?.Contains ((char)HotKeySpecifier.Value) == true
-				    ? Math.Max (HotKeySpecifier.GetColumns (), 0) : 0;
-			} else {
-				return TextFormatter.IsVerticalDirection (TextDirection) &&
-				    TextFormatter.Text?.Contains ((char)HotKeySpecifier.Value) == true
-				    ? Math.Max (HotKeySpecifier.GetColumns (), 0) : 0;
-			}
+		if (GetMinimumSizeOfText (out var size)) {
+			_frame = new Rect (_frame.Location, size);
+			return true;
 		}
+		return false;
+	}
 
-		/// <summary>
-		/// Gets the dimensions required for <see cref="Text"/> ignoring a <see cref="Terminal.Gui.TextFormatter.HotKeySpecifier"/>.
-		/// </summary>
-		/// <returns></returns>
-		public Size GetSizeNeededForTextWithoutHotKey ()
-		{
-			return new Size (TextFormatter.Size.Width - GetHotKeySpecifierLength (),
-			    TextFormatter.Size.Height - GetHotKeySpecifierLength (false));
+	/// <summary>
+	/// Gets the width or height of the <see cref="Terminal.Gui.TextFormatter.HotKeySpecifier"/> characters 
+	/// in the <see cref="Text"/> property.
+	/// </summary>
+	/// <remarks>
+	/// Only the first hotkey specifier found in <see cref="Text"/> is supported.
+	/// </remarks>
+	/// <param name="isWidth">If <see langword="true"/> (the default) the width required for the hotkey specifier is returned. Otherwise the height is returned.</param>
+	/// <returns>The number of characters required for the <see cref="Terminal.Gui.TextFormatter.HotKeySpecifier"/>. If the text direction specified
+	/// by <see cref="TextDirection"/> does not match the <paramref name="isWidth"/> parameter, <c>0</c> is returned.</returns>
+	public int GetHotKeySpecifierLength (bool isWidth = true)
+	{
+		if (isWidth) {
+			return TextFormatter.IsHorizontalDirection (TextDirection) &&
+				TextFormatter.Text?.Contains ((char)HotKeySpecifier.Value) == true
+				? Math.Max (HotKeySpecifier.GetColumns (), 0) : 0;
+		} else {
+			return TextFormatter.IsVerticalDirection (TextDirection) &&
+				TextFormatter.Text?.Contains ((char)HotKeySpecifier.Value) == true
+				? Math.Max (HotKeySpecifier.GetColumns (), 0) : 0;
 		}
+	}
 
-		/// <summary>
-		/// Gets the dimensions required for <see cref="Text"/> accounting for a <see cref="Terminal.Gui.TextFormatter.HotKeySpecifier"/> .
-		/// </summary>
-		/// <returns></returns>
-		public Size GetTextFormatterSizeNeededForTextAndHotKey ()
-		{
-			if (string.IsNullOrEmpty (TextFormatter.Text)) {
-
-				if (!IsInitialized) return Size.Empty;
+	/// <summary>
+	/// Gets the dimensions required for <see cref="Text"/> ignoring a <see cref="Terminal.Gui.TextFormatter.HotKeySpecifier"/>.
+	/// </summary>
+	/// <returns></returns>
+	public Size GetSizeNeededForTextWithoutHotKey () => new (TextFormatter.Size.Width - GetHotKeySpecifierLength (),
+		TextFormatter.Size.Height - GetHotKeySpecifierLength (false));
 
-				return Bounds.Size;
-			}
+	/// <summary>
+	/// Gets the dimensions required for <see cref="Text"/> accounting for a <see cref="Terminal.Gui.TextFormatter.HotKeySpecifier"/> .
+	/// </summary>
+	/// <returns></returns>
+	public Size GetTextFormatterSizeNeededForTextAndHotKey ()
+	{
+		if (!IsInitialized) {
+			return Size.Empty;
+		}
 
-			// BUGBUG: This IGNORES what Text is set to, using on only the current View size. This doesn't seem to make sense.
-			// BUGBUG: This uses Frame; in v2 it should be Bounds
-			return new Size (Bounds.Size.Width + GetHotKeySpecifierLength (),
-					 Bounds.Size.Height + GetHotKeySpecifierLength (false));
+		if (string.IsNullOrEmpty (TextFormatter.Text)) {
+			return Bounds.Size;
 		}
+
+		// BUGBUG: This IGNORES what Text is set to, using on only the current View size. This doesn't seem to make sense.
+		// BUGBUG: This uses Frame; in v2 it should be Bounds
+		return new Size (Bounds.Size.Width + GetHotKeySpecifierLength (),
+			Bounds.Size.Height + GetHotKeySpecifierLength (false));
 	}
 }

+ 6 - 2
Terminal.Gui/Views/ColorPicker.cs

@@ -51,7 +51,9 @@ namespace Terminal.Gui {
 			set {
 				if (_boxWidth != value) {
 					_boxWidth = value;
-					Bounds = new Rect (Bounds.Location, new Size (_cols * BoxWidth, _rows * BoxHeight));
+					if (IsInitialized) {
+						Bounds = new Rect (Bounds.Location, new Size (_cols * BoxWidth, _rows * BoxHeight));
+					}
 				}
 			}
 		}
@@ -65,7 +67,9 @@ namespace Terminal.Gui {
 			set {
 				if (_boxHeight != value) {
 					_boxHeight = value;
-					Bounds = new Rect (Bounds.Location, new Size (_cols * BoxWidth, _rows * BoxHeight));
+					if (IsInitialized) {
+						Bounds = new Rect (Bounds.Location, new Size (_cols * BoxWidth, _rows * BoxHeight));
+					}
 				}
 			}
 		}

+ 682 - 710
Terminal.Gui/Views/ComboBox.cs

@@ -10,881 +10,853 @@ using System.Collections;
 using System.Collections.Generic;
 using System.Text;
 
-namespace Terminal.Gui {
-	/// <summary>
-	/// Provides a drop-down list of items the user can select from.
-	/// </summary>
-	public class ComboBox : View {
+namespace Terminal.Gui; 
 
-		private class ComboListView : ListView {
-			private int highlighted = -1;
-			private bool isFocusing;
-			private ComboBox container;
-			private bool hideDropdownListOnClick;
+/// <summary>
+/// Provides a drop-down list of items the user can select from.
+/// </summary>
+public class ComboBox : View {
+	class ComboListView : ListView {
+		int _highlighted = -1;
+		bool _isFocusing;
+		ComboBox _container;
+		bool _hideDropdownListOnClick;
 
-			public ComboListView (ComboBox container, bool hideDropdownListOnClick)
-			{
-				Initialize (container, hideDropdownListOnClick);
-			}
+		public ComboListView (ComboBox container, bool hideDropdownListOnClick) => SetInitialProperties (container, hideDropdownListOnClick);
 
-			public ComboListView (ComboBox container, Rect rect, IList source, bool hideDropdownListOnClick) : base (rect, source)
-			{
-				Initialize (container, hideDropdownListOnClick);
-			}
+		public ComboListView (ComboBox container, Rect rect, IList source, bool hideDropdownListOnClick) : base (rect, source) => SetInitialProperties (container, hideDropdownListOnClick);
 
-			public ComboListView (ComboBox container, IList source, bool hideDropdownListOnClick) : base (source)
-			{
-				Initialize (container, hideDropdownListOnClick);
-			}
+		public ComboListView (ComboBox container, IList source, bool hideDropdownListOnClick) : base (source) => SetInitialProperties (container, hideDropdownListOnClick);
 
-			private void Initialize (ComboBox container, bool hideDropdownListOnClick)
-			{
-				this.container = container ?? throw new ArgumentNullException (nameof (container), "ComboBox container cannot be null.");
-				HideDropdownListOnClick = hideDropdownListOnClick;
-			}
+		void SetInitialProperties (ComboBox container, bool hideDropdownListOnClick)
+		{
+			_container = container ?? throw new ArgumentNullException (nameof (container), "ComboBox container cannot be null.");
+			HideDropdownListOnClick = hideDropdownListOnClick;
+		}
 
-			public bool HideDropdownListOnClick {
-				get => hideDropdownListOnClick;
-				set => hideDropdownListOnClick = WantContinuousButtonPressed = value;
-			}
+		public bool HideDropdownListOnClick {
+			get => _hideDropdownListOnClick;
+			set => _hideDropdownListOnClick = WantContinuousButtonPressed = value;
+		}
 
-			public override bool MouseEvent (MouseEvent me)
-			{
-				var res = false;
-				var isMousePositionValid = IsMousePositionValid (me);
+		public override bool MouseEvent (MouseEvent me)
+		{
+			bool res = false;
+			bool isMousePositionValid = IsMousePositionValid (me);
 
+			if (isMousePositionValid) {
+				res = base.MouseEvent (me);
+			}
+
+			if (HideDropdownListOnClick && me.Flags == MouseFlags.Button1Clicked) {
+				if (!isMousePositionValid && !_isFocusing) {
+					_container._isShow = false;
+					_container.HideList ();
+				} else if (isMousePositionValid) {
+					OnOpenSelectedItem ();
+				} else {
+					_isFocusing = false;
+				}
+				return true;
+			} else if (me.Flags == MouseFlags.ReportMousePosition && HideDropdownListOnClick) {
 				if (isMousePositionValid) {
-					res = base.MouseEvent (me);
+					_highlighted = Math.Min (TopItem + me.Y, Source.Count);
+					SetNeedsDisplay ();
 				}
+				_isFocusing = false;
+				return true;
+			}
 
-				if (HideDropdownListOnClick && me.Flags == MouseFlags.Button1Clicked) {
-					if (!isMousePositionValid && !isFocusing) {
-						container.isShow = false;
-						container.HideList ();
-					} else if (isMousePositionValid) {
-						OnOpenSelectedItem ();
-					} else {
-						isFocusing = false;
-					}
-					return true;
-				} else if (me.Flags == MouseFlags.ReportMousePosition && HideDropdownListOnClick) {
-					if (isMousePositionValid) {
-						highlighted = Math.Min (TopItem + me.Y, Source.Count);
-						SetNeedsDisplay ();
-					}
-					isFocusing = false;
-					return true;
-				}
+			return res;
+		}
 
-				return res;
+		bool IsMousePositionValid (MouseEvent me)
+		{
+			if (me.X >= 0 && me.X < Frame.Width && me.Y >= 0 && me.Y < Frame.Height) {
+				return true;
 			}
+			return false;
+		}
 
-			private bool IsMousePositionValid (MouseEvent me)
-			{
-				if (me.X >= 0 && me.X < Frame.Width && me.Y >= 0 && me.Y < Frame.Height) {
-					return true;
+		public override void OnDrawContent (Rect contentArea)
+		{
+			var current = ColorScheme.Focus;
+			Driver.SetAttribute (current);
+			Move (0, 0);
+			var f = Frame;
+			int item = TopItem;
+			bool focused = HasFocus;
+			int col = AllowsMarking ? 2 : 0;
+			int start = LeftItem;
+
+			for (int row = 0; row < f.Height; row++, item++) {
+				bool isSelected = item == _container.SelectedItem;
+				bool isHighlighted = _hideDropdownListOnClick && item == _highlighted;
+
+				Attribute newcolor;
+				if (isHighlighted || isSelected && !_hideDropdownListOnClick) {
+					newcolor = focused ? ColorScheme.Focus : ColorScheme.HotNormal;
+				} else if (isSelected && _hideDropdownListOnClick) {
+					newcolor = focused ? ColorScheme.HotFocus : ColorScheme.HotNormal;
+				} else {
+					newcolor = focused ? GetNormalColor () : GetNormalColor ();
 				}
-				return false;
-			}
 
-			public override void OnDrawContent (Rect contentArea)
-			{
-				var current = ColorScheme.Focus;
-				Driver.SetAttribute (current);
-				Move (0, 0);
-				var f = Frame;
-				var item = TopItem;
-				bool focused = HasFocus;
-				int col = AllowsMarking ? 2 : 0;
-				int start = LeftItem;
-
-				for (int row = 0; row < f.Height; row++, item++) {
-					bool isSelected = item == container.SelectedItem;
-					bool isHighlighted = hideDropdownListOnClick && item == highlighted;
-
-					Attribute newcolor;
-					if (isHighlighted || (isSelected && !hideDropdownListOnClick)) {
-						newcolor = focused ? ColorScheme.Focus : ColorScheme.HotNormal;
-					} else if (isSelected && hideDropdownListOnClick) {
-						newcolor = focused ? ColorScheme.HotFocus : ColorScheme.HotNormal;
-					} else {
-						newcolor = focused ? GetNormalColor () : GetNormalColor ();
-					}
+				if (newcolor != current) {
+					Driver.SetAttribute (newcolor);
+					current = newcolor;
+				}
 
-					if (newcolor != current) {
-						Driver.SetAttribute (newcolor);
-						current = newcolor;
+				Move (0, row);
+				if (Source == null || item >= Source.Count) {
+					for (int c = 0; c < f.Width; c++) {
+						Driver.AddRune ((Rune)' ');
 					}
-
-					Move (0, row);
-					if (Source == null || item >= Source.Count) {
-						for (int c = 0; c < f.Width; c++)
-							Driver.AddRune ((Rune)' ');
-					} else {
-						var rowEventArgs = new ListViewRowEventArgs (item);
-						OnRowRender (rowEventArgs);
-						if (rowEventArgs.RowAttribute != null && current != rowEventArgs.RowAttribute) {
-							current = (Attribute)rowEventArgs.RowAttribute;
-							Driver.SetAttribute (current);
-						}
-						if (AllowsMarking) {
-							Driver.AddRune (Source.IsMarked (item) ? (AllowsMultipleSelection ? CM.Glyphs.Checked : CM.Glyphs.Selected) : (AllowsMultipleSelection ? CM.Glyphs.UnChecked : CM.Glyphs.UnSelected));
-							Driver.AddRune ((Rune)' ');
-						}
-						Source.Render (this, Driver, isSelected, item, col, row, f.Width - col, start);
+				} else {
+					var rowEventArgs = new ListViewRowEventArgs (item);
+					OnRowRender (rowEventArgs);
+					if (rowEventArgs.RowAttribute != null && current != rowEventArgs.RowAttribute) {
+						current = (Attribute)rowEventArgs.RowAttribute;
+						Driver.SetAttribute (current);
 					}
+					if (AllowsMarking) {
+						Driver.AddRune (Source.IsMarked (item) ? AllowsMultipleSelection ? Glyphs.Checked : Glyphs.Selected : AllowsMultipleSelection ? Glyphs.UnChecked : Glyphs.UnSelected);
+						Driver.AddRune ((Rune)' ');
+					}
+					Source.Render (this, Driver, isSelected, item, col, row, f.Width - col, start);
 				}
 			}
+		}
 
-			public override bool OnEnter (View view)
-			{
-				if (hideDropdownListOnClick) {
-					isFocusing = true;
-					highlighted = container.SelectedItem;
-					Application.GrabMouse (this);
-				}
-
-				return base.OnEnter (view);
+		public override bool OnEnter (View view)
+		{
+			if (_hideDropdownListOnClick) {
+				_isFocusing = true;
+				_highlighted = _container.SelectedItem;
+				Application.GrabMouse (this);
 			}
 
-			public override bool OnLeave (View view)
-			{
-				if (hideDropdownListOnClick) {
-					isFocusing = false;
-					highlighted = container.SelectedItem;
-					Application.UngrabMouse ();
-				}
+			return base.OnEnter (view);
+		}
 
-				return base.OnLeave (view);
+		public override bool OnLeave (View view)
+		{
+			if (_hideDropdownListOnClick) {
+				_isFocusing = false;
+				_highlighted = _container.SelectedItem;
+				Application.UngrabMouse ();
 			}
 
-			public override bool OnSelectedChanged ()
-			{
-				var res = base.OnSelectedChanged ();
+			return base.OnLeave (view);
+		}
 
-				highlighted = SelectedItem;
+		public override bool OnSelectedChanged ()
+		{
+			bool res = base.OnSelectedChanged ();
 
-				return res;
-			}
-		}
+			_highlighted = SelectedItem;
 
-		IListDataSource source;
-		/// <summary>
-		/// Gets or sets the <see cref="IListDataSource"/> backing this <see cref="ComboBox"/>, enabling custom rendering.
-		/// </summary>
-		/// <value>The source.</value>
-		/// <remarks>
-		///  Use <see cref="SetSource"/> to set a new <see cref="IList"/> source.
-		/// </remarks>
-		public IListDataSource Source {
-			get => source;
-			set {
-				source = value;
-
-				// Only need to refresh list if its been added to a container view
-				if (SuperView != null && SuperView.Subviews.Contains (this)) {
-					SelectedItem = -1;
-					search.Text = "";
-					Search_Changed (this, new TextChangedEventArgs (""));
-					SetNeedsDisplay ();
-				}
-			}
+			return res;
 		}
+	}
 
-		/// <summary>
-		/// Sets the source of the <see cref="ComboBox"/> to an <see cref="IList"/>.
-		/// </summary>
-		/// <value>An object implementing the IList interface.</value>
-		/// <remarks>
-		///  Use the <see cref="Source"/> property to set a new <see cref="IListDataSource"/> source and use custome rendering.
-		/// </remarks>
-		public void SetSource (IList source)
-		{
-			if (source == null) {
-				Source = null;
-			} else {
-				listview.SetSource (source);
-				Source = listview.Source;
+	IListDataSource _source;
+
+	/// <summary>
+	/// Gets or sets the <see cref="IListDataSource"/> backing this <see cref="ComboBox"/>, enabling custom rendering.
+	/// </summary>
+	/// <value>The source.</value>
+	/// <remarks>
+	///  Use <see cref="SetSource"/> to set a new <see cref="IList"/> source.
+	/// </remarks>
+	public IListDataSource Source {
+		get => _source;
+		set {
+			_source = value;
+
+			// Only need to refresh list if its been added to a container view
+			if (SuperView != null && SuperView.Subviews.Contains (this)) {
+				SelectedItem = -1;
+				_search.Text = "";
+				Search_Changed (this, new TextChangedEventArgs (""));
+				SetNeedsDisplay ();
 			}
 		}
+	}
 
-		/// <summary>
-		/// This event is raised when the selected item in the <see cref="ComboBox"/> has changed.
-		/// </summary>
-		public event EventHandler<ListViewItemEventArgs> SelectedItemChanged;
-
-		/// <summary>
-		/// This event is raised when the drop-down list is expanded.
-		/// </summary>
-		public event EventHandler Expanded;
-
-		/// <summary>
-		/// This event is raised when the drop-down list is collapsed.
-		/// </summary>
-		public event EventHandler Collapsed;
-
-		/// <summary>
-		/// This event is raised when the user Double Clicks on an item or presses ENTER to open the selected item.
-		/// </summary>
-		public event EventHandler<ListViewItemEventArgs> OpenSelectedItem;
-
-		readonly IList searchset = new List<object> ();
-		string text = "";
-		readonly TextField search;
-		readonly ComboListView listview;
-		bool autoHide = true;
-		readonly int minimumHeight = 2;
-
-		/// <summary>
-		/// Public constructor
-		/// </summary>
-		public ComboBox () : this (string.Empty)
-		{
+	/// <summary>
+	/// Sets the source of the <see cref="ComboBox"/> to an <see cref="IList"/>.
+	/// </summary>
+	/// <value>An object implementing the IList interface.</value>
+	/// <remarks>
+	///  Use the <see cref="Source"/> property to set a new <see cref="IListDataSource"/> source and use custome rendering.
+	/// </remarks>
+	public void SetSource (IList source)
+	{
+		if (source == null) {
+			Source = null;
+		} else {
+			_listview.SetSource (source);
+			Source = _listview.Source;
 		}
+	}
 
-		/// <summary>
-		/// Public constructor
-		/// </summary>
-		/// <param name="text"></param>
-		public ComboBox (string text) : base ()
-		{
-			search = new TextField ("");
-			listview = new ComboListView (this, HideDropdownListOnClick) { LayoutStyle = LayoutStyle.Computed, CanFocus = true, TabStop = false };
+	/// <summary>
+	/// This event is raised when the selected item in the <see cref="ComboBox"/> has changed.
+	/// </summary>
+	public event EventHandler<ListViewItemEventArgs> SelectedItemChanged;
 
-			Initialize ();
-			Text = text;
-		}
+	/// <summary>
+	/// This event is raised when the drop-down list is expanded.
+	/// </summary>
+	public event EventHandler Expanded;
 
-		/// <summary>
-		/// Public constructor
-		/// </summary>
-		/// <param name="rect"></param>
-		/// <param name="source"></param>
-		public ComboBox (Rect rect, IList source) : base (rect)
-		{
-			search = new TextField ("") { Width = rect.Width };
-			listview = new ComboListView (this, rect, source, HideDropdownListOnClick) { LayoutStyle = LayoutStyle.Computed, ColorScheme = Colors.Base };
+	/// <summary>
+	/// This event is raised when the drop-down list is collapsed.
+	/// </summary>
+	public event EventHandler Collapsed;
 
-			Initialize ();
-			SetSource (source);
-		}
+	/// <summary>
+	/// This event is raised when the user Double Clicks on an item or presses ENTER to open the selected item.
+	/// </summary>
+	public event EventHandler<ListViewItemEventArgs> OpenSelectedItem;
 
-		/// <summary>
-		/// Initialize with the source.
-		/// </summary>
-		/// <param name="source">The source.</param>
-		public ComboBox (IList source) : this (string.Empty)
-		{
-			search = new TextField ("");
-			listview = new ComboListView (this, source, HideDropdownListOnClick) { LayoutStyle = LayoutStyle.Computed, ColorScheme = Colors.Base };
+	readonly IList _searchset = new List<object> ();
+	string _text = "";
+	readonly TextField _search;
+	readonly ComboListView _listview;
+	bool _autoHide = true;
+	readonly int _minimumHeight = 2;
 
-			Initialize ();
-			SetSource (source);
-		}
+	/// <summary>
+	/// Public constructor
+	/// </summary>
+	public ComboBox () : this (string.Empty) { }
 
-		private void Initialize ()
-		{
-			if (Bounds.Height < minimumHeight && (Height == null || Height is Dim.DimAbsolute)) {
-				Height = minimumHeight;
-			}
+	/// <summary>
+	/// Public constructor
+	/// </summary>
+	/// <param name="text"></param>
+	public ComboBox (string text) : base ()
+	{
+		_search = new TextField ("");
+		_listview = new ComboListView (this, HideDropdownListOnClick) { LayoutStyle = LayoutStyle.Computed, CanFocus = true, TabStop = false };
+
+		SetInitialProperties ();
+		Text = text;
+	}
 
-			search.TextChanged += Search_Changed;
+	/// <summary>
+	/// Public constructor
+	/// </summary>
+	/// <param name="rect"></param>
+	/// <param name="source"></param>
+	public ComboBox (Rect rect, IList source) : base (rect)
+	{
+		_search = new TextField ("") { Width = rect.Width };
+		_listview = new ComboListView (this, rect, source, HideDropdownListOnClick) { LayoutStyle = LayoutStyle.Computed, ColorScheme = Colors.Base };
+
+		SetInitialProperties ();
+		SetSource (source);
+	}
 
-			listview.Y = Pos.Bottom (search);
-			listview.OpenSelectedItem += (object sender, ListViewItemEventArgs a) => Selected ();
+	/// <summary>
+	/// Initialize with the source.
+	/// </summary>
+	/// <param name="source">The source.</param>
+	public ComboBox (IList source) : this (string.Empty)
+	{
+		_search = new TextField ("");
+		_listview = new ComboListView (this, source, HideDropdownListOnClick) { LayoutStyle = LayoutStyle.Computed, ColorScheme = Colors.Base };
+
+		SetInitialProperties ();
+		SetSource (source);
+	}
 
-			Add (search, listview);
+	void SetInitialProperties ()
+	{
+		_search.TextChanged += Search_Changed;
 
-			// On resize
-			LayoutComplete += (object sender, LayoutEventArgs a) => {
-				if ((!autoHide && Bounds.Width > 0 && search.Frame.Width != Bounds.Width) ||
-					(autoHide && Bounds.Width > 0 && search.Frame.Width != Bounds.Width - 1)) {
-					search.Width = listview.Width = autoHide ? Bounds.Width - 1 : Bounds.Width;
-					listview.Height = CalculatetHeight ();
-					search.SetRelativeLayout (Bounds);
-					listview.SetRelativeLayout (Bounds);
-				}
-			};
+		_listview.Y = Pos.Bottom (_search);
+		_listview.OpenSelectedItem += (object sender, ListViewItemEventArgs a) => Selected ();
 
-			listview.SelectedItemChanged += (object sender, ListViewItemEventArgs e) => {
+		Add (_search, _listview);
 
-				if (!HideDropdownListOnClick && searchset.Count > 0) {
-					SetValue (searchset [listview.SelectedItem]);
-				}
-			};
+		// On resize
+		LayoutComplete += (object sender, LayoutEventArgs a) => {
+			if (Bounds.Height < _minimumHeight && (Height == null || Height is Dim.DimAbsolute)) {
+				Height = _minimumHeight;
+			}
+			if (!_autoHide && Bounds.Width > 0 && _search.Frame.Width != Bounds.Width ||
+			_autoHide && Bounds.Width > 0 && _search.Frame.Width != Bounds.Width - 1) {
+				_search.Width = _listview.Width = _autoHide ? Bounds.Width - 1 : Bounds.Width;
+				_listview.Height = CalculatetHeight ();
+				_search.SetRelativeLayout (Bounds);
+				_listview.SetRelativeLayout (Bounds);
+			}
+		};
 
-			Added += (s, e) => {
+		_listview.SelectedItemChanged += (object sender, ListViewItemEventArgs e) => {
 
-				// Determine if this view is hosted inside a dialog and is the only control
-				for (View view = this.SuperView; view != null; view = view.SuperView) {
-					if (view is Dialog && SuperView != null && SuperView.Subviews.Count == 1 && SuperView.Subviews [0] == this) {
-						autoHide = false;
-						break;
-					}
-				}
+			if (!HideDropdownListOnClick && _searchset.Count > 0) {
+				SetValue (_searchset [_listview.SelectedItem]);
+			}
+		};
 
-				SetNeedsLayout ();
-				SetNeedsDisplay ();
-				Search_Changed (this, new TextChangedEventArgs (Text));
-			};
-
-			// Things this view knows how to do
-			AddCommand (Command.Accept, () => ActivateSelected ());
-			AddCommand (Command.ToggleExpandCollapse, () => ExpandCollapse ());
-			AddCommand (Command.Expand, () => Expand ());
-			AddCommand (Command.Collapse, () => Collapse ());
-			AddCommand (Command.LineDown, () => MoveDown ());
-			AddCommand (Command.LineUp, () => MoveUp ());
-			AddCommand (Command.PageDown, () => PageDown ());
-			AddCommand (Command.PageUp, () => PageUp ());
-			AddCommand (Command.TopHome, () => MoveHome ());
-			AddCommand (Command.BottomEnd, () => MoveEnd ());
-			AddCommand (Command.Cancel, () => CancelSelected ());
-			AddCommand (Command.UnixEmulation, () => UnixEmulation ());
-
-			// Default keybindings for this view
-			KeyBindings.Add (KeyCode.Enter, Command.Accept);
-			KeyBindings.Add (KeyCode.F4, Command.ToggleExpandCollapse);
-			KeyBindings.Add (KeyCode.CursorDown, Command.LineDown);
-			KeyBindings.Add (KeyCode.CursorUp, Command.LineUp);
-			KeyBindings.Add (KeyCode.PageDown, Command.PageDown);
-			KeyBindings.Add (KeyCode.PageUp, Command.PageUp);
-			KeyBindings.Add (KeyCode.Home, Command.TopHome);
-			KeyBindings.Add (KeyCode.End, Command.BottomEnd);
-			KeyBindings.Add (KeyCode.Esc, Command.Cancel);
-			KeyBindings.Add (KeyCode.U | KeyCode.CtrlMask, Command.UnixEmulation);
-		}
-
-		private bool isShow = false;
-		private int selectedItem = -1;
-		private int lastSelectedItem = -1;
-		private bool hideDropdownListOnClick;
-
-		/// <summary>
-		/// Gets the index of the currently selected item in the <see cref="Source"/>
-		/// </summary>
-		/// <value>The selected item or -1 none selected.</value>
-		public int SelectedItem {
-			get => selectedItem;
-			set {
-				if (selectedItem != value && (value == -1
-					|| (source != null && value > -1 && value < source.Count))) {
-
-					selectedItem = lastSelectedItem = value;
-					if (selectedItem != -1) {
-						SetValue (source.ToList () [selectedItem].ToString (), true);
-					} else {
-						SetValue ("", true);
-					}
-					OnSelectedChanged ();
+		Added += (s, e) => {
+
+			// Determine if this view is hosted inside a dialog and is the only control
+			for (var view = SuperView; view != null; view = view.SuperView) {
+				if (view is Dialog && SuperView != null && SuperView.Subviews.Count == 1 && SuperView.Subviews [0] == this) {
+					_autoHide = false;
+					break;
 				}
 			}
-		}
 
-		/// <summary>
-		/// Gets the drop down list state, expanded or collapsed.
-		/// </summary>
-		public bool IsShow => isShow;
+			SetNeedsLayout ();
+			SetNeedsDisplay ();
+			Search_Changed (this, new TextChangedEventArgs (Text));
+		};
+
+		// Things this view knows how to do
+		AddCommand (Command.Accept, () => ActivateSelected ());
+		AddCommand (Command.ToggleExpandCollapse, () => ExpandCollapse ());
+		AddCommand (Command.Expand, () => Expand ());
+		AddCommand (Command.Collapse, () => Collapse ());
+		AddCommand (Command.LineDown, () => MoveDown ());
+		AddCommand (Command.LineUp, () => MoveUp ());
+		AddCommand (Command.PageDown, () => PageDown ());
+		AddCommand (Command.PageUp, () => PageUp ());
+		AddCommand (Command.TopHome, () => MoveHome ());
+		AddCommand (Command.BottomEnd, () => MoveEnd ());
+		AddCommand (Command.Cancel, () => CancelSelected ());
+		AddCommand (Command.UnixEmulation, () => UnixEmulation ());
+
+		// Default keybindings for this view
+		KeyBindings.Add (KeyCode.Enter, Command.Accept);
+		KeyBindings.Add (KeyCode.F4, Command.ToggleExpandCollapse);
+		KeyBindings.Add (KeyCode.CursorDown, Command.LineDown);
+		KeyBindings.Add (KeyCode.CursorUp, Command.LineUp);
+		KeyBindings.Add (KeyCode.PageDown, Command.PageDown);
+		KeyBindings.Add (KeyCode.PageUp, Command.PageUp);
+		KeyBindings.Add (KeyCode.Home, Command.TopHome);
+		KeyBindings.Add (KeyCode.End, Command.BottomEnd);
+		KeyBindings.Add (KeyCode.Esc, Command.Cancel);
+		KeyBindings.Add (KeyCode.U | KeyCode.CtrlMask, Command.UnixEmulation);
+	}
 
-		///<inheritdoc/>
-		public new ColorScheme ColorScheme {
-			get {
-				return base.ColorScheme;
-			}
-			set {
-				listview.ColorScheme = value;
-				base.ColorScheme = value;
-				SetNeedsDisplay ();
-			}
-		}
+	bool _isShow = false;
+	int _selectedItem = -1;
+	int _lastSelectedItem = -1;
+	bool _hideDropdownListOnClick;
 
-		/// <summary>
-		///If set to true its not allow any changes in the text.
-		/// </summary>
-		public bool ReadOnly {
-			get => search.ReadOnly;
-			set {
-				search.ReadOnly = value;
-				if (search.ReadOnly) {
-					if (search.ColorScheme != null) {
-						search.ColorScheme.Normal = search.ColorScheme.Focus;
-					}
+	/// <summary>
+	/// Gets the index of the currently selected item in the <see cref="Source"/>
+	/// </summary>
+	/// <value>The selected item or -1 none selected.</value>
+	public int SelectedItem {
+		get => _selectedItem;
+		set {
+			if (_selectedItem != value && (value == -1
+							|| _source != null && value > -1 && value < _source.Count)) {
+
+				_selectedItem = _lastSelectedItem = value;
+				if (_selectedItem != -1) {
+					SetValue (_source.ToList () [_selectedItem].ToString (), true);
+				} else {
+					SetValue ("", true);
 				}
+				OnSelectedChanged ();
 			}
 		}
+	}
 
-		/// <summary>
-		/// Gets or sets if the drop-down list can be hide with a button click event.
-		/// </summary>
-		public bool HideDropdownListOnClick {
-			get => hideDropdownListOnClick;
-			set => hideDropdownListOnClick = listview.HideDropdownListOnClick = value;
+	/// <summary>
+	/// Gets the drop down list state, expanded or collapsed.
+	/// </summary>
+	public bool IsShow => _isShow;
+
+	///<inheritdoc/>
+	public new ColorScheme ColorScheme {
+		get => base.ColorScheme;
+		set {
+			_listview.ColorScheme = value;
+			base.ColorScheme = value;
+			SetNeedsDisplay ();
 		}
+	}
 
-		///<inheritdoc/>
-		public override bool MouseEvent (MouseEvent me)
-		{
-			if (me.X == Bounds.Right - 1 && me.Y == Bounds.Top && me.Flags == MouseFlags.Button1Pressed
-				&& autoHide) {
+	/// <summary>
+	///If set to true its not allow any changes in the text.
+	/// </summary>
+	public bool ReadOnly {
+		get => _search.ReadOnly;
+		set {
+			_search.ReadOnly = value;
+			if (_search.ReadOnly) {
+				if (_search.ColorScheme != null) {
+					_search.ColorScheme.Normal = _search.ColorScheme.Focus;
+				}
+			}
+		}
+	}
 
-				if (isShow) {
-					isShow = false;
-					HideList ();
-				} else {
-					SetSearchSet ();
+	/// <summary>
+	/// Gets or sets if the drop-down list can be hide with a button click event.
+	/// </summary>
+	public bool HideDropdownListOnClick {
+		get => _hideDropdownListOnClick;
+		set => _hideDropdownListOnClick = _listview.HideDropdownListOnClick = value;
+	}
 
-					isShow = true;
-					ShowList ();
-					FocusSelectedItem ();
-				}
+	///<inheritdoc/>
+	public override bool MouseEvent (MouseEvent me)
+	{
+		if (me.X == Bounds.Right - 1 && me.Y == Bounds.Top && me.Flags == MouseFlags.Button1Pressed
+		&& _autoHide) {
 
-				return true;
-			} else if (me.Flags == MouseFlags.Button1Pressed) {
-				if (!search.HasFocus) {
-					search.SetFocus ();
-				}
+			if (_isShow) {
+				_isShow = false;
+				HideList ();
+			} else {
+				SetSearchSet ();
 
-				return true;
+				_isShow = true;
+				ShowList ();
+				FocusSelectedItem ();
 			}
 
-			return false;
-		}
+			return true;
+		} else if (me.Flags == MouseFlags.Button1Pressed) {
+			if (!_search.HasFocus) {
+				_search.SetFocus ();
+			}
 
-		private void FocusSelectedItem ()
-		{
-			listview.SelectedItem = SelectedItem > -1 ? SelectedItem : 0;
-			listview.TabStop = true;
-			listview.SetFocus ();
-			OnExpanded ();
+			return true;
 		}
 
-		/// <summary>
-		/// Virtual method which invokes the <see cref="Expanded"/> event.
-		/// </summary>
-		public virtual void OnExpanded ()
-		{
-			Expanded?.Invoke (this, EventArgs.Empty);
-		}
+		return false;
+	}
 
-		/// <summary>
-		/// Virtual method which invokes the <see cref="Collapsed"/> event.
-		/// </summary>
-		public virtual void OnCollapsed ()
-		{
-			Collapsed?.Invoke (this, EventArgs.Empty);
-		}
+	void FocusSelectedItem ()
+	{
+		_listview.SelectedItem = SelectedItem > -1 ? SelectedItem : 0;
+		_listview.TabStop = true;
+		_listview.SetFocus ();
+		OnExpanded ();
+	}
 
-		///<inheritdoc/>
-		public override bool OnEnter (View view)
-		{
-			if (!search.HasFocus && !listview.HasFocus) {
-				search.SetFocus ();
-			}
+	/// <summary>
+	/// Virtual method which invokes the <see cref="Expanded"/> event.
+	/// </summary>
+	public virtual void OnExpanded () => Expanded?.Invoke (this, EventArgs.Empty);
 
-			search.CursorPosition = search.Text.GetRuneCount ();
+	/// <summary>
+	/// Virtual method which invokes the <see cref="Collapsed"/> event.
+	/// </summary>
+	public virtual void OnCollapsed () => Collapsed?.Invoke (this, EventArgs.Empty);
 
-			return base.OnEnter (view);
+	///<inheritdoc/>
+	public override bool OnEnter (View view)
+	{
+		if (!_search.HasFocus && !_listview.HasFocus) {
+			_search.SetFocus ();
 		}
 
-		///<inheritdoc/>
-		public override bool OnLeave (View view)
-		{
-			if (source?.Count > 0 && selectedItem > -1 && selectedItem < source.Count - 1
-				&& text != source.ToList () [selectedItem].ToString ()) {
+		_search.CursorPosition = _search.Text.GetRuneCount ();
 
-				SetValue (source.ToList () [selectedItem].ToString ());
-			}
-			if (autoHide && isShow && view != this && view != search && view != listview) {
-				isShow = false;
-				HideList ();
-			} else if (listview.TabStop) {
-				listview.TabStop = false;
-			}
+		return base.OnEnter (view);
+	}
 
-			return base.OnLeave (view);
+	///<inheritdoc/>
+	public override bool OnLeave (View view)
+	{
+		if (_source?.Count > 0 && _selectedItem > -1 && _selectedItem < _source.Count - 1
+		&& _text != _source.ToList () [_selectedItem].ToString ()) {
+
+			SetValue (_source.ToList () [_selectedItem].ToString ());
+		}
+		if (_autoHide && _isShow && view != this && view != _search && view != _listview) {
+			_isShow = false;
+			HideList ();
+		} else if (_listview.TabStop) {
+			_listview.TabStop = false;
 		}
 
-		/// <summary>
-		/// Invokes the SelectedChanged event if it is defined.
-		/// </summary>
-		/// <returns></returns>
-		public virtual bool OnSelectedChanged ()
-		{
-			// Note: Cannot rely on "listview.SelectedItem != lastSelectedItem" because the list is dynamic. 
-			// So we cannot optimize. Ie: Don't call if not changed
-			SelectedItemChanged?.Invoke (this, new ListViewItemEventArgs (SelectedItem, search.Text));
+		return base.OnLeave (view);
+	}
 
-			return true;
-		}
+	/// <summary>
+	/// Invokes the SelectedChanged event if it is defined.
+	/// </summary>
+	/// <returns></returns>
+	public virtual bool OnSelectedChanged ()
+	{
+		// Note: Cannot rely on "listview.SelectedItem != lastSelectedItem" because the list is dynamic. 
+		// So we cannot optimize. Ie: Don't call if not changed
+		SelectedItemChanged?.Invoke (this, new ListViewItemEventArgs (SelectedItem, _search.Text));
+
+		return true;
+	}
 
-		/// <summary>
-		/// Invokes the OnOpenSelectedItem event if it is defined.
-		/// </summary>
-		/// <returns></returns>
-		public virtual bool OnOpenSelectedItem ()
-		{
-			var value = search.Text;
-			lastSelectedItem = SelectedItem;
-			OpenSelectedItem?.Invoke (this, new ListViewItemEventArgs (SelectedItem, value));
+	/// <summary>
+	/// Invokes the OnOpenSelectedItem event if it is defined.
+	/// </summary>
+	/// <returns></returns>
+	public virtual bool OnOpenSelectedItem ()
+	{
+		string value = _search.Text;
+		_lastSelectedItem = SelectedItem;
+		OpenSelectedItem?.Invoke (this, new ListViewItemEventArgs (SelectedItem, value));
+
+		return true;
+	}
 
-			return true;
+	///<inheritdoc/>
+	public override void OnDrawContent (Rect contentArea)
+	{
+		base.OnDrawContent (contentArea);
+
+		if (!_autoHide) {
+			return;
 		}
 
-		///<inheritdoc/>
-		public override void OnDrawContent (Rect contentArea)
-		{
-			base.OnDrawContent (contentArea);
+		Driver.SetAttribute (ColorScheme.Focus);
+		Move (Bounds.Right - 1, 0);
+		Driver.AddRune (Glyphs.DownArrow);
+	}
 
-			if (!autoHide) {
-				return;
+	bool UnixEmulation ()
+	{
+		// Unix emulation
+		Reset ();
+		return true;
+	}
+
+	bool CancelSelected ()
+	{
+		_search.SetFocus ();
+		if (ReadOnly || HideDropdownListOnClick) {
+			SelectedItem = _lastSelectedItem;
+			if (SelectedItem > -1 && _listview.Source?.Count > 0) {
+				_search.Text = _text = _listview.Source.ToList () [SelectedItem].ToString ();
 			}
+		} else if (!ReadOnly) {
+			_search.Text = _text = "";
+			_selectedItem = _lastSelectedItem;
+			OnSelectedChanged ();
+		}
+		return Collapse ();
+	}
 
-			Driver.SetAttribute (ColorScheme.Focus);
-			Move (Bounds.Right - 1, 0);
-			Driver.AddRune (CM.Glyphs.DownArrow);
+	bool? MoveEnd ()
+	{
+		if (!_isShow && _search.HasFocus) {
+			return null;
 		}
+		if (HasItems ()) {
+			_listview.MoveEnd ();
+		}
+		return true;
+	}
 
-		bool UnixEmulation ()
-		{
-			// Unix emulation
-			Reset ();
-			return true;
+	bool? MoveHome ()
+	{
+		if (!_isShow && _search.HasFocus) {
+			return null;
 		}
+		if (HasItems ()) {
+			_listview.MoveHome ();
+		}
+		return true;
+	}
 
-		bool CancelSelected ()
-		{
-			search.SetFocus ();
-			if (ReadOnly || HideDropdownListOnClick) {
-				SelectedItem = lastSelectedItem;
-				if (SelectedItem > -1 && listview.Source?.Count > 0) {
-					search.Text = text = listview.Source.ToList () [SelectedItem].ToString ();
-				}
-			} else if (!ReadOnly) {
-				search.Text = text = "";
-				selectedItem = lastSelectedItem;
-				OnSelectedChanged ();
-			}
-			Collapse ();
-			return true;
+	bool PageUp ()
+	{
+		if (HasItems ()) {
+			_listview.MovePageUp ();
 		}
+		return true;
+	}
 
-		bool? MoveEnd ()
-		{
-			if (!isShow && search.HasFocus) {
-				return null;
-			}
-			if (HasItems ()) {
-				listview.MoveEnd ();
-			}
-			return true;
+	bool PageDown ()
+	{
+		if (HasItems ()) {
+			_listview.MovePageDown ();
 		}
+		return true;
+	}
 
-		bool? MoveHome ()
-		{
-			if (!isShow && search.HasFocus) {
-				return null;
-			}
-			if (HasItems ()) {
-				listview.MoveHome ();
-			}
+	bool? MoveUp ()
+	{
+		if (_search.HasFocus) {
+			// stop odd behavior on KeyUp when search has focus
 			return true;
 		}
 
-		bool PageUp ()
+		if (_listview.HasFocus && _listview.SelectedItem == 0 && _searchset?.Count > 0) // jump back to search
 		{
-			if (HasItems ()) {
-				listview.MovePageUp ();
-			}
+			_search.CursorPosition = _search.Text.GetRuneCount ();
+			_search.SetFocus ();
 			return true;
 		}
+		return null;
+	}
 
-		bool PageDown ()
-		{
-			if (HasItems ()) {
-				listview.MovePageDown ();
+	bool? MoveDown ()
+	{
+		if (_search.HasFocus) {
+			// jump to list
+			if (_searchset?.Count > 0) {
+				_listview.TabStop = true;
+				_listview.SetFocus ();
+				if (_listview.SelectedItem > -1) {
+					SetValue (_searchset [_listview.SelectedItem]);
+				}
+			} else {
+				_listview.TabStop = false;
+				SuperView?.FocusNext ();
 			}
 			return true;
 		}
+		return null;
+	}
 
-		bool? MoveUp ()
-		{
-			if (search.HasFocus) { // stop odd behavior on KeyUp when search has focus
-				return true;
-			}
-
-			if (listview.HasFocus && listview.SelectedItem == 0 && searchset?.Count > 0) // jump back to search
-			{
-				search.CursorPosition = search.Text.GetRuneCount ();
-				search.SetFocus ();
-				return true;
+	/// <summary>
+	/// Toggles the expand/collapse state of the sublist in the combo box
+	/// </summary>
+	/// <returns></returns>
+	bool ExpandCollapse ()
+	{
+		if (_search.HasFocus || _listview.HasFocus) {
+			if (!_isShow) {
+				return Expand ();
+			} else {
+				return Collapse ();
 			}
-			return null;
 		}
+		return false;
+	}
 
-		bool? MoveDown ()
-		{
-			if (search.HasFocus) { // jump to list
-				if (searchset?.Count > 0) {
-					listview.TabStop = true;
-					listview.SetFocus ();
-					if (listview.SelectedItem > -1) {
-						SetValue (searchset [listview.SelectedItem]);
-					}
-				} else {
-					listview.TabStop = false;
-					SuperView?.FocusNext ();
-				}
-				return true;
-			}
-			return null;
+	bool ActivateSelected ()
+	{
+		if (HasItems ()) {
+			Selected ();
+			return true;
 		}
+		return false;
+	}
 
-		/// <summary>
-		/// Toggles the expand/collapse state of the sublist in the combo box
-		/// </summary>
-		/// <returns></returns>
-		bool ExpandCollapse ()
-		{
-			if (search.HasFocus || listview.HasFocus) {
-				if (!isShow) {
-					return Expand ();
-				} else {
-					return Collapse ();
-				}
-			}
-			return false;
-		}
+	bool HasItems () => Source?.Count > 0;
 
-		bool ActivateSelected ()
-		{
-			if (HasItems ()) {
-				Selected ();
-				return true;
-			}
+	/// <summary>
+	/// Collapses the drop down list.  Returns true if the state chagned or false
+	/// if it was already collapsed and no action was taken
+	/// </summary>
+	public virtual bool Collapse ()
+	{
+		if (!_isShow) {
 			return false;
 		}
 
-		bool HasItems ()
-		{
-			return Source?.Count > 0;
-		}
-
-		/// <summary>
-		/// Collapses the drop down list.  Returns true if the state chagned or false
-		/// if it was already collapsed and no action was taken
-		/// </summary>
-		public virtual bool Collapse ()
-		{
-			if (!isShow) {
-				return false;
-			}
+		_isShow = false;
+		HideList ();
+		return true;
+	}
 
-			isShow = false;
-			HideList ();
-			return true;
+	/// <summary>
+	/// Expands the drop down list.  Returns true if the state chagned or false
+	/// if it was already expanded and no action was taken
+	/// </summary>
+	public virtual bool Expand ()
+	{
+		if (_isShow) {
+			return false;
 		}
 
-		/// <summary>
-		/// Expands the drop down list.  Returns true if the state chagned or false
-		/// if it was already expanded and no action was taken
-		/// </summary>
-		public virtual bool Expand ()
-		{
-			if (isShow) {
-				return false;
-			}
-
-			SetSearchSet ();
-			isShow = true;
-			ShowList ();
-			FocusSelectedItem ();
+		SetSearchSet ();
+		_isShow = true;
+		ShowList ();
+		FocusSelectedItem ();
 
-			return true;
-		}
+		return true;
+	}
 
-		/// <summary>
-		/// The currently selected list item
-		/// </summary>
-		public new string Text {
-			get {
-				return text;
-			}
-			set {
-				SetSearchText (value);
-			}
-		}
+	/// <summary>
+	/// The currently selected list item
+	/// </summary>
+	public new string Text {
+		get => _text;
+		set => SetSearchText (value);
+	}
 
-		/// <summary>
-		/// Current search text 
-		/// </summary>
-		public string SearchText {
-			get {
-				return search.Text;
-			}
-			set {
-				SetSearchText (value);
-			}
-		}
+	/// <summary>
+	/// Current search text 
+	/// </summary>
+	public string SearchText {
+		get => _search.Text;
+		set => SetSearchText (value);
+	}
 
-		private void SetValue (object text, bool isFromSelectedItem = false)
-		{
-			search.TextChanged -= Search_Changed;
-			this.text = search.Text = text.ToString ();
-			search.CursorPosition = 0;
-			search.TextChanged += Search_Changed;
-			if (!isFromSelectedItem) {
-				selectedItem = GetSelectedItemFromSource (this.text);
-				OnSelectedChanged ();
-			}
+	void SetValue (object text, bool isFromSelectedItem = false)
+	{
+		_search.TextChanged -= Search_Changed;
+		this._text = _search.Text = text.ToString ();
+		_search.CursorPosition = 0;
+		_search.TextChanged += Search_Changed;
+		if (!isFromSelectedItem) {
+			_selectedItem = GetSelectedItemFromSource (this._text);
+			OnSelectedChanged ();
 		}
+	}
 
-		private void Selected ()
-		{
-			isShow = false;
-			listview.TabStop = false;
-
-			if (listview.Source.Count == 0 || (searchset?.Count ?? 0) == 0) {
-				text = "";
-				HideList ();
-				isShow = false;
-				return;
-			}
+	void Selected ()
+	{
+		_isShow = false;
+		_listview.TabStop = false;
 
-			SetValue (listview.SelectedItem > -1 ? searchset [listview.SelectedItem] : text);
-			search.CursorPosition = search.Text.GetColumns ();
-			Search_Changed (this, new TextChangedEventArgs (search.Text));
-			OnOpenSelectedItem ();
-			Reset (keepSearchText: true);
+		if (_listview.Source.Count == 0 || (_searchset?.Count ?? 0) == 0) {
+			_text = "";
 			HideList ();
-			isShow = false;
+			_isShow = false;
+			return;
 		}
 
+		SetValue (_listview.SelectedItem > -1 ? _searchset [_listview.SelectedItem] : _text);
+		_search.CursorPosition = _search.Text.GetColumns ();
+		Search_Changed (this, new TextChangedEventArgs (_search.Text));
+		OnOpenSelectedItem ();
+		Reset (keepSearchText: true);
+		HideList ();
+		_isShow = false;
+	}
+
 		private int GetSelectedItemFromSource (string searchText)
 		{
-			if (source is null) {
+			if (_source is null) {
 				return -1;
 			}
-			for (int i = 0; i < searchset.Count; i++) {
-				if (searchset [i].ToString () == searchText) {
+			for (int i = 0; i < _searchset.Count; i++) {
+				if (_searchset [i].ToString () == searchText) {
 					return i;
 				}
 			}
 			return -1;
 		}
 
-		/// <summary>
-		/// Reset to full original list
-		/// </summary>
-		private void Reset (bool keepSearchText = false)
-		{
-			if (!keepSearchText) {
-				SetSearchText (string.Empty);
-			}
+	/// <summary>
+	/// Reset to full original list
+	/// </summary>
+	void Reset (bool keepSearchText = false)
+	{
+		if (!keepSearchText) {
+			SetSearchText (string.Empty);
+		}
 
-			ResetSearchSet ();
+		ResetSearchSet ();
 
-			listview.SetSource (searchset);
-			listview.Height = CalculatetHeight ();
+		_listview.SetSource (_searchset);
+		_listview.Height = CalculatetHeight ();
 
-			if (Subviews.Count > 0) {
-				search.SetFocus ();
-			}
-		}
-		private void SetSearchText (string value)
-		{
-			search.Text = text = value;
+		if (Subviews.Count > 0 && HasFocus) {
+			_search.SetFocus ();
 		}
+	}
 
-		private void ResetSearchSet (bool noCopy = false)
-		{
-			searchset.Clear ();
+	void SetSearchText (string value) => _search.Text = _text = value;
 
-			if (autoHide || noCopy)
-				return;
-			SetSearchSet ();
+	void ResetSearchSet (bool noCopy = false)
+	{
+		_searchset.Clear ();
+
+		if (_autoHide || noCopy) {
+			return;
 		}
+		SetSearchSet ();
+	}
 
-		private void SetSearchSet ()
-		{
-			if (Source == null) { return; }
-			// force deep copy
-			foreach (var item in Source.ToList ()) {
-				searchset.Add (item);
-			}
+	void SetSearchSet ()
+	{
+		if (Source == null) { return; }
+		// force deep copy
+		foreach (object item in Source.ToList ()) {
+			_searchset.Add (item);
 		}
+	}
 
 		private void Search_Changed (object sender, TextChangedEventArgs e)
 		{
-			if (source is null) { // Object initialization		
+			if (_source is null) { // Object initialization		
 				return;
 			}
 
-			if (string.IsNullOrEmpty (search.Text) && string.IsNullOrEmpty (e.OldValue)) {
+			if (string.IsNullOrEmpty (_search.Text) && string.IsNullOrEmpty (e.OldValue)) {
 				ResetSearchSet ();
-			} else if (search.Text != e.OldValue) {
-				if (search.Text.Length < e.OldValue.Length) {
-					selectedItem = -1;
+			} else if (_search.Text != e.OldValue) {
+				if (_search.Text.Length < e.OldValue.Length) {
+					_selectedItem = -1;
 				}
-				isShow = true;
+				_isShow = true;
 				ResetSearchSet (noCopy: true);
 
-				foreach (var item in source.ToList ()) { // Iterate to preserver object type and force deep copy
-					if (item.ToString ().StartsWith (search.Text, StringComparison.CurrentCultureIgnoreCase)) {
-						searchset.Add (item);
-					}
+			foreach (object item in _source.ToList ()) {
+				// Iterate to preserver object type and force deep copy
+				if (item.ToString ().StartsWith (_search.Text, StringComparison.CurrentCultureIgnoreCase)) {
+					_searchset.Add (item);
 				}
 			}
+		}
 
-			if (HasFocus) {
-				ShowList ();
-			} else if (autoHide) {
-				isShow = false;
-				HideList ();
-			}
+		if (HasFocus) {
+			ShowList ();
+		} else if (_autoHide) {
+			_isShow = false;
+			HideList ();
 		}
+	}
 
-		/// <summary>
-		/// Show the search list
-		/// </summary>
-		/// 
-		/// Consider making public
-		private void ShowList ()
-		{
-			listview.SetSource (searchset);
-			listview.Clear (); // Ensure list shrinks in Dialog as you type
-			listview.Height = CalculatetHeight ();
-			SuperView?.BringSubviewToFront (this);
-		}
-
-		/// <summary>
-		/// Hide the search list
-		/// </summary>
-		/// 
-		/// Consider making public
-		private void HideList ()
-		{
-			if (lastSelectedItem != selectedItem) {
-				OnOpenSelectedItem ();
-			}
-			var rect = listview.BoundsToScreen (listview.Bounds);
-			Reset (keepSearchText: true);
-			listview.Clear (rect);
-			listview.TabStop = false;
-			SuperView?.SendSubviewToBack (this);
-			SuperView?.SetNeedsDisplay (rect);
-			OnCollapsed ();
-		}
-
-		/// <summary>
-		/// Internal height of dynamic search list
-		/// </summary>
-		/// <returns></returns>
-		private int CalculatetHeight ()
-		{
-			if (Bounds.Height == 0)
-				return 0;
+	/// <summary>
+	/// Show the search list
+	/// </summary>
+	/// 
+	/// Consider making public
+	void ShowList ()
+	{
+		_listview.SetSource (_searchset);
+		_listview.Clear (); // Ensure list shrinks in Dialog as you type
+		_listview.Height = CalculatetHeight ();
+		SuperView?.BringSubviewToFront (this);
+	}
+
+	/// <summary>
+	/// Hide the search list
+	/// </summary>
+	/// 
+	/// Consider making public
+	void HideList ()
+	{
+		if (_lastSelectedItem != _selectedItem) {
+			OnOpenSelectedItem ();
+		}
+		var rect = _listview.BoundsToScreen (_listview.IsInitialized ? _listview.Bounds : Rect.Empty);
+		Reset (keepSearchText: true);
+		_listview.Clear (rect);
+		_listview.TabStop = false;
+		SuperView?.SendSubviewToBack (this);
+		SuperView?.SetNeedsDisplay (rect);
+		OnCollapsed ();
+	}
 
-			return Math.Min (Math.Max (Bounds.Height - 1, minimumHeight - 1), searchset?.Count > 0 ? searchset.Count : isShow ? Math.Max (Bounds.Height - 1, minimumHeight - 1) : 0);
+	/// <summary>
+	/// Internal height of dynamic search list
+	/// </summary>
+	/// <returns></returns>
+	int CalculatetHeight ()
+	{
+		if (!IsInitialized || Bounds.Height == 0) {
+			return 0;
 		}
+
+		return Math.Min (Math.Max (Bounds.Height - 1, _minimumHeight - 1), _searchset?.Count > 0 ? _searchset.Count : _isShow ? Math.Max (Bounds.Height - 1, _minimumHeight - 1) : 0);
 	}
-}
+}

+ 5 - 2
Terminal.Gui/Views/FileDialog.cs

@@ -198,9 +198,12 @@ namespace Terminal.Gui {
 				Width = Dim.Fill (0),
 				Height = Dim.Fill (1),
 			};
-			this.splitContainer.SetSplitterPos (0, 30);
+			
+			Initialized += (s, e) => {
+				this.splitContainer.SetSplitterPos (0, 30);
+				this.splitContainer.Tiles.ElementAt (0).ContentView.Visible = false;
+			};
 			//			this.splitContainer.Border.BorderStyle = BorderStyle.None;
-			this.splitContainer.Tiles.ElementAt (0).ContentView.Visible = false;
 
 			this.tableView = new TableView {
 				Width = Dim.Fill (),

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

@@ -171,7 +171,9 @@ namespace Terminal.Gui {
 				// Should be able to just use 0 but switching between top/bottom tabs repeatedly breaks in ValidatePosDim if just using the absolute value 0
 				tabsBar.Y = Pos.Percent (0);
 			}
-			LayoutSubviews ();
+			if (IsInitialized) {
+				LayoutSubviews ();
+			}
 			SetNeedsDisplay ();
 		}
 
@@ -279,7 +281,7 @@ namespace Terminal.Gui {
 		/// </summary>
 		public void EnsureSelectedTabIsVisible ()
 		{
-			if (SelectedTab == null) {
+			if (!IsInitialized || SelectedTab == null) {
 				return;
 			}
 

+ 3 - 0
Terminal.Gui/Views/TextField.cs

@@ -391,6 +391,9 @@ namespace Terminal.Gui {
 		/// </summary>
 		public override void PositionCursor ()
 		{
+			if (!IsInitialized) {
+				return;
+			}
 			ProcessAutocomplete ();
 
 			var col = 0;

+ 1 - 0
UICatalog/Scenarios/ASCIICustomButton.cs

@@ -77,6 +77,7 @@ namespace UICatalog.Scenarios {
 				};
 
 				AutoSize = false;
+				LayoutStyle = LayoutStyle.Absolute;
 
 				var fillText = new System.Text.StringBuilder ();
 				for (int i = 0; i < Bounds.Height; i++) {

+ 354 - 385
UICatalog/Scenarios/AllViewsTester.cs

@@ -1,438 +1,407 @@
 using System;
-using System.Collections;
 using System.Collections.Generic;
-using System.Diagnostics;
 using System.Linq;
 using System.Reflection;
-using System.Text;
 using Terminal.Gui;
 
-namespace UICatalog.Scenarios {
-	[ScenarioMetadata (Name: "All Views Tester", Description: "Provides a test UI for all classes derived from View.")]
-	[ScenarioCategory ("Layout")]
-	[ScenarioCategory ("Tests")]
-	[ScenarioCategory ("Top Level Windows")]
-	public class AllViewsTester : Scenario {
-		FrameView _leftPane;
-		ListView _classListView;
-		FrameView _hostPane;
-
-		Dictionary<string, Type> _viewClasses;
-		View _curView = null;
-
-		// Settings
-		FrameView _settingsPane;
-		CheckBox _computedCheckBox;
-		FrameView _locationFrame;
-		RadioGroup _xRadioGroup;
-		TextField _xText;
-		int _xVal = 0;
-		RadioGroup _yRadioGroup;
-		TextField _yText;
-		int _yVal = 0;
-
-		FrameView _sizeFrame;
-		RadioGroup _wRadioGroup;
-		TextField _wText;
-		int _wVal = 0;
-		RadioGroup _hRadioGroup;
-		TextField _hText;
-		int _hVal = 0;
-
-		public override void Init ()
-		{
-			// Don't create a sub-win (Scenario.Win); just use Application.Top
-			Application.Init ();
-			ConfigurationManager.Themes.Theme = Theme;
-			ConfigurationManager.Apply ();
-			Application.Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme];
-		}
+namespace UICatalog.Scenarios;
+
+[ScenarioMetadata ("All Views Tester", "Provides a test UI for all classes derived from View.")]
+[ScenarioCategory ("Layout")]
+[ScenarioCategory ("Tests")]
+[ScenarioCategory ("Top Level Windows")]
+public class AllViewsTester : Scenario {
+	FrameView _leftPane;
+	ListView _classListView;
+	FrameView _hostPane;
+
+	Dictionary<string, Type> _viewClasses;
+	View _curView = null;
+
+	// Settings
+	FrameView _settingsPane;
+	CheckBox _computedCheckBox;
+	FrameView _locationFrame;
+	RadioGroup _xRadioGroup;
+	TextField _xText;
+	int _xVal = 0;
+	RadioGroup _yRadioGroup;
+	TextField _yText;
+	int _yVal = 0;
+
+	FrameView _sizeFrame;
+	RadioGroup _wRadioGroup;
+	TextField _wText;
+	int _wVal = 0;
+	RadioGroup _hRadioGroup;
+	TextField _hText;
+	int _hVal = 0;
+
+	public override void Init ()
+	{
+		// Don't create a sub-win (Scenario.Win); just use Application.Top
+		Application.Init ();
+		ConfigurationManager.Themes.Theme = Theme;
+		ConfigurationManager.Apply ();
+		Application.Top.ColorScheme = Colors.ColorSchemes [TopLevelColorScheme];
+	}
 
-		public override void Setup ()
-		{
-			var statusBar = new StatusBar (new StatusItem [] {
-				new StatusItem(Application.QuitKey, $"{Application.QuitKey} to Quit", () => Quit()),
-				new StatusItem(KeyCode.F2, "~F2~ Toggle Frame Ruler", () => {
-					ConsoleDriver.Diagnostics ^= ConsoleDriver.DiagnosticFlags.FrameRuler;
-					Application.Top.SetNeedsDisplay ();
-				}),
-				new StatusItem(KeyCode.F3, "~F3~ Toggle Frame Padding", () => {
-					ConsoleDriver.Diagnostics ^= ConsoleDriver.DiagnosticFlags.FramePadding;
-					Application.Top.SetNeedsDisplay ();
-				}),
-			});
-			Application.Top.Add (statusBar);
-
-			_viewClasses = GetAllViewClassesCollection ()
+	public override void Setup ()
+	{
+		var statusBar = new StatusBar (new StatusItem [] {
+			new (Application.QuitKey, $"{Application.QuitKey} to Quit", () => Quit ()),
+			new (KeyCode.F2, "~F2~ Toggle Frame Ruler", () => {
+				ConsoleDriver.Diagnostics ^= ConsoleDriver.DiagnosticFlags.FrameRuler;
+				Application.Top.SetNeedsDisplay ();
+			}),
+			new (KeyCode.F3, "~F3~ Toggle Frame Padding", () => {
+				ConsoleDriver.Diagnostics ^= ConsoleDriver.DiagnosticFlags.FramePadding;
+				Application.Top.SetNeedsDisplay ();
+			})
+		});
+		Application.Top.Add (statusBar);
+
+		_viewClasses = GetAllViewClassesCollection ()
 				.OrderBy (t => t.Name)
 				.Select (t => new KeyValuePair<string, Type> (t.Name, t))
 				.ToDictionary (t => t.Key, t => t.Value);
 
-			_leftPane = new FrameView ("Classes") {
-				X = 0,
-				Y = 0,
-				Width = 15,
-				Height = Dim.Fill (1), // for status bar
-				CanFocus = false,
-				ColorScheme = Colors.TopLevel,
-			};
-
-			_classListView = new ListView (_viewClasses.Keys.ToList ()) {
-				X = 0,
-				Y = 0,
-				Width = Dim.Fill (0),
-				Height = Dim.Fill (0),
-				AllowsMarking = false,
-				ColorScheme = Colors.TopLevel,
-				SelectedItem = 0
-			};
-			_classListView.OpenSelectedItem += (s, a) => {
-				_settingsPane.SetFocus ();
-			};
-			_classListView.SelectedItemChanged += (s,args) => {
-				// Remove existing class, if any
-				if (_curView != null) {
-					_curView.LayoutComplete -= LayoutCompleteHandler;
-					_hostPane.Remove (_curView);
-					_curView.Dispose ();
-					_curView = null;
-					_hostPane.Clear ();
-				}
-				_curView = CreateClass (_viewClasses.Values.ToArray () [_classListView.SelectedItem]);
-			};
-			_leftPane.Add (_classListView);
-
-			_settingsPane = new FrameView ("Settings") {
-				X = Pos.Right (_leftPane),
-				Y = 0, // for menu
-				Width = Dim.Fill (),
-				Height = 10,
-				CanFocus = false,
-				ColorScheme = Colors.TopLevel,
-			};
-			_computedCheckBox = new CheckBox ("Computed Layout", true) { X = 0, Y = 0 };
-			_computedCheckBox.Toggled += (s,e) => {
-				if (_curView != null) {
-					_curView.LayoutStyle = e.OldValue == true ? LayoutStyle.Absolute : LayoutStyle.Computed;
-					_hostPane.LayoutSubviews ();
-				}
-			};
-			_settingsPane.Add (_computedCheckBox);
-
-			var radioItems = new string [] { "Percent(x)", "AnchorEnd(x)", "Center", "At(x)" };
-			_locationFrame = new FrameView ("Location (Pos)") {
-				X = Pos.Left (_computedCheckBox),
-				Y = Pos.Bottom (_computedCheckBox),
-				Height = 3 + radioItems.Length,
-				Width = 36,
-			};
-			_settingsPane.Add (_locationFrame);
-
-			var label = new Label ("x:") { X = 0, Y = 0 };
-			_locationFrame.Add (label);
-			_xRadioGroup = new RadioGroup (radioItems) {
-				X = 0,
-				Y = Pos.Bottom (label),
-			};
-			_xRadioGroup.SelectedItemChanged += (s, selected) => DimPosChanged (_curView);
-			_xText = new TextField ($"{_xVal}") { X = Pos.Right (label) + 1, Y = 0, Width = 4 };
-			_xText.TextChanged += (s, args) => {
-				try {
-					_xVal = int.Parse (_xText.Text);
-					DimPosChanged (_curView);
-				} catch {
-
-				}
-			};
-			_locationFrame.Add (_xText);
-
-			_locationFrame.Add (_xRadioGroup);
-
-			radioItems = new string [] { "Percent(y)", "AnchorEnd(y)", "Center", "At(y)" };
-			label = new Label ("y:") { X = Pos.Right (_xRadioGroup) + 1, Y = 0 };
-			_locationFrame.Add (label);
-			_yText = new TextField ($"{_yVal}") { X = Pos.Right (label) + 1, Y = 0, Width = 4 };
-			_yText.TextChanged += (s,args) => {
-				try {
-					_yVal = int.Parse (_yText.Text);
-					DimPosChanged (_curView);
-				} catch {
-
-				}
-			};
-			_locationFrame.Add (_yText);
-			_yRadioGroup = new RadioGroup (radioItems) {
-				X = Pos.X (label),
-				Y = Pos.Bottom (label),
-			};
-			_yRadioGroup.SelectedItemChanged += (s, selected) => DimPosChanged (_curView);
-			_locationFrame.Add (_yRadioGroup);
-
-			_sizeFrame = new FrameView ("Size (Dim)") {
-				X = Pos.Right (_locationFrame),
-				Y = Pos.Y (_locationFrame),
-				Height = 3 + radioItems.Length,
-				Width = 40,
-			};
-
-			radioItems = new string [] { "Percent(width)", "Fill(width)", "Sized(width)" };
-			label = new Label ("width:") { X = 0, Y = 0 };
-			_sizeFrame.Add (label);
-			_wRadioGroup = new RadioGroup (radioItems) {
-				X = 0,
-				Y = Pos.Bottom (label),
-			};
-			_wRadioGroup.SelectedItemChanged += (s, selected) => DimPosChanged (_curView);
-			_wText = new TextField ($"{_wVal}") { X = Pos.Right (label) + 1, Y = 0, Width = 4 };
-			_wText.TextChanged += (s,args) => {
-				try {
-					switch (_wRadioGroup.SelectedItem) {
-					case 0:
-						_wVal = Math.Min (int.Parse (_wText.Text), 100);
-						break;
-					case 1:
-					case 2:
-						_wVal = int.Parse (_wText.Text);
-						break;
-					}
-					DimPosChanged (_curView);
-				} catch {
-
-				}
-			};
-			_sizeFrame.Add (_wText);
-			_sizeFrame.Add (_wRadioGroup);
-
-			radioItems = new string [] { "Percent(height)", "Fill(height)", "Sized(height)" };
-			label = new Label ("height:") { X = Pos.Right (_wRadioGroup) + 1, Y = 0 };
-			_sizeFrame.Add (label);
-			_hText = new TextField ($"{_hVal}") { X = Pos.Right (label) + 1, Y = 0, Width = 4 };
-			_hText.TextChanged += (s, args) => {
-				try {
-					switch (_hRadioGroup.SelectedItem) {
-					case 0:
-						_hVal = Math.Min (int.Parse (_hText.Text), 100);
-						break;
-					case 1:
-					case 2:
-						_hVal = int.Parse (_hText.Text);
-						break;
-					}
-					DimPosChanged (_curView);
-				} catch {
-
-				}
-			};
-			_sizeFrame.Add (_hText);
-
-			_hRadioGroup = new RadioGroup (radioItems) {
-				X = Pos.X (label),
-				Y = Pos.Bottom (label),
-			};
-			_hRadioGroup.SelectedItemChanged += (s, selected) => DimPosChanged (_curView);
-			_sizeFrame.Add (_hRadioGroup);
-
-			_settingsPane.Add (_sizeFrame);
-
-			_hostPane = new FrameView ("") {
-				X = Pos.Right (_leftPane),
-				Y = Pos.Bottom (_settingsPane),
-				Width = Dim.Fill (),
-				Height = Dim.Fill (1), // + 1 for status bar
-				ColorScheme = Colors.Dialog,
-			};
-
-			Application.Top.Add (_leftPane, _settingsPane, _hostPane);
-
-			_curView = CreateClass (_viewClasses.First ().Value);
-		}
-
-		void DimPosChanged (View view)
-		{
-			if (view == null) {
-				return;
+		_leftPane = new FrameView ("Classes") {
+			X = 0,
+			Y = 0,
+			Width = 15,
+			Height = Dim.Fill (1), // for status bar
+			CanFocus = false,
+			ColorScheme = Colors.TopLevel
+		};
+
+		_classListView = new ListView (_viewClasses.Keys.ToList ()) {
+			X = 0,
+			Y = 0,
+			Width = Dim.Fill (0),
+			Height = Dim.Fill (0),
+			AllowsMarking = false,
+			ColorScheme = Colors.TopLevel,
+			SelectedItem = 0
+		};
+		_classListView.OpenSelectedItem += (s, a) => {
+			_settingsPane.SetFocus ();
+		};
+		_classListView.SelectedItemChanged += (s, args) => {
+			// Remove existing class, if any
+			if (_curView != null) {
+				_curView.LayoutComplete -= LayoutCompleteHandler;
+				_hostPane.Remove (_curView);
+				_curView.Dispose ();
+				_curView = null;
+				_hostPane.Clear ();
 			}
-
-			var layout = view.LayoutStyle;
-
+			_curView = CreateClass (_viewClasses.Values.ToArray () [_classListView.SelectedItem]);
+		};
+		_leftPane.Add (_classListView);
+
+		_settingsPane = new FrameView ("Settings") {
+			X = Pos.Right (_leftPane),
+			Y = 0, // for menu
+			Width = Dim.Fill (),
+			Height = 10,
+			CanFocus = false,
+			ColorScheme = Colors.TopLevel
+		};
+		_computedCheckBox = new CheckBox ("Computed Layout", true) { X = 0, Y = 0 };
+		_computedCheckBox.Toggled += (s, e) => {
+			if (_curView != null) {
+				_curView.LayoutStyle = e.OldValue == true ? LayoutStyle.Absolute : LayoutStyle.Computed;
+				_hostPane.LayoutSubviews ();
+			}
+		};
+		_settingsPane.Add (_computedCheckBox);
+
+		string [] radioItems = new string [] { "Percent(x)", "AnchorEnd(x)", "Center", "At(x)" };
+		_locationFrame = new FrameView ("Location (Pos)") {
+			X = Pos.Left (_computedCheckBox),
+			Y = Pos.Bottom (_computedCheckBox),
+			Height = 3 + radioItems.Length,
+			Width = 36
+		};
+		_settingsPane.Add (_locationFrame);
+
+		var label = new Label ("x:") { X = 0, Y = 0 };
+		_locationFrame.Add (label);
+		_xRadioGroup = new RadioGroup (radioItems) {
+			X = 0,
+			Y = Pos.Bottom (label)
+		};
+		_xRadioGroup.SelectedItemChanged += (s, selected) => DimPosChanged (_curView);
+		_xText = new TextField ($"{_xVal}") { X = Pos.Right (label) + 1, Y = 0, Width = 4 };
+		_xText.TextChanged += (s, args) => {
+			try {
+				_xVal = int.Parse (_xText.Text);
+				DimPosChanged (_curView);
+			} catch { }
+		};
+		_locationFrame.Add (_xText);
+
+		_locationFrame.Add (_xRadioGroup);
+
+		radioItems = new string [] { "Percent(y)", "AnchorEnd(y)", "Center", "At(y)" };
+		label = new Label ("y:") { X = Pos.Right (_xRadioGroup) + 1, Y = 0 };
+		_locationFrame.Add (label);
+		_yText = new TextField ($"{_yVal}") { X = Pos.Right (label) + 1, Y = 0, Width = 4 };
+		_yText.TextChanged += (s, args) => {
+			try {
+				_yVal = int.Parse (_yText.Text);
+				DimPosChanged (_curView);
+			} catch { }
+		};
+		_locationFrame.Add (_yText);
+		_yRadioGroup = new RadioGroup (radioItems) {
+			X = Pos.X (label),
+			Y = Pos.Bottom (label)
+		};
+		_yRadioGroup.SelectedItemChanged += (s, selected) => DimPosChanged (_curView);
+		_locationFrame.Add (_yRadioGroup);
+
+		_sizeFrame = new FrameView ("Size (Dim)") {
+			X = Pos.Right (_locationFrame),
+			Y = Pos.Y (_locationFrame),
+			Height = 3 + radioItems.Length,
+			Width = 40
+		};
+
+		radioItems = new string [] { "Percent(width)", "Fill(width)", "Sized(width)" };
+		label = new Label ("width:") { X = 0, Y = 0 };
+		_sizeFrame.Add (label);
+		_wRadioGroup = new RadioGroup (radioItems) {
+			X = 0,
+			Y = Pos.Bottom (label)
+		};
+		_wRadioGroup.SelectedItemChanged += (s, selected) => DimPosChanged (_curView);
+		_wText = new TextField ($"{_wVal}") { X = Pos.Right (label) + 1, Y = 0, Width = 4 };
+		_wText.TextChanged += (s, args) => {
 			try {
-				view.LayoutStyle = LayoutStyle.Absolute;
-
-				switch (_xRadioGroup.SelectedItem) {
-				case 0:
-					view.X = Pos.Percent (_xVal);
-					break;
-				case 1:
-					view.X = Pos.AnchorEnd (_xVal);
-					break;
-				case 2:
-					view.X = Pos.Center ();
-					break;
-				case 3:
-					view.X = Pos.At (_xVal);
-					break;
-				}
-
-				switch (_yRadioGroup.SelectedItem) {
-				case 0:
-					view.Y = Pos.Percent (_yVal);
-					break;
-				case 1:
-					view.Y = Pos.AnchorEnd (_yVal);
-					break;
-				case 2:
-					view.Y = Pos.Center ();
-					break;
-				case 3:
-					view.Y = Pos.At (_yVal);
-					break;
-				}
-
 				switch (_wRadioGroup.SelectedItem) {
 				case 0:
-					view.Width = Dim.Percent (_wVal);
+					_wVal = Math.Min (int.Parse (_wText.Text), 100);
 					break;
 				case 1:
-					view.Width = Dim.Fill (_wVal);
-					break;
 				case 2:
-					view.Width = Dim.Sized (_wVal);
+					_wVal = int.Parse (_wText.Text);
 					break;
 				}
-
+				DimPosChanged (_curView);
+			} catch { }
+		};
+		_sizeFrame.Add (_wText);
+		_sizeFrame.Add (_wRadioGroup);
+
+		radioItems = new string [] { "Percent(height)", "Fill(height)", "Sized(height)" };
+		label = new Label ("height:") { X = Pos.Right (_wRadioGroup) + 1, Y = 0 };
+		_sizeFrame.Add (label);
+		_hText = new TextField ($"{_hVal}") { X = Pos.Right (label) + 1, Y = 0, Width = 4 };
+		_hText.TextChanged += (s, args) => {
+			try {
 				switch (_hRadioGroup.SelectedItem) {
 				case 0:
-					view.Height = Dim.Percent (_hVal);
+					_hVal = Math.Min (int.Parse (_hText.Text), 100);
 					break;
 				case 1:
-					view.Height = Dim.Fill (_hVal);
-					break;
 				case 2:
-					view.Height = Dim.Sized (_hVal);
+					_hVal = int.Parse (_hText.Text);
 					break;
 				}
-			} catch (Exception e) {
-				MessageBox.ErrorQuery ("Exception", e.Message, "Ok");
-			} finally {
-				view.LayoutStyle = layout;
-			}
-			UpdateTitle (view);
-		}
+				DimPosChanged (_curView);
+			} catch { }
+		};
+		_sizeFrame.Add (_hText);
+
+		_hRadioGroup = new RadioGroup (radioItems) {
+			X = Pos.X (label),
+			Y = Pos.Bottom (label)
+		};
+		_hRadioGroup.SelectedItemChanged += (s, selected) => DimPosChanged (_curView);
+		_sizeFrame.Add (_hRadioGroup);
+
+		_settingsPane.Add (_sizeFrame);
+
+		_hostPane = new FrameView ("") {
+			X = Pos.Right (_leftPane),
+			Y = Pos.Bottom (_settingsPane),
+			Width = Dim.Fill (),
+			Height = Dim.Fill (1), // + 1 for status bar
+			ColorScheme = Colors.Dialog
+		};
+
+		Application.Top.Add (_leftPane, _settingsPane, _hostPane);
+
+		_curView = CreateClass (_viewClasses.First ().Value);
+	}
 
-		List<string> posNames = new List<String> { "Factor", "AnchorEnd", "Center", "Absolute" };
-		List<string> dimNames = new List<String> { "Factor", "Fill", "Absolute" };
-
-		void UpdateSettings (View view)
-		{
-			var x = view.X.ToString ();
-			var y = view.Y.ToString ();
-			_xRadioGroup.SelectedItem = posNames.IndexOf (posNames.Where (s => x.Contains (s)).First ());
-			_yRadioGroup.SelectedItem = posNames.IndexOf (posNames.Where (s => y.Contains (s)).First ());
-			_xText.Text = $"{view.Frame.X}";
-			_yText.Text = $"{view.Frame.Y}";
-
-			var w = view.Width.ToString ();
-			var h = view.Height.ToString ();
-			_wRadioGroup.SelectedItem = dimNames.IndexOf (dimNames.Where (s => w.Contains (s)).First ());
-			_hRadioGroup.SelectedItem = dimNames.IndexOf (dimNames.Where (s => h.Contains (s)).First ());
-			_wText.Text = $"{view.Frame.Width}";
-			_hText.Text = $"{view.Frame.Height}";
+	void DimPosChanged (View view)
+	{
+		if (view == null) {
+			return;
 		}
 
-		void UpdateTitle (View view)
-		{
-			_hostPane.Title = $"{view.GetType ().Name} - {view.X}, {view.Y}, {view.Width}, {view.Height}";
-		}
+		var layout = view.LayoutStyle;
 
-		List<Type> GetAllViewClassesCollection ()
-		{
-			List<Type> types = new List<Type> ();
-			foreach (Type type in typeof (View).Assembly.GetTypes ()
-			 .Where (myType => myType.IsClass && !myType.IsAbstract && myType.IsPublic && myType.IsSubclassOf (typeof (View)))) {
-				types.Add (type);
-			}
-			types.Add (typeof (View));
-			return types;
+		try {
+			view.LayoutStyle = LayoutStyle.Absolute;
+
+			view.X = _xRadioGroup.SelectedItem switch {
+				0 => Pos.Percent (_xVal),
+				1 => Pos.AnchorEnd (_xVal),
+				2 => Pos.Center (),
+				3 => Pos.At (_xVal),
+				_ => view.X
+			};
+
+			view.Y = _yRadioGroup.SelectedItem switch {
+				0 => Pos.Percent (_yVal),
+				1 => Pos.AnchorEnd (_yVal),
+				2 => Pos.Center (),
+				3 => Pos.At (_yVal),
+				_ => view.Y
+			};
+
+			view.Width = _wRadioGroup.SelectedItem switch {
+				0 => Dim.Percent (_wVal),
+				1 => Dim.Fill (_wVal),
+				2 => Dim.Sized (_wVal),
+				_ => view.Width
+			};
+
+			view.Height = _hRadioGroup.SelectedItem switch {
+				0 => Dim.Percent (_hVal),
+				1 => Dim.Fill (_hVal),
+				2 => Dim.Sized (_hVal),
+				_ => view.Height
+			};
+		} catch (Exception e) {
+			MessageBox.ErrorQuery ("Exception", e.Message, "Ok");
+		} finally {
+			view.LayoutStyle = layout;
 		}
-		
+		UpdateTitle (view);
+	}
 
-		View CreateClass (Type type)
-		{
-			// If we are to create a generic Type
-			if (type.IsGenericType) {
+	// TODO: This is missing some
+	List<string> _posNames = new() { "Factor", "AnchorEnd", "Center", "Absolute" };
+	List<string> _dimNames = new() { "Factor", "Fill", "Absolute" };
+
+	void UpdateSettings (View view)
+	{
+		string x = view.X.ToString ();
+		string y = view.Y.ToString ();
+		_xRadioGroup.SelectedItem = _posNames.IndexOf (_posNames.Where (s => x.Contains (s)).First ());
+		_yRadioGroup.SelectedItem = _posNames.IndexOf (_posNames.Where (s => y.Contains (s)).First ());
+		_xText.Text = $"{view.Frame.X}";
+		_yText.Text = $"{view.Frame.Y}";
+
+		string w = view.Width.ToString ();
+		string h = view.Height.ToString ();
+		_wRadioGroup.SelectedItem = _dimNames.IndexOf (_dimNames.Where (s => w.Contains (s)).First ());
+		_hRadioGroup.SelectedItem = _dimNames.IndexOf (_dimNames.Where (s => h.Contains (s)).First ());
+		_wText.Text = $"{view.Frame.Width}";
+		_hText.Text = $"{view.Frame.Height}";
+	}
 
-				// For each of the <T> arguments
-				List<Type> typeArguments = new List<Type> ();
+	void UpdateTitle (View view) => _hostPane.Title = $"{view.GetType ().Name} - {view.X}, {view.Y}, {view.Width}, {view.Height}";
 
-				// use <object>
-				foreach (var arg in type.GetGenericArguments ()) {
-					typeArguments.Add (typeof (object));
-				}
+	List<Type> GetAllViewClassesCollection ()
+	{
+		var types = new List<Type> ();
+		foreach (var type in typeof (View).Assembly.GetTypes ()
+						.Where (myType => myType.IsClass && !myType.IsAbstract && myType.IsPublic && myType.IsSubclassOf (typeof (View)))) {
+			types.Add (type);
+		}
+		types.Add (typeof (View));
+		return types;
+	}
 
-				// And change what type we are instantiating from MyClass<T> to MyClass<object>
-				type = type.MakeGenericType (typeArguments.ToArray ());
-			}
-			// Instantiate view
-			var view = (View)Activator.CreateInstance (type);
+	// TODO: Add Command.Default handler (pop a message box?)
+	View CreateClass (Type type)
+	{
+		// If we are to create a generic Type
+		if (type.IsGenericType) {
 
-			//_curView.X = Pos.Center ();
-			//_curView.Y = Pos.Center ();
-			view.Width = Dim.Percent (75);
-			view.Height = Dim.Percent (75);
+			// For each of the <T> arguments
+			var typeArguments = new List<Type> ();
 
-			// Set the colorscheme to make it stand out if is null by default
-			if (view.ColorScheme == null) {
-				view.ColorScheme = Colors.Base;
+			// use <object>
+			foreach (var arg in type.GetGenericArguments ()) {
+				typeArguments.Add (typeof (object));
 			}
 
-			// If the view supports a Text property, set it so we have something to look at
-			if (view.GetType ().GetProperty ("Text") != null) {
-				try {
-					view.GetType ().GetProperty ("Text")?.GetSetMethod ()?.Invoke (view, new [] { "Test Text" });
-				} catch (TargetInvocationException e) {
-					MessageBox.ErrorQuery ("Exception", e.InnerException.Message, "Ok");
-					view = null;
-				}
-			}
+			// And change what type we are instantiating from MyClass<T> to MyClass<object>
+			type = type.MakeGenericType (typeArguments.ToArray ());
+		}
+		// Instantiate view
+		var view = (View)Activator.CreateInstance (type);
 
-			// If the view supports a Title property, set it so we have something to look at
-			if (view != null && view.GetType ().GetProperty ("Title") != null) {
-				if (view.GetType ().GetProperty ("Title").PropertyType == typeof (string)) {
-					view?.GetType ().GetProperty ("Title")?.GetSetMethod ()?.Invoke (view, new [] { "Test Title" });
-				} else {
-					view?.GetType ().GetProperty ("Title")?.GetSetMethod ()?.Invoke (view, new [] { "Test Title" });
-				}
+		// Set the colorscheme to make it stand out if is null by default
+		if (view.ColorScheme == null) {
+			view.ColorScheme = Colors.Base;
+		}
+
+		// If the view supports a Text property, set it so we have something to look at
+		if (view.GetType ().GetProperty ("Text") != null) {
+			try {
+				view.GetType ().GetProperty ("Text")?.GetSetMethod ()?.Invoke (view, new [] { "Test Text" });
+			} catch (TargetInvocationException e) {
+				MessageBox.ErrorQuery ("Exception", e.InnerException.Message, "Ok");
+				view = null;
 			}
+		}
 
-			// If the view supports a Source property, set it so we have something to look at
-			if (view != null && view.GetType ().GetProperty ("Source") != null && view.GetType ().GetProperty ("Source").PropertyType == typeof (Terminal.Gui.IListDataSource)) {
-				var source = new ListWrapper (new List<string> () { "Test Text #1", "Test Text #2", "Test Text #3" });
-				view?.GetType ().GetProperty ("Source")?.GetSetMethod ()?.Invoke (view, new [] { source });
+		// If the view supports a Title property, set it so we have something to look at
+		if (view != null && view.GetType ().GetProperty ("Title") != null) {
+			if (view.GetType ().GetProperty ("Title").PropertyType == typeof (string)) {
+				view?.GetType ().GetProperty ("Title")?.GetSetMethod ()?.Invoke (view, new [] { "Test Title" });
+			} else {
+				view?.GetType ().GetProperty ("Title")?.GetSetMethod ()?.Invoke (view, new [] { "Test Title" });
 			}
+		}
 
-			// Set Settings
-			_computedCheckBox.Checked = view.LayoutStyle == LayoutStyle.Computed;
+		// If the view supports a Source property, set it so we have something to look at
+		if (view != null && view.GetType ().GetProperty ("Source") != null && view.GetType ().GetProperty ("Source").PropertyType == typeof (IListDataSource)) {
+			var source = new ListWrapper (new List<string> () { "Test Text #1", "Test Text #2", "Test Text #3" });
+			view?.GetType ().GetProperty ("Source")?.GetSetMethod ()?.Invoke (view, new [] { source });
+		}
 
-			// Add
-			_hostPane.Add (view);
-			_hostPane.Clear ();
-			_hostPane.SetNeedsDisplay ();
-			UpdateSettings (view);
-			UpdateTitle (view);
+		// Set Settings
+		_computedCheckBox.Checked = view.LayoutStyle == LayoutStyle.Computed;
 
-			view.LayoutComplete += LayoutCompleteHandler;
+		view.Initialized += View_Initialized;
 
-			return view;
-		}
+		// Add
+		_hostPane.Add (view);
+		_hostPane.SetNeedsDisplay ();
 
-		void LayoutCompleteHandler (object sender, LayoutEventArgs args)
-		{
-			UpdateTitle (_curView);
-		}
+		return view;
+	}
+
+	void View_Initialized (object sender, EventArgs e)
+	{
+		var view = sender as View;
 
-		private void Quit ()
-		{
-			Application.RequestStop ();
+		//view.X = Pos.Center ();
+		//view.Y = Pos.Center ();
+		if (view.Width == null || view.Frame.Width == 0) {
+			view.Width = Dim.Fill();
+		}
+		if (view.Height == null || view.Frame.Height == 0) {
+			view.Height = Dim.Fill();
 		}
+		UpdateSettings (view);
+		UpdateTitle (view);
 	}
+
+	void LayoutCompleteHandler (object sender, LayoutEventArgs args)
+	{
+		UpdateSettings (_curView);
+		UpdateTitle (_curView);
+	}
+
+	void Quit () => Application.RequestStop ();
 }

+ 25 - 25
UICatalog/Scenarios/CharacterMap.cs

@@ -114,10 +114,9 @@ public class CharacterMap : Scenario {
 		Application.Top.Add (_categoryList);
 
 		_charMap.SelectedCodePoint = 0;
-		//jumpList.Refresh ();
 		_charMap.SetFocus ();
-
-		_charMap.Width = Dim.Fill () - _categoryList.Width;
+		// TODO: Replace this with Dim.Auto when that's ready
+		_categoryList.Initialized += _categoryList_Initialized;
 
 		var menu = new MenuBar (new MenuBarItem [] {
 			new ("_File", new MenuItem [] {
@@ -128,12 +127,11 @@ public class CharacterMap : Scenario {
 			})
 		});
 		Application.Top.Add (menu);
-
-		//_charMap.Hover += (s, a) => {
-		//	_errorLabel.Text = $"U+{a.Item:x5} {(Rune)a.Item}";
-		//};
+	
 	}
 
+	private void _categoryList_Initialized (object sender, EventArgs e) => _charMap.Width = Dim.Fill () - _categoryList.Width;
+
 	MenuItem CreateMenuShowWidth ()
 	{
 		var item = new MenuItem {
@@ -255,24 +253,26 @@ class CharMap : ScrollView {
 		get => _selected;
 		set {
 			_selected = value;
-			int row = SelectedCodePoint / 16 * _rowHeight;
-			int col = SelectedCodePoint % 16 * COLUMN_WIDTH;
-
-			int height = Bounds.Height - (ShowHorizontalScrollIndicator ? 2 : 1);
-			if (row + ContentOffset.Y < 0) {
-				// Moving up.
-				ContentOffset = new Point (ContentOffset.X, row);
-			} else if (row + ContentOffset.Y >= height) {
-				// Moving down.
-				ContentOffset = new Point (ContentOffset.X, Math.Min (row, row - height + _rowHeight));
-			}
-			int width = Bounds.Width / COLUMN_WIDTH * COLUMN_WIDTH - (ShowVerticalScrollIndicator ? RowLabelWidth + 1 : RowLabelWidth);
-			if (col + ContentOffset.X < 0) {
-				// Moving left.
-				ContentOffset = new Point (col, ContentOffset.Y);
-			} else if (col + ContentOffset.X >= width) {
-				// Moving right.
-				ContentOffset = new Point (Math.Min (col, col - width + COLUMN_WIDTH), ContentOffset.Y);
+			if (IsInitialized) {
+				int row = SelectedCodePoint / 16 * _rowHeight;
+				int col = SelectedCodePoint % 16 * COLUMN_WIDTH;
+
+				int height = Bounds.Height - (ShowHorizontalScrollIndicator ? 2 : 1);
+				if (row + ContentOffset.Y < 0) {
+					// Moving up.
+					ContentOffset = new Point (ContentOffset.X, row);
+				} else if (row + ContentOffset.Y >= height) {
+					// Moving down.
+					ContentOffset = new Point (ContentOffset.X, Math.Min (row, row - height + _rowHeight));
+				}
+				int width = Bounds.Width / COLUMN_WIDTH * COLUMN_WIDTH - (ShowVerticalScrollIndicator ? RowLabelWidth + 1 : RowLabelWidth);
+				if (col + ContentOffset.X < 0) {
+					// Moving left.
+					ContentOffset = new Point (col, ContentOffset.Y);
+				} else if (col + ContentOffset.X >= width) {
+					// Moving right.
+					ContentOffset = new Point (Math.Min (col, col - width + COLUMN_WIDTH), ContentOffset.Y);
+				}
 			}
 			SetNeedsDisplay ();
 			SelectedCodePointChanged?.Invoke (this, new ListViewItemEventArgs (SelectedCodePoint, null));

+ 0 - 1
UICatalog/Scenarios/ClassExplorer.cs

@@ -59,7 +59,6 @@ namespace UICatalog.Scenarios {
 			Win.Title = this.GetName ();
 			Win.Y = 1; // menu
 			Win.Height = Dim.Fill (1); // status bar
-			Application.Top.LayoutSubviews ();
 
 			var menu = new MenuBar (new MenuBarItem [] {
 				new MenuBarItem ("_File", new MenuItem [] {

+ 1 - 0
UICatalog/Scenarios/ColorPicker.cs

@@ -91,6 +91,7 @@ namespace UICatalog.Scenarios {
 			// Set default colors.
 			foregroundColorPicker.SelectedColor = _demoView.SuperView.ColorScheme.Normal.Foreground.ColorName;
 			backgroundColorPicker.SelectedColor = _demoView.SuperView.ColorScheme.Normal.Background.ColorName;
+			Win.Initialized += (s, e) => Win.LayoutSubviews ();
 		}
 
 		/// <summary>

+ 11 - 3
UICatalog/Scenarios/ComputedLayout.cs

@@ -79,7 +79,9 @@ namespace UICatalog.Scenarios {
 				Width = Dim.Fill (margin),
 				Height = 7
 			};
-			subWin.Title = $"{subWin.GetType ().Name} {{X={subWin.X},Y={subWin.Y},Width={subWin.Width},Height={subWin.Height}}}";
+			subWin.Initialized += (s, a) => {
+				subWin.Title = $"{subWin.GetType ().Name} {{X={subWin.X},Y={subWin.Y},Width={subWin.Width},Height={subWin.Height}}}";
+			};
 			Application.Top.Add (subWin);
 
 			int i = 1;
@@ -98,7 +100,10 @@ namespace UICatalog.Scenarios {
 				Width = 30,
 				Height = 7
 			};
-			frameView.Title = $"{frameView.GetType ().Name} {{X={frameView.X},Y={frameView.Y},Width={frameView.Width},Height={frameView.Height}}}";
+			frameView.Initialized += (sender, args) => {
+				var fv = sender as FrameView;
+				fv.Title = $"{frameView.GetType ().Name} {{X={fv.X},Y={fv.Y},Width={fv.Width},Height={fv.Height}}}";
+			};
 			i = 1;
 			labelList = new List<Label> ();
 			labelList.Add (new Label ($"The lines below show different TextAlignments"));
@@ -115,7 +120,10 @@ namespace UICatalog.Scenarios {
 				Width = Dim.Fill (),
 				Height = 7,
 			};
-			frameView.Title = $"{frameView.GetType ().Name} {{X={frameView.X},Y={frameView.Y},Width={frameView.Width},Height={frameView.Height}}}";
+			frameView.Initialized += (sender, args) => {
+				var fv = sender as FrameView;
+				fv.Title = $"{frameView.GetType ().Name} {{X={fv.X},Y={fv.Y},Width={fv.Width},Height={fv.Height}}}";
+			};
 			Application.Top.Add (frameView);
 
 			// Demonstrate Dim & Pos using percentages - a TextField that is 30% height and 80% wide

+ 420 - 419
UICatalog/Scenarios/CsvEditor.cs

@@ -1,553 +1,554 @@
-using System;
+using CsvHelper;
+using System;
+using System.Collections.Generic;
 using System.Data;
-using System.Linq;
 using System.Globalization;
 using System.IO;
+using System.Linq;
 using System.Text.RegularExpressions;
-using System.Text;
 using Terminal.Gui;
-using CsvHelper;
-using System.Collections.Generic;
 
-namespace UICatalog.Scenarios {
-
-	[ScenarioMetadata (Name: "Csv Editor", Description: "Open and edit simple CSV files using the TableView class.")]
-	[ScenarioCategory ("TableView"), ScenarioCategory ("TextView"), ScenarioCategory ("Controls"), ScenarioCategory ("Dialogs"), 
-	ScenarioCategory ("Text and Formatting"), ScenarioCategory ("Dialogs"), ScenarioCategory ("Top Level Windows"), ScenarioCategory ("Files and IO")]
-	public class CsvEditor : Scenario {
-		TableView tableView;
-		private string _currentFile;
-		DataTable currentTable;
-		private MenuItem _miLeft;
-		private MenuItem _miRight;
-		private MenuItem _miCentered;
-		private TextField _selectedCellLabel;
-
-		public override void Setup ()
-		{
-			Win.Title = this.GetName ();
-			Win.Y = 1; // menu
-			Win.Height = Dim.Fill (1); // status bar
-			Application.Top.LayoutSubviews ();
-
-			this.tableView = new TableView () {
-				X = 0,
-				Y = 0,
-				Width = Dim.Fill (),
-				Height = Dim.Fill (1),
-			};
-
-			var fileMenu = new MenuBarItem ("_File", new MenuItem [] {
-					new MenuItem ("_Open CSV", "", () => Open()),
-					new MenuItem ("_Save", "", () => Save()),
-					new MenuItem ("_Quit", "Quits The App", () => Quit()),
-				});
-			//fileMenu.Help = "Help";
-			var menu = new MenuBar (new MenuBarItem [] {
-				fileMenu,
-				new MenuBarItem ("_Edit", new MenuItem [] {
-					new MenuItem ("_New Column", "", () => AddColumn()),
-					new MenuItem ("_New Row", "", () => AddRow()),
-					new MenuItem ("_Rename Column", "", () => RenameColumn()),
-					new MenuItem ("_Delete Column", "", () => DeleteColum()),
-					new MenuItem ("_Move Column", "", () => MoveColumn()),
-					new MenuItem ("_Move Row", "", () => MoveRow()),
-					new MenuItem ("_Sort Asc", "", () => Sort(true)),
-					new MenuItem ("_Sort Desc", "", () => Sort(false)),
-				}),
-				new MenuBarItem ("_View", new MenuItem [] {
-					_miLeft = new MenuItem ("_Align Left", "", () => Align(TextAlignment.Left)),
-					_miRight = new MenuItem ("_Align Right", "", () => Align(TextAlignment.Right)),
-					_miCentered = new MenuItem ("_Align Centered", "", () => Align(TextAlignment.Centered)),
-					
-					// Format requires hard typed data table, when we read a CSV everything is untyped (string) so this only works for new columns in this demo
-					_miCentered = new MenuItem ("_Set Format Pattern", "", () => SetFormat()),
-				})
-			});
-			Application.Top.Add (menu);
-
-			var statusBar = new StatusBar (new StatusItem [] {
-				new StatusItem(KeyCode.CtrlMask | KeyCode.O, "~^O~ Open", () => Open()),
-				new StatusItem(KeyCode.CtrlMask | KeyCode.S, "~^S~ Save", () => Save()),
-				new StatusItem(Application.QuitKey, $"{Application.QuitKey} to Quit", () => Quit()),
-			});
-			Application.Top.Add (statusBar);
-
-			Win.Add (tableView);
-
-			_selectedCellLabel = new TextField () {
-				X = 0,
-				Y = Pos.Bottom (tableView),
-				Text = "0,0",
-				Width = Dim.Fill (),
-				TextAlignment = TextAlignment.Right
-			};
-			_selectedCellLabel.TextChanged += SelectedCellLabel_TextChanged;
-
-			Win.Add (_selectedCellLabel);
-
-			tableView.SelectedCellChanged += OnSelectedCellChanged;
-			tableView.CellActivated += EditCurrentCell;
-			tableView.KeyDown += TableViewKeyPress;
-
-			SetupScrollBar ();
-		}
-
-		private void SelectedCellLabel_TextChanged (object sender, TextChangedEventArgs e)
-		{
-			// if user is in the text control and editing the selected cell
-			if (!_selectedCellLabel.HasFocus)
-				return;
-
-			// change selected cell to the one the user has typed into the box
-			var match = Regex.Match (_selectedCellLabel.Text, "^(\\d+),(\\d+)$");
-			if (match.Success) {
+namespace UICatalog.Scenarios;
+
+[ScenarioMetadata ("Csv Editor", "Open and edit simple CSV files using the TableView class.")]
+[ScenarioCategory ("TableView")] [ScenarioCategory ("TextView")] [ScenarioCategory ("Controls")] [ScenarioCategory ("Dialogs")] [ScenarioCategory ("Text and Formatting")] [ScenarioCategory ("Dialogs")] [ScenarioCategory ("Top Level Windows")] [ScenarioCategory ("Files and IO")]
+public class CsvEditor : Scenario {
+	TableView tableView;
+	string _currentFile;
+	DataTable _currentTable;
+	MenuItem _miLeft;
+	MenuItem _miRight;
+	MenuItem _miCentered;
+	TextField _selectedCellLabel;
+
+	public override void Setup ()
+	{
+		Win.Title = GetName ();
+		Win.Y = 1; // menu
+		Win.Height = Dim.Fill (1); // status bar
+
+		tableView = new TableView () {
+			X = 0,
+			Y = 0,
+			Width = Dim.Fill (),
+			Height = Dim.Fill (1)
+		};
+
+		var fileMenu = new MenuBarItem ("_File", new MenuItem [] {
+			new ("_Open CSV", "", () => Open ()),
+			new ("_Save", "", () => Save ()),
+			new ("_Quit", "Quits The App", () => Quit ())
+		});
+		//fileMenu.Help = "Help";
+		var menu = new MenuBar (new MenuBarItem [] {
+			fileMenu,
+			new ("_Edit", new MenuItem [] {
+				new ("_New Column", "", () => AddColumn ()),
+				new ("_New Row", "", () => AddRow ()),
+				new ("_Rename Column", "", () => RenameColumn ()),
+				new ("_Delete Column", "", () => DeleteColum ()),
+				new ("_Move Column", "", () => MoveColumn ()),
+				new ("_Move Row", "", () => MoveRow ()),
+				new ("_Sort Asc", "", () => Sort (true)),
+				new ("_Sort Desc", "", () => Sort (false))
+			}),
+			new ("_View", new MenuItem [] {
+				_miLeft = new MenuItem ("_Align Left", "", () => Align (TextAlignment.Left)),
+				_miRight = new MenuItem ("_Align Right", "", () => Align (TextAlignment.Right)),
+				_miCentered = new MenuItem ("_Align Centered", "", () => Align (TextAlignment.Centered)),
+
+				// Format requires hard typed data table, when we read a CSV everything is untyped (string) so this only works for new columns in this demo
+				_miCentered = new MenuItem ("_Set Format Pattern", "", () => SetFormat ())
+			})
+		});
+		Application.Top.Add (menu);
+
+		var statusBar = new StatusBar (new StatusItem [] {
+			new (KeyCode.CtrlMask | KeyCode.O, "~^O~ Open", () => Open ()),
+			new (KeyCode.CtrlMask | KeyCode.S, "~^S~ Save", () => Save ()),
+			new (Application.QuitKey, $"{Application.QuitKey} to Quit", () => Quit ())
+		});
+		Application.Top.Add (statusBar);
+
+		Win.Add (tableView);
+
+		_selectedCellLabel = new TextField () {
+			X = 0,
+			Y = Pos.Bottom (tableView),
+			Text = "0,0",
+			Width = Dim.Fill (),
+			TextAlignment = TextAlignment.Right
+		};
+		_selectedCellLabel.TextChanged += SelectedCellLabel_TextChanged;
+
+		Win.Add (_selectedCellLabel);
+
+		tableView.SelectedCellChanged += OnSelectedCellChanged;
+		tableView.CellActivated += EditCurrentCell;
+		tableView.KeyDown += TableViewKeyPress;
+
+		SetupScrollBar ();
+	}
 
-				tableView.SelectedColumn = int.Parse (match.Groups [1].Value);
-				tableView.SelectedRow = int.Parse (match.Groups [2].Value);
-			}
+	void SelectedCellLabel_TextChanged (object sender, TextChangedEventArgs e)
+	{
+		// if user is in the text control and editing the selected cell
+		if (!_selectedCellLabel.HasFocus) {
+			return;
 		}
 
-		private void OnSelectedCellChanged (object sender, SelectedCellChangedEventArgs e)
-		{
-			// only update the text box if the user is not manually editing it
-			if (!_selectedCellLabel.HasFocus)
-				_selectedCellLabel.Text = $"{tableView.SelectedRow},{tableView.SelectedColumn}";
+		// change selected cell to the one the user has typed into the box
+		var match = Regex.Match (_selectedCellLabel.Text, "^(\\d+),(\\d+)$");
+		if (match.Success) {
 
-			if (tableView.Table == null || tableView.SelectedColumn == -1)
-				return;
+			tableView.SelectedColumn = int.Parse (match.Groups [1].Value);
+			tableView.SelectedRow = int.Parse (match.Groups [2].Value);
+		}
+	}
 
-			var style = tableView.Style.GetColumnStyleIfAny (tableView.SelectedColumn);
+	void OnSelectedCellChanged (object sender, SelectedCellChangedEventArgs e)
+	{
+		// only update the text box if the user is not manually editing it
+		if (!_selectedCellLabel.HasFocus) {
+			_selectedCellLabel.Text = $"{tableView.SelectedRow},{tableView.SelectedColumn}";
+		}
 
-			_miLeft.Checked = style?.Alignment == TextAlignment.Left;
-			_miRight.Checked = style?.Alignment == TextAlignment.Right;
-			_miCentered.Checked = style?.Alignment == TextAlignment.Centered;
+		if (tableView.Table == null || tableView.SelectedColumn == -1) {
+			return;
 		}
 
-		private void RenameColumn ()
-		{
-			if (NoTableLoaded ()) {
-				return;
-			}
+		var style = tableView.Style.GetColumnStyleIfAny (tableView.SelectedColumn);
 
-			var currentCol = currentTable.Columns [tableView.SelectedColumn];
+		_miLeft.Checked = style?.Alignment == TextAlignment.Left;
+		_miRight.Checked = style?.Alignment == TextAlignment.Right;
+		_miCentered.Checked = style?.Alignment == TextAlignment.Centered;
+	}
 
-			if (GetText ("Rename Column", "Name:", currentCol.ColumnName, out string newName)) {
-				currentCol.ColumnName = newName;
-				tableView.Update ();
-			}
+	void RenameColumn ()
+	{
+		if (NoTableLoaded ()) {
+			return;
 		}
 
-		private void DeleteColum ()
-		{
-			if (NoTableLoaded ()) {
-				return;
-			}
+		var currentCol = _currentTable.Columns [tableView.SelectedColumn];
 
-			if (tableView.SelectedColumn == -1) {
+		if (GetText ("Rename Column", "Name:", currentCol.ColumnName, out string newName)) {
+			currentCol.ColumnName = newName;
+			tableView.Update ();
+		}
+	}
 
-				MessageBox.ErrorQuery ("No Column", "No column selected", "Ok");
-				return;
-			}
+	void DeleteColum ()
+	{
+		if (NoTableLoaded ()) {
+			return;
+		}
 
-			try {
-				currentTable.Columns.RemoveAt (tableView.SelectedColumn);
-				tableView.Update ();
+		if (tableView.SelectedColumn == -1) {
 
-			} catch (Exception ex) {
-				MessageBox.ErrorQuery ("Could not remove column", ex.Message, "Ok");
-			}
+			MessageBox.ErrorQuery ("No Column", "No column selected", "Ok");
+			return;
 		}
 
-		private void MoveColumn ()
-		{
-			if (NoTableLoaded ()) {
-				return;
-			}
+		try {
+			_currentTable.Columns.RemoveAt (tableView.SelectedColumn);
+			tableView.Update ();
 
-			if (tableView.SelectedColumn == -1) {
+		} catch (Exception ex) {
+			MessageBox.ErrorQuery ("Could not remove column", ex.Message, "Ok");
+		}
+	}
 
-				MessageBox.ErrorQuery ("No Column", "No column selected", "Ok");
-				return;
-			}
+	void MoveColumn ()
+	{
+		if (NoTableLoaded ()) {
+			return;
+		}
 
-			try {
+		if (tableView.SelectedColumn == -1) {
 
-				var currentCol = currentTable.Columns [tableView.SelectedColumn];
+			MessageBox.ErrorQuery ("No Column", "No column selected", "Ok");
+			return;
+		}
 
-				if (GetText ("Move Column", "New Index:", currentCol.Ordinal.ToString (), out string newOrdinal)) {
+		try {
 
-					var newIdx = Math.Min (Math.Max (0, int.Parse (newOrdinal)), tableView.Table.Columns - 1);
+			var currentCol = _currentTable.Columns [tableView.SelectedColumn];
 
-					currentCol.SetOrdinal (newIdx);
+			if (GetText ("Move Column", "New Index:", currentCol.Ordinal.ToString (), out string newOrdinal)) {
 
-					tableView.SetSelection (newIdx, tableView.SelectedRow, false);
-					tableView.EnsureSelectedCellIsVisible ();
-					tableView.SetNeedsDisplay ();
-				}
+				int newIdx = Math.Min (Math.Max (0, int.Parse (newOrdinal)), tableView.Table.Columns - 1);
 
-			} catch (Exception ex) {
-				MessageBox.ErrorQuery ("Error moving column", ex.Message, "Ok");
-			}
-		}
-		private void Sort (bool asc)
-		{
+				currentCol.SetOrdinal (newIdx);
 
-			if (NoTableLoaded ()) {
-				return;
+				tableView.SetSelection (newIdx, tableView.SelectedRow, false);
+				tableView.EnsureSelectedCellIsVisible ();
+				tableView.SetNeedsDisplay ();
 			}
 
-			if (tableView.SelectedColumn == -1) {
-
-				MessageBox.ErrorQuery ("No Column", "No column selected", "Ok");
-				return;
-			}
+		} catch (Exception ex) {
+			MessageBox.ErrorQuery ("Error moving column", ex.Message, "Ok");
+		}
+	}
 
-			var colName = tableView.Table.ColumnNames [tableView.SelectedColumn];
+	void Sort (bool asc)
+	{
 
-			currentTable.DefaultView.Sort = colName + (asc ? " asc" : " desc");
-			SetTable(currentTable.DefaultView.ToTable ());
+		if (NoTableLoaded ()) {
+			return;
 		}
 
-		private void SetTable (DataTable dataTable)
-		{			
-			tableView.Table = new DataTableSource(currentTable = dataTable);
-		}
+		if (tableView.SelectedColumn == -1) {
 
-		private void MoveRow ()
-		{
-			if (NoTableLoaded ()) {
-				return;
-			}
+			MessageBox.ErrorQuery ("No Column", "No column selected", "Ok");
+			return;
+		}
 
-			if (tableView.SelectedRow == -1) {
+		string colName = tableView.Table.ColumnNames [tableView.SelectedColumn];
 
-				MessageBox.ErrorQuery ("No Rows", "No row selected", "Ok");
-				return;
-			}
+		_currentTable.DefaultView.Sort = colName + (asc ? " asc" : " desc");
+		SetTable (_currentTable.DefaultView.ToTable ());
+	}
 
-			try {
+	void SetTable (DataTable dataTable) => tableView.Table = new DataTableSource (_currentTable = dataTable);
 
-				int oldIdx = tableView.SelectedRow;
+	void MoveRow ()
+	{
+		if (NoTableLoaded ()) {
+			return;
+		}
 
-				var currentRow = currentTable.Rows [oldIdx];
+		if (tableView.SelectedRow == -1) {
 
-				if (GetText ("Move Row", "New Row:", oldIdx.ToString (), out string newOrdinal)) {
+			MessageBox.ErrorQuery ("No Rows", "No row selected", "Ok");
+			return;
+		}
 
-					var newIdx = Math.Min (Math.Max (0, int.Parse (newOrdinal)), tableView.Table.Rows - 1);
+		try {
 
-					if (newIdx == oldIdx)
-						return;
+			int oldIdx = tableView.SelectedRow;
 
-					var arrayItems = currentRow.ItemArray;
-					currentTable.Rows.Remove (currentRow);
+			var currentRow = _currentTable.Rows [oldIdx];
 
-					// Removing and Inserting the same DataRow seems to result in it loosing its values so we have to create a new instance
-					var newRow = currentTable.NewRow ();
-					newRow.ItemArray = arrayItems;
+			if (GetText ("Move Row", "New Row:", oldIdx.ToString (), out string newOrdinal)) {
 
-					currentTable.Rows.InsertAt (newRow, newIdx);
+				int newIdx = Math.Min (Math.Max (0, int.Parse (newOrdinal)), tableView.Table.Rows - 1);
 
-					tableView.SetSelection (tableView.SelectedColumn, newIdx, false);
-					tableView.EnsureSelectedCellIsVisible ();
-					tableView.SetNeedsDisplay ();
+				if (newIdx == oldIdx) {
+					return;
 				}
 
-			} catch (Exception ex) {
-				MessageBox.ErrorQuery ("Error moving column", ex.Message, "Ok");
+				object [] arrayItems = currentRow.ItemArray;
+				_currentTable.Rows.Remove (currentRow);
+
+				// Removing and Inserting the same DataRow seems to result in it loosing its values so we have to create a new instance
+				var newRow = _currentTable.NewRow ();
+				newRow.ItemArray = arrayItems;
+
+				_currentTable.Rows.InsertAt (newRow, newIdx);
+
+				tableView.SetSelection (tableView.SelectedColumn, newIdx, false);
+				tableView.EnsureSelectedCellIsVisible ();
+				tableView.SetNeedsDisplay ();
 			}
+
+		} catch (Exception ex) {
+			MessageBox.ErrorQuery ("Error moving column", ex.Message, "Ok");
 		}
+	}
 
-		private void Align (TextAlignment newAlignment)
-		{
-			if (NoTableLoaded ()) {
-				return;
-			}
+	void Align (TextAlignment newAlignment)
+	{
+		if (NoTableLoaded ()) {
+			return;
+		}
 
-			var style = tableView.Style.GetOrCreateColumnStyle (tableView.SelectedColumn);
-			style.Alignment = newAlignment;
+		var style = tableView.Style.GetOrCreateColumnStyle (tableView.SelectedColumn);
+		style.Alignment = newAlignment;
 
-			_miLeft.Checked = style.Alignment == TextAlignment.Left;
-			_miRight.Checked = style.Alignment == TextAlignment.Right;
-			_miCentered.Checked = style.Alignment == TextAlignment.Centered;
+		_miLeft.Checked = style.Alignment == TextAlignment.Left;
+		_miRight.Checked = style.Alignment == TextAlignment.Right;
+		_miCentered.Checked = style.Alignment == TextAlignment.Centered;
 
-			tableView.Update ();
+		tableView.Update ();
+	}
+
+	void SetFormat ()
+	{
+		if (NoTableLoaded ()) {
+			return;
 		}
 
-		private void SetFormat ()
-		{
-			if (NoTableLoaded ()) {
-				return;
-			}
+		var col = _currentTable.Columns [tableView.SelectedColumn];
 
-			var col = currentTable.Columns [tableView.SelectedColumn];
+		if (col.DataType == typeof (string)) {
+			MessageBox.ErrorQuery ("Cannot Format Column", "String columns cannot be Formatted, try adding a new column to the table with a date/numerical Type", "Ok");
+			return;
+		}
 
-			if (col.DataType == typeof (string)) {
-				MessageBox.ErrorQuery ("Cannot Format Column", "String columns cannot be Formatted, try adding a new column to the table with a date/numerical Type", "Ok");
-				return;
-			}
+		var style = tableView.Style.GetOrCreateColumnStyle (col.Ordinal);
 
-			var style = tableView.Style.GetOrCreateColumnStyle (col.Ordinal);
+		if (GetText ("Format", "Pattern:", style.Format ?? "", out string newPattern)) {
+			style.Format = newPattern;
+			tableView.Update ();
+		}
+	}
 
-			if (GetText ("Format", "Pattern:", style.Format ?? "", out string newPattern)) {
-				style.Format = newPattern;
-				tableView.Update ();
-			}
+	bool NoTableLoaded ()
+	{
+		if (tableView.Table == null) {
+			MessageBox.ErrorQuery ("No Table Loaded", "No table has currently be opened", "Ok");
+			return true;
 		}
 
-		private bool NoTableLoaded ()
-		{
-			if (tableView.Table == null) {
-				MessageBox.ErrorQuery ("No Table Loaded", "No table has currently be opened", "Ok");
-				return true;
-			}
+		return false;
+	}
 
-			return false;
+	void AddRow ()
+	{
+		if (NoTableLoaded ()) {
+			return;
 		}
 
-		private void AddRow ()
-		{
-			if (NoTableLoaded ()) {
-				return;
-			}
+		var newRow = _currentTable.NewRow ();
 
-			var newRow = currentTable.NewRow ();
+		int newRowIdx = Math.Min (Math.Max (0, tableView.SelectedRow + 1), tableView.Table.Rows);
 
-			var newRowIdx = Math.Min (Math.Max (0, tableView.SelectedRow + 1), tableView.Table.Rows);
+		_currentTable.Rows.InsertAt (newRow, newRowIdx);
+		tableView.Update ();
+	}
 
-			currentTable.Rows.InsertAt (newRow, newRowIdx);
-			tableView.Update ();
+	void AddColumn ()
+	{
+		if (NoTableLoaded ()) {
+			return;
 		}
 
-		private void AddColumn ()
-		{
-			if (NoTableLoaded ()) {
-				return;
-			}
+		if (GetText ("Enter column name", "Name:", "", out string colName)) {
 
-			if (GetText ("Enter column name", "Name:", "", out string colName)) {
+			var col = new DataColumn (colName);
 
-				var col = new DataColumn (colName);
+			int newColIdx = Math.Min (Math.Max (0, tableView.SelectedColumn + 1), tableView.Table.Columns);
 
-				var newColIdx = Math.Min (Math.Max (0, tableView.SelectedColumn + 1), tableView.Table.Columns);
+			int result = MessageBox.Query ("Column Type", "Pick a data type for the column", new string [] { "Date", "Integer", "Double", "Text", "Cancel" });
 
-				int result = MessageBox.Query ("Column Type", "Pick a data type for the column", new string [] { "Date", "Integer", "Double", "Text", "Cancel" });
+			if (result <= -1 || result >= 4) {
+				return;
+			}
+			switch (result) {
+			case 0:
+				col.DataType = typeof (DateTime);
+				break;
+			case 1:
+				col.DataType = typeof (int);
+				break;
+			case 2:
+				col.DataType = typeof (double);
+				break;
+			case 3:
+				col.DataType = typeof (string);
+				break;
+			}
 
-				if (result <= -1 || result >= 4)
-					return;
-				switch (result) {
-				case 0:
-					col.DataType = typeof (DateTime);
-					break;
-				case 1:
-					col.DataType = typeof (int);
-					break;
-				case 2:
-					col.DataType = typeof (double);
-					break;
-				case 3:
-					col.DataType = typeof (string);
-					break;
-				}
+			_currentTable.Columns.Add (col);
+			col.SetOrdinal (newColIdx);
+			tableView.Update ();
+		}
 
-				currentTable.Columns.Add (col);
-				col.SetOrdinal (newColIdx);
-				tableView.Update ();
-			}
 
+	}
+
+	void Save ()
+	{
+		if (tableView.Table == null || string.IsNullOrWhiteSpace (_currentFile)) {
+			MessageBox.ErrorQuery ("No file loaded", "No file is currently loaded", "Ok");
+			return;
+		}
+		using var writer = new CsvWriter (
+			new StreamWriter (File.OpenWrite (_currentFile)),
+			CultureInfo.InvariantCulture);
 
+		foreach (string col in _currentTable.Columns.Cast<DataColumn> ().Select (c => c.ColumnName)) {
+			writer.WriteField (col);
 		}
 
-		private void Save ()
-		{
-			if (tableView.Table == null || string.IsNullOrWhiteSpace (_currentFile)) {
-				MessageBox.ErrorQuery ("No file loaded", "No file is currently loaded", "Ok");
-				return;
-			}
-			using var writer = new CsvWriter (
-				new StreamWriter (File.OpenWrite (_currentFile)),
-				CultureInfo.InvariantCulture);
+		writer.NextRecord ();
 
-			foreach (var col in currentTable.Columns.Cast<DataColumn> ().Select (c => c.ColumnName)) {
-				writer.WriteField (col);
+		foreach (DataRow row in _currentTable.Rows) {
+			foreach (object item in row.ItemArray) {
+				writer.WriteField (item);
 			}
-
 			writer.NextRecord ();
+		}
 
-			foreach (DataRow row in currentTable.Rows) {
-				foreach (var item in row.ItemArray) {
-					writer.WriteField (item);
-				}
-				writer.NextRecord ();
-			}
+	}
 
-		}
-		
-		private void Open ()
-		{
-			var ofd = new FileDialog () {
-				AllowedTypes = new List<IAllowedType> { new AllowedType("Comma Separated Values", ".csv") }
-			};
-			ofd.Style.OkButtonText = "Open";
+	void Open ()
+	{
+		var ofd = new FileDialog () {
+			AllowedTypes = new List<IAllowedType> { new AllowedType ("Comma Separated Values", ".csv") }
+		};
+		ofd.Style.OkButtonText = "Open";
 
-			Application.Run (ofd);
+		Application.Run (ofd);
 
-			if (!ofd.Canceled && !string.IsNullOrWhiteSpace (ofd.Path)) {
-				Open (ofd.Path);
-			}
+		if (!ofd.Canceled && !string.IsNullOrWhiteSpace (ofd.Path)) {
+			Open (ofd.Path);
 		}
+	}
 
-		private void Open (string filename)
-		{
+	void Open (string filename)
+	{
 
-			int lineNumber = 0;
-			_currentFile = null;
+		int lineNumber = 0;
+		_currentFile = null;
 
-			try {
-				using var reader = new CsvReader (File.OpenText (filename), CultureInfo.InvariantCulture);
+		try {
+			using var reader = new CsvReader (File.OpenText (filename), CultureInfo.InvariantCulture);
 
-				var dt = new DataTable ();
+			var dt = new DataTable ();
 
-				reader.Read ();
+			reader.Read ();
 
-				if (reader.ReadHeader ()) {
-					foreach (var h in reader.HeaderRecord) {
-						dt.Columns.Add (h);
-					}
+			if (reader.ReadHeader ()) {
+				foreach (string h in reader.HeaderRecord) {
+					dt.Columns.Add (h);
 				}
+			}
 
-				while (reader.Read ()) {
-					lineNumber++;
+			while (reader.Read ()) {
+				lineNumber++;
 
-					var newRow = dt.Rows.Add ();
-					for (int i = 0; i < dt.Columns.Count; i++) {
-						newRow [i] = reader [i];
-					}
+				var newRow = dt.Rows.Add ();
+				for (int i = 0; i < dt.Columns.Count; i++) {
+					newRow [i] = reader [i];
 				}
+			}
 
-				SetTable(dt);
+			SetTable (dt);
 
-				// Only set the current filename if we successfully loaded the entire file
-				_currentFile = filename;
-				Win.Title = $"{this.GetName ()} - {Path.GetFileName (_currentFile)}";
+			// Only set the current filename if we successfully loaded the entire file
+			_currentFile = filename;
+			Win.Title = $"{GetName ()} - {Path.GetFileName (_currentFile)}";
 
-			} catch (Exception ex) {
-				MessageBox.ErrorQuery ("Open Failed", $"Error on line {lineNumber}{Environment.NewLine}{ex.Message}", "Ok");
-			}
+		} catch (Exception ex) {
+			MessageBox.ErrorQuery ("Open Failed", $"Error on line {lineNumber}{Environment.NewLine}{ex.Message}", "Ok");
 		}
-		private void SetupScrollBar ()
-		{
-			var scrollBar = new ScrollBarView (tableView, true);
+	}
 
-			scrollBar.ChangedPosition += (s, e) => {
-				tableView.RowOffset = scrollBar.Position;
-				if (tableView.RowOffset != scrollBar.Position) {
-					scrollBar.Position = tableView.RowOffset;
-				}
-				tableView.SetNeedsDisplay ();
-			};
-			/*
-			scrollBar.OtherScrollBarView.ChangedPosition += (s,e) => {
-				tableView.LeftItem = scrollBar.OtherScrollBarView.Position;
-				if (tableView.LeftItem != scrollBar.OtherScrollBarView.Position) {
-					scrollBar.OtherScrollBarView.Position = tableView.LeftItem;
-				}
-				tableView.SetNeedsDisplay ();
-			};*/
+	void SetupScrollBar ()
+	{
+		var scrollBar = new ScrollBarView (tableView, true);
 
-			tableView.DrawContent += (s, e) => {
-				scrollBar.Size = tableView.Table?.Rows ?? 0;
+		scrollBar.ChangedPosition += (s, e) => {
+			tableView.RowOffset = scrollBar.Position;
+			if (tableView.RowOffset != scrollBar.Position) {
 				scrollBar.Position = tableView.RowOffset;
-				//scrollBar.OtherScrollBarView.Size = tableView.Maxlength - 1;
-				//scrollBar.OtherScrollBarView.Position = tableView.LeftItem;
-				scrollBar.Refresh ();
-			};
+			}
+			tableView.SetNeedsDisplay ();
+		};
+		/*
+		scrollBar.OtherScrollBarView.ChangedPosition += (s,e) => {
+			tableView.LeftItem = scrollBar.OtherScrollBarView.Position;
+			if (tableView.LeftItem != scrollBar.OtherScrollBarView.Position) {
+				scrollBar.OtherScrollBarView.Position = tableView.LeftItem;
+			}
+			tableView.SetNeedsDisplay ();
+		};*/
 
-		}
+		tableView.DrawContent += (s, e) => {
+			scrollBar.Size = tableView.Table?.Rows ?? 0;
+			scrollBar.Position = tableView.RowOffset;
+			//scrollBar.OtherScrollBarView.Size = tableView.Maxlength - 1;
+			//scrollBar.OtherScrollBarView.Position = tableView.LeftItem;
+			scrollBar.Refresh ();
+		};
 
-		private void TableViewKeyPress (object sender, Key e)
-		{
-			if (e.KeyCode == KeyCode.DeleteChar) {
+	}
 
-				if (tableView.FullRowSelect) {
-					// Delete button deletes all rows when in full row mode
-					foreach (int toRemove in tableView.GetAllSelectedCells ().Select (p => p.Y).Distinct ().OrderByDescending (i => i))
-						currentTable.Rows.RemoveAt (toRemove);
-				} else {
+	void TableViewKeyPress (object sender, Key e)
+	{
+		if (e.KeyCode == KeyCode.DeleteChar) {
 
-					// otherwise set all selected cells to null
-					foreach (var pt in tableView.GetAllSelectedCells ()) {
-						currentTable.Rows [pt.Y] [pt.X] = DBNull.Value;
-					}
+			if (tableView.FullRowSelect) {
+				// Delete button deletes all rows when in full row mode
+				foreach (int toRemove in tableView.GetAllSelectedCells ().Select (p => p.Y).Distinct ().OrderByDescending (i => i)) {
+					_currentTable.Rows.RemoveAt (toRemove);
 				}
+			} else {
 
-				tableView.Update ();
-				e.Handled = true;
+				// otherwise set all selected cells to null
+				foreach (var pt in tableView.GetAllSelectedCells ()) {
+					_currentTable.Rows [pt.Y] [pt.X] = DBNull.Value;
+				}
 			}
-		}
 
-		private void ClearColumnStyles ()
-		{
-			tableView.Style.ColumnStyles.Clear ();
 			tableView.Update ();
+			e.Handled = true;
 		}
+	}
 
-		private void CloseExample ()
-		{
-			tableView.Table = null;
-		}
-
-		private void Quit ()
-		{
-			Application.RequestStop ();
-		}
-		private bool GetText (string title, string label, string initialText, out string enteredText)
-		{
-			bool okPressed = false;
-
-			var ok = new Button ("Ok", is_default: true);
-			ok.Clicked += (s, e) => { okPressed = true; Application.RequestStop (); };
-			var cancel = new Button ("Cancel");
-			cancel.Clicked += (s, e) => { Application.RequestStop (); };
-			var d = new Dialog (ok, cancel) { Title = title };
+	void ClearColumnStyles ()
+	{
+		tableView.Style.ColumnStyles.Clear ();
+		tableView.Update ();
+	}
 
-			var lbl = new Label () {
-				X = 0,
-				Y = 1,
-				Text = label
-			};
+	void CloseExample () => tableView.Table = null;
 
-			var tf = new TextField () {
-				Text = initialText,
-				X = 0,
-				Y = 2,
-				Width = Dim.Fill ()
-			};
+	void Quit () => Application.RequestStop ();
 
-			d.Add (lbl, tf);
-			tf.SetFocus ();
+	bool GetText (string title, string label, string initialText, out string enteredText)
+	{
+		bool okPressed = false;
 
-			Application.Run (d);
+		var ok = new Button ("Ok", true);
+		ok.Clicked += (s, e) => {
+			okPressed = true;
+			Application.RequestStop ();
+		};
+		var cancel = new Button ("Cancel");
+		cancel.Clicked += (s, e) => { Application.RequestStop (); };
+		var d = new Dialog (ok, cancel) { Title = title };
+
+		var lbl = new Label () {
+			X = 0,
+			Y = 1,
+			Text = label
+		};
+
+		var tf = new TextField () {
+			Text = initialText,
+			X = 0,
+			Y = 2,
+			Width = Dim.Fill ()
+		};
+
+		d.Add (lbl, tf);
+		tf.SetFocus ();
+
+		Application.Run (d);
+
+		enteredText = okPressed ? tf.Text : null;
+		return okPressed;
+	}
 
-			enteredText = okPressed ? tf.Text : null;
-			return okPressed;
+	void EditCurrentCell (object sender, CellActivatedEventArgs e)
+	{
+		if (e.Table == null) {
+			return;
 		}
-		private void EditCurrentCell (object sender, CellActivatedEventArgs e)
-		{
-			if (e.Table == null)
-				return;
 
-			var oldValue = currentTable.Rows [e.Row] [e.Col].ToString ();
-
-			if (GetText ("Enter new value", currentTable.Columns [e.Col].ColumnName, oldValue, out string newText)) {
-				try {
-					currentTable.Rows [e.Row] [e.Col] = string.IsNullOrWhiteSpace (newText) ? DBNull.Value : (object)newText;
-				} catch (Exception ex) {
-					MessageBox.ErrorQuery (60, 20, "Failed to set text", ex.Message, "Ok");
-				}
+		string oldValue = _currentTable.Rows [e.Row] [e.Col].ToString ();
 
-				tableView.Update ();
+		if (GetText ("Enter new value", _currentTable.Columns [e.Col].ColumnName, oldValue, out string newText)) {
+			try {
+				_currentTable.Rows [e.Row] [e.Col] = string.IsNullOrWhiteSpace (newText) ? DBNull.Value : (object)newText;
+			} catch (Exception ex) {
+				MessageBox.ErrorQuery (60, 20, "Failed to set text", ex.Message, "Ok");
 			}
+
+			tableView.Update ();
 		}
 	}
-}
+}

+ 0 - 1
UICatalog/Scenarios/GraphViewExample.cs

@@ -23,7 +23,6 @@ namespace UICatalog.Scenarios {
 			Win.Title = this.GetName ();
 			Win.Y = 1; // menu
 			Win.Height = Dim.Fill (1); // status bar
-			Application.Top.LayoutSubviews ();
 
 			graphs = new Action [] {
 				 ()=>SetupPeriodicTableScatterPlot(),    //0

+ 0 - 1
UICatalog/Scenarios/InteractiveTree.cs

@@ -15,7 +15,6 @@ namespace UICatalog.Scenarios {
 			Win.Title = this.GetName ();
 			Win.Y = 1; // menu
 			Win.Height = Dim.Fill (1); // status bar
-			Application.Top.LayoutSubviews ();
 
 			var menu = new MenuBar (new MenuBarItem [] {
 				new MenuBarItem ("_File", new MenuItem [] {

+ 0 - 1
UICatalog/Scenarios/LineViewExample.cs

@@ -17,7 +17,6 @@ namespace UICatalog.Scenarios {
 			Win.Title = this.GetName ();
 			Win.Y = 1; // menu
 			Win.Height = Dim.Fill (1); // status bar
-			Application.Top.LayoutSubviews ();
 
 			var menu = new MenuBar (new MenuBarItem [] {
 			new MenuBarItem ("_File", new MenuItem [] {

+ 0 - 1
UICatalog/Scenarios/ListColumns.cs

@@ -34,7 +34,6 @@ namespace UICatalog.Scenarios {
 			Win.Title = this.GetName ();
 			Win.Y = 1; // menu
 			Win.Height = Dim.Fill (1); // status bar
-			Application.Top.LayoutSubviews ();
 
 			this.listColView = new TableView () {
 				X = 0,

+ 0 - 1
UICatalog/Scenarios/MultiColouredTable.cs

@@ -18,7 +18,6 @@ namespace UICatalog.Scenarios {
 			Win.Title = this.GetName ();
 			Win.Y = 1; // menu
 			Win.Height = Dim.Fill (1); // status bar
-			Application.Top.LayoutSubviews ();
 
 			this.tableView = new TableViewColors () {
 				X = 0,

+ 1 - 2
UICatalog/Scenarios/Notepad.cs

@@ -70,8 +70,7 @@ namespace UICatalog.Scenarios {
 			tabView.Enter += (s, e) => focusedTabView = tabView;
 
 			Application.Top.Add (statusBar);
-
-			New ();
+			Application.Top.Ready += (s, e) => New ();
 		}
 
 		private void TabView_SelectedTabChanged (object sender, TabChangedEventArgs e)

+ 0 - 1
UICatalog/Scenarios/ProcessTable.cs

@@ -18,7 +18,6 @@ namespace UICatalog.Scenarios {
 			Win.Title = this.GetName ();
 			Win.Y = 1; // menu
 			Win.Height = Dim.Fill (1); // status bar
-			Application.Top.LayoutSubviews ();
 
 			this.tableView = new TableView () {
 				X = 0,

+ 5 - 5
UICatalog/Scenarios/Progress.cs

@@ -112,11 +112,11 @@ namespace UICatalog.Scenarios {
 				};
 				Add (_startedLabel);
 
-				// Explictly cause layout so the setting of Height below works
-				LayoutSubviews ();
-
-				// Set height to height of controls + spacing + frame
-				Height = 2 + _verticalSpace + startButton.Frame.Height + _verticalSpace + ActivityProgressBar.Frame.Height + _verticalSpace + PulseProgressBar.Frame.Height + _verticalSpace;
+				// TODO: Great use of Dim.Auto
+				Initialized += (s, e) => {
+					// Set height to height of controls + spacing + frame
+					Height = 2 + _verticalSpace + startButton.Frame.Height + _verticalSpace + ActivityProgressBar.Frame.Height + _verticalSpace + PulseProgressBar.Frame.Height + _verticalSpace;
+				};
 			}
 
 			internal void Start ()

+ 3 - 1
UICatalog/Scenarios/Sliders.cs

@@ -72,7 +72,9 @@ public class Sliders : Scenario {
 				else
 					s.ShowSpacing = false;
 			}
-			Win.LayoutSubviews ();
+			if (Win.IsInitialized) {
+				Win.LayoutSubviews ();
+			}
 		};
 		slider.SetOption (0);
 		slider.SetOption (1);

+ 0 - 1
UICatalog/Scenarios/TabViewExample.cs

@@ -24,7 +24,6 @@ namespace UICatalog.Scenarios {
 			Win.Title = this.GetName ();
 			Win.Y = 1; // menu
 			Win.Height = Dim.Fill (1); // status bar
-			Application.Top.LayoutSubviews ();
 
 			var menu = new MenuBar (new MenuBarItem [] {
 				new MenuBarItem ("_File", new MenuItem [] {

+ 1 - 2
UICatalog/Scenarios/TableEditor.cs

@@ -49,8 +49,7 @@ namespace UICatalog.Scenarios {
 			Win.Title = this.GetName ();
 			Win.Y = 1; // menu
 			Win.Height = Dim.Fill (1); // status bar
-			Application.Top.LayoutSubviews ();
-
+			
 			this.tableView = new TableView () {
 				X = 0,
 				Y = 0,

+ 0 - 1
UICatalog/Scenarios/TreeUseCases.cs

@@ -14,7 +14,6 @@ namespace UICatalog.Scenarios {
 			Win.Title = this.GetName ();
 			Win.Y = 1; // menu
 			Win.Height = Dim.Fill (1); // status bar
-			Application.Top.LayoutSubviews ();
 
 			var menu = new MenuBar (new MenuBarItem [] {
 				new MenuBarItem ("_File", new MenuItem [] {

+ 334 - 336
UICatalog/Scenarios/TreeViewFileSystem.cs

@@ -1,400 +1,398 @@
-using System;
-using System.Collections.Generic;
 using System.IO;
 using System.IO.Abstractions;
 using System.Linq;
 using System.Text;
 using Terminal.Gui;
 
-namespace UICatalog.Scenarios {
-	[ScenarioMetadata (Name: "File System Explorer", Description: "Hierarchical file system explorer demonstrating TreeView.")]
-	[ScenarioCategory ("Controls"), ScenarioCategory ("TreeView"), ScenarioCategory ("Files and IO")]
-	public class TreeViewFileSystem : Scenario {
-
-		/// <summary>
-		/// A tree view where nodes are files and folders
-		/// </summary>
-		TreeView<IFileSystemInfo> treeViewFiles;
-
-		MenuItem miShowLines;
-		private MenuItem _miPlusMinus;
-		private MenuItem _miArrowSymbols;
-		private MenuItem _miNoSymbols;
-		private MenuItem _miColoredSymbols;
-		private MenuItem _miInvertSymbols;
-
-		private MenuItem _miBasicIcons;
-		private MenuItem _miUnicodeIcons;
-		private MenuItem _miNerdIcons;
-
-		private MenuItem _miFullPaths;
-		private MenuItem _miLeaveLastRow;
-		private MenuItem _miHighlightModelTextOnly;
-		private MenuItem _miCustomColors;
-		private MenuItem _miCursor;
-		private MenuItem _miMultiSelect;
-
-		private DetailsFrame _detailsFrame;
-		private FileSystemIconProvider _iconProvider = new ();
-
-		public override void Setup ()
-		{
-			Win.Title = this.GetName ();
-			Win.Y = 1; // menu
-			Win.Height = Dim.Fill ();
-			Application.Top.LayoutSubviews ();
-
-			var menu = new MenuBar (new MenuBarItem [] {
-				new MenuBarItem ("_File", new MenuItem [] {
-					new MenuItem ("_Quit", $"{Application.QuitKey}", () => Quit()),
-				}),
-				new MenuBarItem ("_View", new MenuItem [] {
-					_miFullPaths = new MenuItem ("_Full Paths", "", () => SetFullName()){Checked = false, CheckType = MenuItemCheckStyle.Checked},
-					_miMultiSelect = new MenuItem ("_Multi Select", "", () => SetMultiSelect()){Checked = true, CheckType = MenuItemCheckStyle.Checked},
-				}),
-				new MenuBarItem ("_Style", new MenuItem [] {
-					miShowLines = new MenuItem ("_Show Lines", "", () => ShowLines()){
+namespace UICatalog.Scenarios;
+
+[ScenarioMetadata ("File System Explorer", "Hierarchical file system explorer demonstrating TreeView.")]
+[ScenarioCategory ("Controls")] [ScenarioCategory ("TreeView")] [ScenarioCategory ("Files and IO")]
+public class TreeViewFileSystem : Scenario {
+	/// <summary>
+	/// A tree view where nodes are files and folders
+	/// </summary>
+	TreeView<IFileSystemInfo> _treeViewFiles;
+
+	MenuItem _miShowLines;
+	MenuItem _miPlusMinus;
+	MenuItem _miArrowSymbols;
+	MenuItem _miNoSymbols;
+	MenuItem _miColoredSymbols;
+	MenuItem _miInvertSymbols;
+
+	MenuItem _miBasicIcons;
+	MenuItem _miUnicodeIcons;
+	MenuItem _miNerdIcons;
+
+	MenuItem _miFullPaths;
+	MenuItem _miLeaveLastRow;
+	MenuItem _miHighlightModelTextOnly;
+	MenuItem _miCustomColors;
+	MenuItem _miCursor;
+	MenuItem _miMultiSelect;
+
+	DetailsFrame _detailsFrame;
+	FileSystemIconProvider _iconProvider = new ();
+
+	public override void Setup ()
+	{
+		Win.Title = GetName ();
+		Win.Y = 1; // menu
+		Win.Height = Dim.Fill ();
+
+		var menu = new MenuBar (new MenuBarItem [] {
+			new ("_File", new MenuItem [] {
+				new ("_Quit", $"{Application.QuitKey}", () => Quit ())
+			}),
+			new ("_View", new MenuItem [] {
+				_miFullPaths = new MenuItem ("_Full Paths", "", () => SetFullName ()) { Checked = false, CheckType = MenuItemCheckStyle.Checked },
+				_miMultiSelect = new MenuItem ("_Multi Select", "", () => SetMultiSelect ()) { Checked = true, CheckType = MenuItemCheckStyle.Checked }
+			}),
+			new ("_Style", new MenuItem [] {
+				_miShowLines = new MenuItem ("_Show Lines", "", () => ShowLines ()) {
 					Checked = true, CheckType = MenuItemCheckStyle.Checked
-						},
-					null /*separator*/,
-					_miPlusMinus = new MenuItem ("_Plus Minus Symbols", "+ -", () => SetExpandableSymbols((Rune)'+',(Rune)'-')){Checked = true, CheckType = MenuItemCheckStyle.Radio},
-					_miArrowSymbols = new MenuItem ("_Arrow Symbols", "> v", () => SetExpandableSymbols((Rune)'>',(Rune)'v')){Checked = false, CheckType = MenuItemCheckStyle.Radio},
-					_miNoSymbols = new MenuItem ("_No Symbols", "", () => SetExpandableSymbols(default,null)){Checked = false, CheckType = MenuItemCheckStyle.Radio},
-					null /*separator*/,
-					_miColoredSymbols = new MenuItem ("_Colored Symbols", "", () => ShowColoredExpandableSymbols()){Checked = false, CheckType = MenuItemCheckStyle.Checked},
-					_miInvertSymbols = new MenuItem ("_Invert Symbols", "", () => InvertExpandableSymbols()){Checked = false, CheckType = MenuItemCheckStyle.Checked},
-					null /*separator*/,
-					_miBasicIcons = new MenuItem ("_Basic Icons",null, SetNoIcons){Checked = false, CheckType = MenuItemCheckStyle.Radio},
-					_miUnicodeIcons = new MenuItem ("_Unicode Icons", null, SetUnicodeIcons){Checked = false, CheckType = MenuItemCheckStyle.Radio},
-					_miNerdIcons = new MenuItem ("_Nerd Icons", null, SetNerdIcons){Checked = false, CheckType = MenuItemCheckStyle.Radio},
-					null /*separator*/,
-					_miLeaveLastRow = new MenuItem ("_Leave Last Row", "", () => SetLeaveLastRow()){Checked = true, CheckType = MenuItemCheckStyle.Checked},
-					_miHighlightModelTextOnly = new MenuItem ("_Highlight Model Text Only", "", () => SetCheckHighlightModelTextOnly()){Checked = false, CheckType = MenuItemCheckStyle.Checked},
-					null /*separator*/,
-					_miCustomColors = new MenuItem ("C_ustom Colors Hidden Files", "Yellow/Red", () => SetCustomColors()){Checked = false, CheckType = MenuItemCheckStyle.Checked},
-					null /*separator*/,
-					_miCursor = new MenuItem ("Curs_or (MultiSelect only)", "", () => SetCursor()){Checked = false, CheckType = MenuItemCheckStyle.Checked},
-				}),
-			});
-			Application.Top.Add (menu);
-
-			treeViewFiles = new TreeView<IFileSystemInfo> () {
-				X = 0,
-				Y = 0,
-				Width = Dim.Percent (50),
-				Height = Dim.Fill (),
-			};
-			treeViewFiles.DrawLine += TreeViewFiles_DrawLine;
-
-			_detailsFrame = new DetailsFrame (_iconProvider) {
-				X = Pos.Right (treeViewFiles),
-				Y = 0,
-				Width = Dim.Fill (),
-				Height = Dim.Fill (),
-			};
-
-			Win.Add (_detailsFrame);
-			treeViewFiles.MouseClick += TreeViewFiles_MouseClick;
-			treeViewFiles.KeyDown += TreeViewFiles_KeyPress;
-			treeViewFiles.SelectionChanged += TreeViewFiles_SelectionChanged;
-
-			SetupFileTree ();
+				},
+				null /*separator*/,
+				_miPlusMinus = new MenuItem ("_Plus Minus Symbols", "+ -", () => SetExpandableSymbols ((Rune)'+', (Rune)'-')) { Checked = true, CheckType = MenuItemCheckStyle.Radio },
+				_miArrowSymbols = new MenuItem ("_Arrow Symbols", "> v", () => SetExpandableSymbols ((Rune)'>', (Rune)'v')) { Checked = false, CheckType = MenuItemCheckStyle.Radio },
+				_miNoSymbols = new MenuItem ("_No Symbols", "", () => SetExpandableSymbols (default, null)) { Checked = false, CheckType = MenuItemCheckStyle.Radio },
+				null /*separator*/,
+				_miColoredSymbols = new MenuItem ("_Colored Symbols", "", () => ShowColoredExpandableSymbols ()) { Checked = false, CheckType = MenuItemCheckStyle.Checked },
+				_miInvertSymbols = new MenuItem ("_Invert Symbols", "", () => InvertExpandableSymbols ()) { Checked = false, CheckType = MenuItemCheckStyle.Checked },
+				null /*separator*/,
+				_miBasicIcons = new MenuItem ("_Basic Icons", null, SetNoIcons) { Checked = false, CheckType = MenuItemCheckStyle.Radio },
+				_miUnicodeIcons = new MenuItem ("_Unicode Icons", null, SetUnicodeIcons) { Checked = false, CheckType = MenuItemCheckStyle.Radio },
+				_miNerdIcons = new MenuItem ("_Nerd Icons", null, SetNerdIcons) { Checked = false, CheckType = MenuItemCheckStyle.Radio },
+				null /*separator*/,
+				_miLeaveLastRow = new MenuItem ("_Leave Last Row", "", () => SetLeaveLastRow ()) { Checked = true, CheckType = MenuItemCheckStyle.Checked },
+				_miHighlightModelTextOnly = new MenuItem ("_Highlight Model Text Only", "", () => SetCheckHighlightModelTextOnly ()) { Checked = false, CheckType = MenuItemCheckStyle.Checked },
+				null /*separator*/,
+				_miCustomColors = new MenuItem ("C_ustom Colors Hidden Files", "Yellow/Red", () => SetCustomColors ()) { Checked = false, CheckType = MenuItemCheckStyle.Checked },
+				null /*separator*/,
+				_miCursor = new MenuItem ("Curs_or (MultiSelect only)", "", () => SetCursor ()) { Checked = false, CheckType = MenuItemCheckStyle.Checked }
+			})
+		});
+		Application.Top.Add (menu);
+
+		_treeViewFiles = new TreeView<IFileSystemInfo> () {
+			X = 0,
+			Y = 0,
+			Width = Dim.Percent (50),
+			Height = Dim.Fill ()
+		};
+		_treeViewFiles.DrawLine += TreeViewFiles_DrawLine;
+
+		_detailsFrame = new DetailsFrame (_iconProvider) {
+			X = Pos.Right (_treeViewFiles),
+			Y = 0,
+			Width = Dim.Fill (),
+			Height = Dim.Fill ()
+		};
+
+		Win.Add (_detailsFrame);
+		_treeViewFiles.MouseClick += TreeViewFiles_MouseClick;
+		_treeViewFiles.KeyDown += TreeViewFiles_KeyPress;
+		_treeViewFiles.SelectionChanged += TreeViewFiles_SelectionChanged;
+
+		SetupFileTree ();
+
+		Win.Add (_treeViewFiles);
+		_treeViewFiles.GoToFirst ();
+		_treeViewFiles.Expand ();
+
+		SetupScrollBar ();
+
+		_treeViewFiles.SetFocus ();
+
+		UpdateIconCheckedness ();
+	}
 
-			Win.Add (treeViewFiles);
-			treeViewFiles.GoToFirst ();
-			treeViewFiles.Expand ();
+	void SetNoIcons ()
+	{
+		_iconProvider.UseUnicodeCharacters = false;
+		_iconProvider.UseNerdIcons = false;
+		UpdateIconCheckedness ();
+	}
 
-			SetupScrollBar ();
+	void SetUnicodeIcons ()
+	{
+		_iconProvider.UseUnicodeCharacters = true;
+		UpdateIconCheckedness ();
+	}
 
-			treeViewFiles.SetFocus ();
+	void SetNerdIcons ()
+	{
+		_iconProvider.UseNerdIcons = true;
+		UpdateIconCheckedness ();
+	}
 
-			UpdateIconCheckedness ();
-		}
+	void UpdateIconCheckedness ()
+	{
+		_miBasicIcons.Checked = !_iconProvider.UseNerdIcons && !_iconProvider.UseUnicodeCharacters;
+		_miUnicodeIcons.Checked = _iconProvider.UseUnicodeCharacters;
+		_miNerdIcons.Checked = _iconProvider.UseNerdIcons;
+		_treeViewFiles.SetNeedsDisplay ();
+	}
 
-		private void SetNoIcons ()
-		{
-			_iconProvider.UseUnicodeCharacters = false;
-			_iconProvider.UseNerdIcons = false;
-			UpdateIconCheckedness ();
+	void TreeViewFiles_SelectionChanged (object sender, SelectionChangedEventArgs<IFileSystemInfo> e) => ShowPropertiesOf (e.NewValue);
+
+	void TreeViewFiles_DrawLine (object sender, DrawTreeViewLineEventArgs<IFileSystemInfo> e)
+	{
+		// Render directory icons in yellow
+		if (e.Model is IDirectoryInfo d) {
+			if (_iconProvider.UseNerdIcons || _iconProvider.UseUnicodeCharacters) {
+				if (e.IndexOfModelText > 0 && e.IndexOfModelText < e.RuneCells.Count) {
+					var cell = e.RuneCells [e.IndexOfModelText];
+					cell.ColorScheme = new ColorScheme (
+						new Attribute (
+							Color.BrightYellow,
+							cell.ColorScheme.Normal.Background)
+					);
+				}
+			}
 		}
+	}
 
-		private void SetUnicodeIcons ()
-		{
-			_iconProvider.UseUnicodeCharacters = true;
-			UpdateIconCheckedness ();
-		}
-		private void SetNerdIcons ()
-		{
-			_iconProvider.UseNerdIcons = true;
-			UpdateIconCheckedness ();
-		}
-		private void UpdateIconCheckedness ()
-		{
-			_miBasicIcons.Checked = !_iconProvider.UseNerdIcons && !_iconProvider.UseUnicodeCharacters;
-			_miUnicodeIcons.Checked = _iconProvider.UseUnicodeCharacters;
-			_miNerdIcons.Checked = _iconProvider.UseNerdIcons;
-			treeViewFiles.SetNeedsDisplay ();
-		}
+	void TreeViewFiles_KeyPress (object sender, Key obj)
+	{
+		if (obj.KeyCode == (KeyCode.R | KeyCode.CtrlMask)) {
 
-		private void TreeViewFiles_SelectionChanged (object sender, SelectionChangedEventArgs<IFileSystemInfo> e)
-		{
-			ShowPropertiesOf (e.NewValue);
-		}
+			var selected = _treeViewFiles.SelectedObject;
 
-		private void TreeViewFiles_DrawLine (object sender, DrawTreeViewLineEventArgs<IFileSystemInfo> e)
-		{
-			// Render directory icons in yellow
-			if (e.Model is IDirectoryInfo d) {
-				if (_iconProvider.UseNerdIcons || _iconProvider.UseUnicodeCharacters) {
-					if (e.IndexOfModelText > 0 && e.IndexOfModelText < e.RuneCells.Count) {
-						var cell = e.RuneCells [e.IndexOfModelText];
-						cell.ColorScheme = new ColorScheme (
-							new Terminal.Gui.Attribute (
-								Color.BrightYellow,
-								cell.ColorScheme.Normal.Background)
-						);
-					}
-				}
+			// nothing is selected
+			if (selected == null) {
+				return;
 			}
-		}
 
-		private void TreeViewFiles_KeyPress (object sender, Key obj)
-		{
-			if (obj.KeyCode == (KeyCode.R | KeyCode.CtrlMask)) {
+			int? location = _treeViewFiles.GetObjectRow (selected);
 
-				var selected = treeViewFiles.SelectedObject;
+			//selected object is offscreen or somehow not found
+			if (location == null || location < 0 || location > _treeViewFiles.Frame.Height) {
+				return;
+			}
 
-				// nothing is selected
-				if (selected == null)
-					return;
+			ShowContextMenu (new Point (
+					5 + _treeViewFiles.Frame.X,
+					location.Value + _treeViewFiles.Frame.Y + 2),
+				selected);
+		}
+	}
 
-				var location = treeViewFiles.GetObjectRow (selected);
+	void TreeViewFiles_MouseClick (object sender, MouseEventEventArgs obj)
+	{
+		// if user right clicks
+		if (obj.MouseEvent.Flags.HasFlag (MouseFlags.Button3Clicked)) {
 
-				//selected object is offscreen or somehow not found
-				if (location == null || location < 0 || location > treeViewFiles.Frame.Height)
-					return;
+			var rightClicked = _treeViewFiles.GetObjectOnRow (obj.MouseEvent.Y);
 
-				ShowContextMenu (new Point (
-					5 + treeViewFiles.Frame.X,
-					location.Value + treeViewFiles.Frame.Y + 2),
-					selected);
+			// nothing was clicked
+			if (rightClicked == null) {
+				return;
 			}
+
+			ShowContextMenu (new Point (
+					obj.MouseEvent.X + _treeViewFiles.Frame.X,
+					obj.MouseEvent.Y + _treeViewFiles.Frame.Y + 2),
+				rightClicked);
 		}
+	}
 
-		private void TreeViewFiles_MouseClick (object sender, MouseEventEventArgs obj)
-		{
-			// if user right clicks
-			if (obj.MouseEvent.Flags.HasFlag (MouseFlags.Button3Clicked)) {
+	void ShowContextMenu (Point screenPoint, IFileSystemInfo forObject)
+	{
+		var menu = new ContextMenu ();
+		menu.Position = screenPoint;
 
-				var rightClicked = treeViewFiles.GetObjectOnRow (obj.MouseEvent.Y);
+		menu.MenuItems = new MenuBarItem (new [] { new MenuItem ("Properties", null, () => ShowPropertiesOf (forObject)) });
 
-				// nothing was clicked
-				if (rightClicked == null)
-					return;
+		Application.Invoke (menu.Show);
+	}
 
-				ShowContextMenu (new Point (
-					obj.MouseEvent.X + treeViewFiles.Frame.X,
-					obj.MouseEvent.Y + treeViewFiles.Frame.Y + 2),
-					rightClicked);
-			}
-		}
+	class DetailsFrame : FrameView {
+		IFileSystemInfo fileInfo;
+		FileSystemIconProvider _iconProvider;
 
-		private void ShowContextMenu (Point screenPoint, IFileSystemInfo forObject)
+		public DetailsFrame (FileSystemIconProvider iconProvider)
 		{
-			var menu = new ContextMenu ();
-			menu.Position = screenPoint;
-
-			menu.MenuItems = new MenuBarItem (new [] { new MenuItem ("Properties", null, () => ShowPropertiesOf (forObject)) });
-
-			Application.Invoke (menu.Show);
+			Title = "Details";
+			Visible = true;
+			CanFocus = true;
+			_iconProvider = iconProvider;
 		}
 
-		class DetailsFrame : FrameView {
-			private IFileSystemInfo fileInfo;
-			private FileSystemIconProvider _iconProvider;
-
-			public DetailsFrame (FileSystemIconProvider iconProvider)
-			{
-				Title = "Details";
-				Visible = true;
-				CanFocus = true;
-				_iconProvider = iconProvider;
-			}
+		public IFileSystemInfo FileInfo {
+			get => fileInfo;
+			set {
+				fileInfo = value;
+				StringBuilder sb = null;
+
+				if (fileInfo is IFileInfo f) {
+					Title = $"{_iconProvider.GetIconWithOptionalSpace (f)}{f.Name}".Trim ();
+					sb = new StringBuilder ();
+					sb.AppendLine ($"Path:\n {f.FullName}\n");
+					sb.AppendLine ($"Size:\n {f.Length:N0} bytes\n");
+					sb.AppendLine ($"Modified:\n {f.LastWriteTime}\n");
+					sb.AppendLine ($"Created:\n {f.CreationTime}");
+				}
 
-			public IFileSystemInfo FileInfo {
-				get => fileInfo; set {
-					fileInfo = value;
-					System.Text.StringBuilder sb = null;
-
-					if (fileInfo is IFileInfo f) {
-						Title = $"{_iconProvider.GetIconWithOptionalSpace (f)}{f.Name}".Trim ();
-						sb = new System.Text.StringBuilder ();
-						sb.AppendLine ($"Path:\n {f.FullName}\n");
-						sb.AppendLine ($"Size:\n {f.Length:N0} bytes\n");
-						sb.AppendLine ($"Modified:\n {f.LastWriteTime}\n");
-						sb.AppendLine ($"Created:\n {f.CreationTime}");
-					}
-
-					if (fileInfo is IDirectoryInfo dir) {
-						Title = $"{_iconProvider.GetIconWithOptionalSpace (dir)}{dir.Name}".Trim ();
-						sb = new System.Text.StringBuilder ();
-						sb.AppendLine ($"Path:\n {dir?.FullName}\n");
-						sb.AppendLine ($"Modified:\n {dir.LastWriteTime}\n");
-						sb.AppendLine ($"Created:\n {dir.CreationTime}\n");
-					}
-					Text = sb.ToString ();
+				if (fileInfo is IDirectoryInfo dir) {
+					Title = $"{_iconProvider.GetIconWithOptionalSpace (dir)}{dir.Name}".Trim ();
+					sb = new StringBuilder ();
+					sb.AppendLine ($"Path:\n {dir?.FullName}\n");
+					sb.AppendLine ($"Modified:\n {dir.LastWriteTime}\n");
+					sb.AppendLine ($"Created:\n {dir.CreationTime}\n");
 				}
+				Text = sb.ToString ();
 			}
 		}
+	}
 
-		private void ShowPropertiesOf (IFileSystemInfo fileSystemInfo)
-		{
-			_detailsFrame.FileInfo = fileSystemInfo;
-		}
+	void ShowPropertiesOf (IFileSystemInfo fileSystemInfo) => _detailsFrame.FileInfo = fileSystemInfo;
 
-		private void SetupScrollBar ()
-		{
-			// When using scroll bar leave the last row of the control free (for over-rendering with scroll bar)
-			treeViewFiles.Style.LeaveLastRow = true;
+	void SetupScrollBar ()
+	{
+		// When using scroll bar leave the last row of the control free (for over-rendering with scroll bar)
+		_treeViewFiles.Style.LeaveLastRow = true;
 
-			var scrollBar = new ScrollBarView (treeViewFiles, true);
+		var scrollBar = new ScrollBarView (_treeViewFiles, true);
 
-			scrollBar.ChangedPosition += (s, e) => {
-				treeViewFiles.ScrollOffsetVertical = scrollBar.Position;
-				if (treeViewFiles.ScrollOffsetVertical != scrollBar.Position) {
-					scrollBar.Position = treeViewFiles.ScrollOffsetVertical;
-				}
-				treeViewFiles.SetNeedsDisplay ();
-			};
+		scrollBar.ChangedPosition += (s, e) => {
+			_treeViewFiles.ScrollOffsetVertical = scrollBar.Position;
+			if (_treeViewFiles.ScrollOffsetVertical != scrollBar.Position) {
+				scrollBar.Position = _treeViewFiles.ScrollOffsetVertical;
+			}
+			_treeViewFiles.SetNeedsDisplay ();
+		};
 
-			scrollBar.OtherScrollBarView.ChangedPosition += (s, e) => {
-				treeViewFiles.ScrollOffsetHorizontal = scrollBar.OtherScrollBarView.Position;
-				if (treeViewFiles.ScrollOffsetHorizontal != scrollBar.OtherScrollBarView.Position) {
-					scrollBar.OtherScrollBarView.Position = treeViewFiles.ScrollOffsetHorizontal;
-				}
-				treeViewFiles.SetNeedsDisplay ();
-			};
+		scrollBar.OtherScrollBarView.ChangedPosition += (s, e) => {
+			_treeViewFiles.ScrollOffsetHorizontal = scrollBar.OtherScrollBarView.Position;
+			if (_treeViewFiles.ScrollOffsetHorizontal != scrollBar.OtherScrollBarView.Position) {
+				scrollBar.OtherScrollBarView.Position = _treeViewFiles.ScrollOffsetHorizontal;
+			}
+			_treeViewFiles.SetNeedsDisplay ();
+		};
+
+		_treeViewFiles.DrawContent += (s, e) => {
+			scrollBar.Size = _treeViewFiles.ContentHeight;
+			scrollBar.Position = _treeViewFiles.ScrollOffsetVertical;
+			scrollBar.OtherScrollBarView.Size = _treeViewFiles.GetContentWidth (true);
+			scrollBar.OtherScrollBarView.Position = _treeViewFiles.ScrollOffsetHorizontal;
+			scrollBar.Refresh ();
+		};
+	}
 
-			treeViewFiles.DrawContent += (s, e) => {
-				scrollBar.Size = treeViewFiles.ContentHeight;
-				scrollBar.Position = treeViewFiles.ScrollOffsetVertical;
-				scrollBar.OtherScrollBarView.Size = treeViewFiles.GetContentWidth (true);
-				scrollBar.OtherScrollBarView.Position = treeViewFiles.ScrollOffsetHorizontal;
-				scrollBar.Refresh ();
-			};
-		}
+	void SetupFileTree ()
+	{
+		// setup how to build tree
+		var fs = new FileSystem ();
+		var rootDirs = DriveInfo.GetDrives ().Select (d => fs.DirectoryInfo.New (d.RootDirectory.FullName));
+		_treeViewFiles.TreeBuilder = new FileSystemTreeBuilder ();
+		_treeViewFiles.AddObjects (rootDirs);
 
-		private void SetupFileTree ()
-		{
-			// setup how to build tree
-			var fs = new FileSystem ();
-			var rootDirs = DriveInfo.GetDrives ().Select (d => fs.DirectoryInfo.New (d.RootDirectory.FullName));
-			treeViewFiles.TreeBuilder = new FileSystemTreeBuilder ();
-			treeViewFiles.AddObjects (rootDirs);
+		// Determines how to represent objects as strings on the screen
+		_treeViewFiles.AspectGetter = AspectGetter;
 
-			// Determines how to represent objects as strings on the screen
-			treeViewFiles.AspectGetter = AspectGetter;
+		_iconProvider.IsOpenGetter = _treeViewFiles.IsExpanded;
+	}
 
-			_iconProvider.IsOpenGetter = treeViewFiles.IsExpanded;
-		}
+	string AspectGetter (IFileSystemInfo f) => (_iconProvider.GetIconWithOptionalSpace (f) + f.Name).Trim ();
 
-		private string AspectGetter (IFileSystemInfo f)
-		{
-			return (_iconProvider.GetIconWithOptionalSpace (f) + f.Name).Trim ();
-		}
+	void ShowLines ()
+	{
+		_miShowLines.Checked = !_miShowLines.Checked;
 
-		private void ShowLines ()
-		{
-			miShowLines.Checked = !miShowLines.Checked;
+		_treeViewFiles.Style.ShowBranchLines = (bool)_miShowLines.Checked;
+		_treeViewFiles.SetNeedsDisplay ();
+	}
 
-			treeViewFiles.Style.ShowBranchLines = (bool)miShowLines.Checked;
-			treeViewFiles.SetNeedsDisplay ();
-		}
+	void SetExpandableSymbols (Rune expand, Rune? collapse)
+	{
+		_miPlusMinus.Checked = expand.Value == '+';
+		_miArrowSymbols.Checked = expand.Value == '>';
+		_miNoSymbols.Checked = expand.Value == default;
 
-		private void SetExpandableSymbols (Rune expand, Rune? collapse)
-		{
-			_miPlusMinus.Checked = expand.Value == '+';
-			_miArrowSymbols.Checked = expand.Value == '>';
-			_miNoSymbols.Checked = expand.Value == default;
+		_treeViewFiles.Style.ExpandableSymbol = expand;
+		_treeViewFiles.Style.CollapseableSymbol = collapse;
+		_treeViewFiles.SetNeedsDisplay ();
+	}
 
-			treeViewFiles.Style.ExpandableSymbol = expand;
-			treeViewFiles.Style.CollapseableSymbol = collapse;
-			treeViewFiles.SetNeedsDisplay ();
-		}
-		private void ShowColoredExpandableSymbols ()
-		{
-			_miColoredSymbols.Checked = !_miColoredSymbols.Checked;
+	void ShowColoredExpandableSymbols ()
+	{
+		_miColoredSymbols.Checked = !_miColoredSymbols.Checked;
 
-			treeViewFiles.Style.ColorExpandSymbol = (bool)_miColoredSymbols.Checked;
-			treeViewFiles.SetNeedsDisplay ();
-		}
-		private void InvertExpandableSymbols ()
-		{
-			_miInvertSymbols.Checked = !_miInvertSymbols.Checked;
+		_treeViewFiles.Style.ColorExpandSymbol = (bool)_miColoredSymbols.Checked;
+		_treeViewFiles.SetNeedsDisplay ();
+	}
 
-			treeViewFiles.Style.InvertExpandSymbolColors = (bool)_miInvertSymbols.Checked;
-			treeViewFiles.SetNeedsDisplay ();
-		}
+	void InvertExpandableSymbols ()
+	{
+		_miInvertSymbols.Checked = !_miInvertSymbols.Checked;
 
-		private void SetFullName ()
-		{
-			_miFullPaths.Checked = !_miFullPaths.Checked;
+		_treeViewFiles.Style.InvertExpandSymbolColors = (bool)_miInvertSymbols.Checked;
+		_treeViewFiles.SetNeedsDisplay ();
+	}
 
-			if (_miFullPaths.Checked == true) {
-				treeViewFiles.AspectGetter = (f) => f.FullName;
-			} else {
-				treeViewFiles.AspectGetter = (f) => f.Name;
-			}
-			treeViewFiles.SetNeedsDisplay ();
-		}
+	void SetFullName ()
+	{
+		_miFullPaths.Checked = !_miFullPaths.Checked;
 
-		private void SetLeaveLastRow ()
-		{
-			_miLeaveLastRow.Checked = !_miLeaveLastRow.Checked;
-			treeViewFiles.Style.LeaveLastRow = (bool)_miLeaveLastRow.Checked;
-		}
-		private void SetCursor ()
-		{
-			_miCursor.Checked = !_miCursor.Checked;
-			treeViewFiles.DesiredCursorVisibility = _miCursor.Checked == true ? CursorVisibility.Default : CursorVisibility.Invisible;
-		}
-		private void SetMultiSelect ()
-		{
-			_miMultiSelect.Checked = !_miMultiSelect.Checked;
-			treeViewFiles.MultiSelect = (bool)_miMultiSelect.Checked;
+		if (_miFullPaths.Checked == true) {
+			_treeViewFiles.AspectGetter = (f) => f.FullName;
+		} else {
+			_treeViewFiles.AspectGetter = (f) => f.Name;
 		}
+		_treeViewFiles.SetNeedsDisplay ();
+	}
 
-		private void SetCustomColors ()
-		{
-			var hidden = new ColorScheme {
-				Focus = new Terminal.Gui.Attribute (Color.BrightRed, treeViewFiles.ColorScheme.Focus.Background),
-				Normal = new Terminal.Gui.Attribute (Color.BrightYellow, treeViewFiles.ColorScheme.Normal.Background),
-			};
+	void SetLeaveLastRow ()
+	{
+		_miLeaveLastRow.Checked = !_miLeaveLastRow.Checked;
+		_treeViewFiles.Style.LeaveLastRow = (bool)_miLeaveLastRow.Checked;
+	}
 
-			_miCustomColors.Checked = !_miCustomColors.Checked;
+	void SetCursor ()
+	{
+		_miCursor.Checked = !_miCursor.Checked;
+		_treeViewFiles.DesiredCursorVisibility = _miCursor.Checked == true ? CursorVisibility.Default : CursorVisibility.Invisible;
+	}
 
-			if (_miCustomColors.Checked == true) {
-				treeViewFiles.ColorGetter = (m) => {
-					if (m is IDirectoryInfo && m.Attributes.HasFlag (FileAttributes.Hidden)) return hidden;
-					if (m is IFileInfo && m.Attributes.HasFlag (FileAttributes.Hidden)) return hidden;
-					return null;
-				};
-			} else {
-				treeViewFiles.ColorGetter = null;
-			}
-			treeViewFiles.SetNeedsDisplay ();
-		}
+	void SetMultiSelect ()
+	{
+		_miMultiSelect.Checked = !_miMultiSelect.Checked;
+		_treeViewFiles.MultiSelect = (bool)_miMultiSelect.Checked;
+	}
 
-		private void SetCheckHighlightModelTextOnly ()
-		{
-			treeViewFiles.Style.HighlightModelTextOnly = !treeViewFiles.Style.HighlightModelTextOnly;
-			_miHighlightModelTextOnly.Checked = treeViewFiles.Style.HighlightModelTextOnly;
-			treeViewFiles.SetNeedsDisplay ();
-		}
+	void SetCustomColors ()
+	{
+		var hidden = new ColorScheme {
+			Focus = new Attribute (Color.BrightRed, _treeViewFiles.ColorScheme.Focus.Background),
+			Normal = new Attribute (Color.BrightYellow, _treeViewFiles.ColorScheme.Normal.Background)
+		};
 
-		private void Quit ()
-		{
-			Application.RequestStop ();
+		_miCustomColors.Checked = !_miCustomColors.Checked;
+
+		if (_miCustomColors.Checked == true) {
+			_treeViewFiles.ColorGetter = (m) => {
+				if (m is IDirectoryInfo && m.Attributes.HasFlag (FileAttributes.Hidden)) {
+					return hidden;
+				}
+				if (m is IFileInfo && m.Attributes.HasFlag (FileAttributes.Hidden)) {
+					return hidden;
+				}
+				return null;
+			};
+		} else {
+			_treeViewFiles.ColorGetter = null;
 		}
+		_treeViewFiles.SetNeedsDisplay ();
 	}
-}
+
+	void SetCheckHighlightModelTextOnly ()
+	{
+		_treeViewFiles.Style.HighlightModelTextOnly = !_treeViewFiles.Style.HighlightModelTextOnly;
+		_miHighlightModelTextOnly.Checked = _treeViewFiles.Style.HighlightModelTextOnly;
+		_treeViewFiles.SetNeedsDisplay ();
+	}
+
+	void Quit () => Application.RequestStop ();
+}

+ 337 - 345
UnitTests/View/Layout/AbsoluteLayoutTests.cs

@@ -1,350 +1,342 @@
-using System.Text;
-using System;
-using System.Collections.Generic;
-using System.Xml.Linq;
-using Xunit;
+using Xunit;
 using Xunit.Abstractions;
 //using GraphViewTests = Terminal.Gui.Views.GraphViewTests;
 
 // Alias Console to MockConsole so we don't accidentally use Console
-using Console = Terminal.Gui.FakeConsole;
-
-namespace Terminal.Gui.ViewTests {
-	public class AbsoluteLayoutTests {
-		readonly ITestOutputHelper output;
-
-		public AbsoluteLayoutTests (ITestOutputHelper output)
-		{
-			this.output = output;
-		}
-
-		[Fact, TestRespondersDisposed]
-		public void AbsoluteLayout_Constructor ()
-		{
-			var frame = new Rect (1, 2, 3, 4);
-			var v = new View (frame);
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute);
-			Assert.Equal (frame, v.Frame);
-			Assert.Equal (new Rect(0, 0, frame.Width, frame.Height), v.Bounds); // With Absolute Bounds *is* deterministic before Layout
-			Assert.Null (v.X);
-			Assert.Null (v.Y);
-			Assert.Null (v.Height);
-			Assert.Null (v.Width);
-			v.Dispose ();
-
-			v = new View (frame, "v");
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute);
-			Assert.Equal (frame, v.Frame);
-			Assert.Equal (new Rect (0, 0, frame.Width, frame.Height), v.Bounds); // With Absolute Bounds *is* deterministic before Layout
-			Assert.Null (v.X);
-			Assert.Null (v.Y);
-			Assert.Null (v.Height);
-			Assert.Null (v.Width);
-			v.Dispose ();
-
-			v = new View (frame.X, frame.Y, "v");
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute);
-			// BUGBUG: v2 - I think the default size should be 0,0
-			Assert.Equal (new Rect(frame.X, frame.Y, 1, 1), v.Frame);
-			Assert.Equal (new Rect (0, 0, 1, 1), v.Bounds); // With Absolute Bounds *is* deterministic before Layout
-			Assert.Null (v.X);
-			Assert.Null (v.Y);
-			Assert.Null (v.Height);
-			Assert.Null (v.Width);
-			v.Dispose ();
-			
-		}
-
-		[Fact, TestRespondersDisposed]
-		public void AbsoluteLayout_Change_Frame ()
-		{
-			var frame = new Rect (1, 2, 3, 4);
-			var newFrame = new Rect (1, 2, 30, 40);
-
-			var v = new View (frame);
-			v.Frame = newFrame;
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute);
-			Assert.Equal (newFrame, v.Frame);
-			Assert.Equal (new Rect (0, 0, newFrame.Width, newFrame.Height), v.Bounds); // With Absolute Bounds *is* deterministic before Layout
-			Assert.Null (v.X);
-			Assert.Null (v.Y);
-			Assert.Null (v.Height);
-			Assert.Null (v.Width);
-			v.Dispose ();
-
-			v = new View (frame.X, frame.Y, "v");
-			v.Frame = newFrame;
-			Assert.Equal (newFrame, v.Frame);
-			Assert.Equal (new Rect (0, 0, newFrame.Width, newFrame.Height), v.Bounds); // With Absolute Bounds *is* deterministic before Layout
-			Assert.Null (v.X);
-			Assert.Null (v.Y);
-			Assert.Null (v.Height);
-			Assert.Null (v.Width);
-			v.Dispose ();
-
-			newFrame = new Rect (10, 20, 30, 40);
-			v = new View (frame);
-			v.Frame = newFrame;
-			Assert.Equal (newFrame, v.Frame);
-			Assert.Equal (new Rect (0, 0, newFrame.Width, newFrame.Height), v.Bounds); // With Absolute Bounds *is* deterministic before Layout
-			Assert.Null (v.X);
-			Assert.Null (v.Y);
-			Assert.Null (v.Height);
-			Assert.Null (v.Width);
-			v.Dispose ();
-
-			v = new View (frame.X, frame.Y, "v");
-			v.Frame = newFrame;
-			Assert.Equal (newFrame, v.Frame);
-			Assert.Equal (new Rect (0, 0, newFrame.Width, newFrame.Height), v.Bounds); // With Absolute Bounds *is* deterministic before Layout
-			Assert.Null (v.X);
-			Assert.Null (v.Y);
-			Assert.Null (v.Height);
-			Assert.Null (v.Width);
-			v.Dispose ();
-		}
-
-		[Fact, TestRespondersDisposed]
-		public void AbsoluteLayout_Change_Height_or_Width_Absolute ()
-		{
-			var frame = new Rect (1, 2, 3, 4);
-			var newFrame = new Rect (1, 2, 30, 40);
-
-			var v = new View (frame);
-			v.Height = newFrame.Height;
-			v.Width = newFrame.Width;
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute);
-			Assert.Equal (newFrame, v.Frame);
-			Assert.Equal (new Rect (0, 0, newFrame.Width, newFrame.Height), v.Bounds); // With Absolute Bounds *is* deterministic before Layout
-			Assert.Null (v.X);
-			Assert.Null (v.Y);
-			Assert.Equal ($"Absolute({newFrame.Height})", v.Height.ToString());
-			Assert.Equal ($"Absolute({newFrame.Width})", v.Width.ToString ());
-			v.Dispose ();
-		}
-
-		[Fact, TestRespondersDisposed]
-		public void AbsoluteLayout_Change_Height_or_Width_NotAbsolute ()
-		{
-			var v = new View (Rect.Empty);
-			v.Height = Dim.Fill ();
-			v.Width = Dim.Fill ();
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute);  // BUGBUG: v2 - Changing the Height or Width should change the LayoutStyle
-			v.Dispose ();
-		}
-
-		[Fact, TestRespondersDisposed]
-		public void AbsoluteLayout_Change_Height_or_Width_Null ()
-		{
-			var v = new View (Rect.Empty);
-			v.Height = null;
-			v.Width = null;
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute);
-			v.Dispose ();
-		}
-
-		[Fact, TestRespondersDisposed]
-		public void AbsoluteLayout_Change_X_or_Y_Absolute ()
-		{
-			var frame = new Rect (1, 2, 3, 4);
-			var newFrame = new Rect (10, 20, 3, 4);
-
-			var v = new View (frame);
-			v.X = newFrame.X;
-			v.Y = newFrame.Y;
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute);
-			Assert.Equal (newFrame, v.Frame);
-			Assert.Equal (new Rect (0, 0, newFrame.Width, newFrame.Height), v.Bounds); // With Absolute Bounds *is* deterministic before Layout
-			Assert.Equal ($"Absolute({newFrame.X})", v.X.ToString ());
-			Assert.Equal ($"Absolute({newFrame.Y})", v.Y.ToString ());
-			Assert.Null (v.Height);
-			Assert.Null (v.Width);
-			v.Dispose ();
-		}
-
-		[Fact, TestRespondersDisposed]
-		public void AbsoluteLayout_Change_X_or_Y_NotAbsolute ()
-		{
-			var v = new View (Rect.Empty);
-			v.X = Pos.Center ();
-			v.Y = Pos.Center ();
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // BUGBUG: v2 - Changing the Height or Width should change the LayoutStyle
-			v.Dispose ();
-		}
-
-		[Fact, TestRespondersDisposed]
-		public void AbsoluteLayout_Change_X_or_Y_Null ()
-		{
-			var v = new View (Rect.Empty);
-			v.X = null;
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute);
-			v.Dispose ();
-
-			v = new View (Rect.Empty);
-			v.X = Pos.Center ();
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // BUGBUG: v2 - Changing the Height or Width should change the LayoutStyle
-
-			v.X = null;
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute);
-			v.Dispose ();
-
-			v = new View (Rect.Empty);
-			v.Y = null;
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute);
-			v.Dispose ();
-
-			v = new View (Rect.Empty);
-			v.Y = Pos.Center ();
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // BUGBUG: v2 - Changing the Height or Width should change the LayoutStyle
-
-			v.Y = null;
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute);
-			v.Dispose ();
-		}
-
-		[Fact, TestRespondersDisposed]
-		public void AbsoluteLayout_Change_X_Y_Height_Width_Absolute ()
-		{
-			var v = new View (Rect.Empty);
-			v.X = 1;
-			v.Y = 2;
-			v.Height = 3;
-			v.Width = 4;
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute);
-			v.Dispose ();
-
-			v = new View (Rect.Empty);
-			v.X = Pos.Center ();
-			v.Y = Pos.Center ();
-			v.Width = Dim.Fill ();
-			v.Height = Dim.Fill ();
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // BUGBUG: v2 - Changing the Height or Width should change the LayoutStyle
-
-			// BUGBUG: v2 - If all of X, Y, Width, and Height are null or Absolute(n), isn't that the same as LayoutStyle.Absoulte?
-			v.X = null;
-			v.Y = null;
-			v.Height = null;
-			v.Width = null;
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // We never automatically change to Absolute from Computed??
-			v.Dispose ();
-
-			v = new View (Rect.Empty);
-			v.X = Pos.Center ();
-			v.Y = Pos.Center ();
-			v.Width = Dim.Fill ();
-			v.Height = Dim.Fill ();
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // BUGBUG: v2 - Changing the Height or Width should change the LayoutStyle
-
-			// BUGBUG: v2 - If all of X, Y, Width, and Height are null or Absolute(n), isn't that the same as LayoutStyle.Absoulte?
-			v.X = 1;
-			v.Y = null;
-			v.Height = null;
-			v.Width = null;
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // We never automatically change to Absolute from Computed??
-			v.Dispose ();
-
-			v = new View (Rect.Empty);
-			v.X = Pos.Center ();
-			v.Y = Pos.Center ();
-			v.Width = Dim.Fill ();
-			v.Height = Dim.Fill ();
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // BUGBUG: v2 - Changing the Height or Width should change the LayoutStyle
-
-			// BUGBUG: v2 - If all of X, Y, Width, and Height are null or Absolute(n), isn't that the same as LayoutStyle.Absoulte?
-			v.X = null;
-			v.Y = 2;
-			v.Height = null;
-			v.Width = null;
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // We never automatically change to Absolute from Computed??
-			v.Dispose ();
-
-			v = new View (Rect.Empty);
-			v.X = Pos.Center ();
-			v.Y = Pos.Center ();
-			v.Width = Dim.Fill ();
-			v.Height = Dim.Fill ();
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // BUGBUG: v2 - Changing the Height or Width should change the LayoutStyle
-
-			// BUGBUG: v2 - If all of X, Y, Width, and Height are null or Absolute(n), isn't that the same as LayoutStyle.Absoulte?
-			v.X = null;
-			v.Y = null;
-			v.Height = 3;
-			v.Width = null;
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // We never automatically change to Absolute from Computed??
-			v.Dispose ();
-
-			v = new View (Rect.Empty);
-			v.X = Pos.Center ();
-			v.Y = Pos.Center ();
-			v.Width = Dim.Fill ();
-			v.Height = Dim.Fill ();
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // BUGBUG: v2 - Changing the Height or Width should change the LayoutStyle
-
-			// BUGBUG: v2 - If all of X, Y, Width, and Height are null or Absolute(n), isn't that the same as LayoutStyle.Absoulte?
-			v.X = null;
-			v.Y = null;
-			v.Height = null;
-			v.Width = 4;
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // We never automatically change to Absolute from Computed??
-			v.Dispose ();
-		}
-
-		[Fact, TestRespondersDisposed]
-		public void AbsoluteLayout_Change_X_Y_Height_Width_Null ()
-		{
-			var v = new View (Rect.Empty);
-			v.X = null;
-			v.Y = null;
-			v.Height = null;
-			v.Width = null;
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute);
-
-			v.Dispose ();
-			v = new View (Rect.Empty);
-			v.X = Pos.Center ();
-			v.Y = Pos.Center ();
-			v.Width = Dim.Fill ();
-			v.Height = Dim.Fill ();
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // BUGBUG: v2 - Changing the Height or Width should change the LayoutStyle
-
-			// BUGBUG: v2 - If all of X, Y, Width, and Height are null or Absolute(n), isn't that the same as LayoutStyle.Absoulte?
-			v.X = null;
-			v.Y = null;
-			v.Height = null;
-			v.Width = null;
-			Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // We never automatically change to Absolute from Computed??
-			v.Dispose ();
-		}
-
-		[Fact, TestRespondersDisposed]
-		public void AbsoluteLayout_Layout ()
-		{
-			var superRect = new Rect (0, 0, 100, 100);
-			var super = new View (superRect, "super");
-			Assert.True (super.LayoutStyle == LayoutStyle.Absolute);
-			var v1 = new View () {
-				X = 0,
-				Y = 0,
-				Width = 10,
-				Height = 10
-			};
-			// BUGBUG: v2 - This should be LayoutStyle.Absolute
-			Assert.True (v1.LayoutStyle == LayoutStyle.Computed);
-
-			var v2 = new View () {
-				X = 10,
-				Y = 10,
-				Width = 10,
-				Height = 10
-			};
-			// BUGBUG: v2 - This should be LayoutStyle.Absolute
-			Assert.True (v1.LayoutStyle == LayoutStyle.Computed);
-
-			super.Add (v1, v2);
-			super.LayoutSubviews ();
-			Assert.Equal (new Rect (0, 0, 10, 10), v1.Frame);
-			Assert.Equal (new Rect (10, 10, 10, 10), v2.Frame);
-			super.Dispose ();
-		}
+
+namespace Terminal.Gui.ViewTests;
+
+public class AbsoluteLayoutTests {
+	readonly ITestOutputHelper _output;
+
+	public AbsoluteLayoutTests (ITestOutputHelper output) => this._output = output;
+
+	[Fact] [TestRespondersDisposed]
+	public void AbsoluteLayout_Constructor ()
+	{
+		var frame = new Rect (1, 2, 3, 4);
+		var v = new View (frame);
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute);
+		Assert.Equal (frame, v.Frame);
+		Assert.Equal (new Rect (0, 0, frame.Width, frame.Height), v.Bounds); // With Absolute Bounds *is* deterministic before Layout
+		Assert.Null (v.X);
+		Assert.Null (v.Y);
+		Assert.Null (v.Height);
+		Assert.Null (v.Width);
+		v.Dispose ();
+
+		v = new View (frame, "v");
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute);
+		Assert.Equal (frame, v.Frame);
+		Assert.Equal (new Rect (0, 0, frame.Width, frame.Height), v.Bounds); // With Absolute Bounds *is* deterministic before Layout
+		Assert.Null (v.X);
+		Assert.Null (v.Y);
+		Assert.Null (v.Height);
+		Assert.Null (v.Width);
+		v.Dispose ();
+
+		v = new View (frame.X, frame.Y, "v");
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute);
+		// BUGBUG: v2 - I think the default size should be 0,0
+		Assert.Equal (new Rect (frame.X, frame.Y, 1, 1), v.Frame);
+		Assert.Equal (new Rect (0, 0, 1, 1), v.Bounds); // With Absolute Bounds *is* deterministic before Layout
+		Assert.Null (v.X);
+		Assert.Null (v.Y);
+		Assert.Null (v.Height);
+		Assert.Null (v.Width);
+		v.Dispose ();
+
+	}
+
+	[Fact] [TestRespondersDisposed]
+	public void AbsoluteLayout_Change_Frame ()
+	{
+		var frame = new Rect (1, 2, 3, 4);
+		var newFrame = new Rect (1, 2, 30, 40);
+
+		var v = new View (frame);
+		v.Frame = newFrame;
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute);
+		Assert.Equal (newFrame, v.Frame);
+		Assert.Equal (new Rect (0, 0, newFrame.Width, newFrame.Height), v.Bounds); // With Absolute Bounds *is* deterministic before Layout
+		Assert.Null (v.X);
+		Assert.Null (v.Y);
+		Assert.Null (v.Height);
+		Assert.Null (v.Width);
+		v.Dispose ();
+
+		v = new View (frame.X, frame.Y, "v");
+		v.Frame = newFrame;
+		Assert.Equal (newFrame, v.Frame);
+		Assert.Equal (new Rect (0, 0, newFrame.Width, newFrame.Height), v.Bounds); // With Absolute Bounds *is* deterministic before Layout
+		Assert.Null (v.X);
+		Assert.Null (v.Y);
+		Assert.Null (v.Height);
+		Assert.Null (v.Width);
+		v.Dispose ();
+
+		newFrame = new Rect (10, 20, 30, 40);
+		v = new View (frame);
+		v.Frame = newFrame;
+		Assert.Equal (newFrame, v.Frame);
+		Assert.Equal (new Rect (0, 0, newFrame.Width, newFrame.Height), v.Bounds); // With Absolute Bounds *is* deterministic before Layout
+		Assert.Null (v.X);
+		Assert.Null (v.Y);
+		Assert.Null (v.Height);
+		Assert.Null (v.Width);
+		v.Dispose ();
+
+		v = new View (frame.X, frame.Y, "v");
+		v.Frame = newFrame;
+		Assert.Equal (newFrame, v.Frame);
+		Assert.Equal (new Rect (0, 0, newFrame.Width, newFrame.Height), v.Bounds); // With Absolute Bounds *is* deterministic before Layout
+		Assert.Null (v.X);
+		Assert.Null (v.Y);
+		Assert.Null (v.Height);
+		Assert.Null (v.Width);
+		v.Dispose ();
+	}
+
+	[Fact] [TestRespondersDisposed]
+	public void AbsoluteLayout_Change_Height_or_Width_Absolute ()
+	{
+		var frame = new Rect (1, 2, 3, 4);
+		var newFrame = new Rect (1, 2, 30, 40);
+
+		var v = new View (frame);
+		v.Height = newFrame.Height;
+		v.Width = newFrame.Width;
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute);
+		Assert.Equal (newFrame, v.Frame);
+		Assert.Equal (new Rect (0, 0, newFrame.Width, newFrame.Height), v.Bounds); // With Absolute Bounds *is* deterministic before Layout
+		Assert.Null (v.X);
+		Assert.Null (v.Y);
+		Assert.Equal ($"Absolute({newFrame.Height})", v.Height.ToString ());
+		Assert.Equal ($"Absolute({newFrame.Width})", v.Width.ToString ());
+		v.Dispose ();
+	}
+
+	[Fact] [TestRespondersDisposed]
+	public void AbsoluteLayout_Change_Height_or_Width_NotAbsolute ()
+	{
+		var v = new View (Rect.Empty);
+		v.Height = Dim.Fill ();
+		v.Width = Dim.Fill ();
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // BUGBUG: v2 - Changing the Height or Width should change the LayoutStyle
+		v.Dispose ();
+	}
+
+	[Fact] [TestRespondersDisposed]
+	public void AbsoluteLayout_Change_Height_or_Width_Null ()
+	{
+		var v = new View (Rect.Empty);
+		v.Height = null;
+		v.Width = null;
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute);
+		v.Dispose ();
+	}
+
+	[Fact] [TestRespondersDisposed]
+	public void AbsoluteLayout_Change_X_or_Y_Absolute ()
+	{
+		var frame = new Rect (1, 2, 3, 4);
+		var newFrame = new Rect (10, 20, 3, 4);
+
+		var v = new View (frame);
+		v.X = newFrame.X;
+		v.Y = newFrame.Y;
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute);
+		Assert.Equal (newFrame, v.Frame);
+		Assert.Equal (new Rect (0, 0, newFrame.Width, newFrame.Height), v.Bounds); // With Absolute Bounds *is* deterministic before Layout
+		Assert.Equal ($"Absolute({newFrame.X})", v.X.ToString ());
+		Assert.Equal ($"Absolute({newFrame.Y})", v.Y.ToString ());
+		Assert.Null (v.Height);
+		Assert.Null (v.Width);
+		v.Dispose ();
+	}
+
+	[Fact] [TestRespondersDisposed]
+	public void AbsoluteLayout_Change_X_or_Y_NotAbsolute ()
+	{
+		var v = new View (Rect.Empty);
+		v.X = Pos.Center ();
+		v.Y = Pos.Center ();
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // BUGBUG: v2 - Changing the Height or Width should change the LayoutStyle
+		v.Dispose ();
+	}
+
+	[Fact] [TestRespondersDisposed]
+	public void AbsoluteLayout_Change_X_or_Y_Null ()
+	{
+		var v = new View (Rect.Empty);
+		v.X = null;
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute);
+		v.Dispose ();
+
+		v = new View (Rect.Empty);
+		v.X = Pos.Center ();
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // BUGBUG: v2 - Changing the Height or Width should change the LayoutStyle
+
+		v.X = null;
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute);
+		v.Dispose ();
+
+		v = new View (Rect.Empty);
+		v.Y = null;
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute);
+		v.Dispose ();
+
+		v = new View (Rect.Empty);
+		v.Y = Pos.Center ();
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // BUGBUG: v2 - Changing the Height or Width should change the LayoutStyle
+
+		v.Y = null;
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute);
+		v.Dispose ();
+	}
+
+	[Fact] [TestRespondersDisposed]
+	public void AbsoluteLayout_Change_X_Y_Height_Width_Absolute ()
+	{
+		var v = new View (Rect.Empty);
+		v.X = 1;
+		v.Y = 2;
+		v.Height = 3;
+		v.Width = 4;
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute);
+		v.Dispose ();
+
+		v = new View (Rect.Empty);
+		v.X = Pos.Center ();
+		v.Y = Pos.Center ();
+		v.Width = Dim.Fill ();
+		v.Height = Dim.Fill ();
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // BUGBUG: v2 - Changing the Height or Width should change the LayoutStyle
+
+		// BUGBUG: v2 - If all of X, Y, Width, and Height are null or Absolute(n), isn't that the same as LayoutStyle.Absoulte?
+		v.X = null;
+		v.Y = null;
+		v.Height = null;
+		v.Width = null;
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // We never automatically change to Absolute from Computed??
+		v.Dispose ();
+
+		v = new View (Rect.Empty);
+		v.X = Pos.Center ();
+		v.Y = Pos.Center ();
+		v.Width = Dim.Fill ();
+		v.Height = Dim.Fill ();
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // BUGBUG: v2 - Changing the Height or Width should change the LayoutStyle
+
+		// BUGBUG: v2 - If all of X, Y, Width, and Height are null or Absolute(n), isn't that the same as LayoutStyle.Absoulte?
+		v.X = 1;
+		v.Y = null;
+		v.Height = null;
+		v.Width = null;
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // We never automatically change to Absolute from Computed??
+		v.Dispose ();
+
+		v = new View (Rect.Empty);
+		v.X = Pos.Center ();
+		v.Y = Pos.Center ();
+		v.Width = Dim.Fill ();
+		v.Height = Dim.Fill ();
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // BUGBUG: v2 - Changing the Height or Width should change the LayoutStyle
+
+		// BUGBUG: v2 - If all of X, Y, Width, and Height are null or Absolute(n), isn't that the same as LayoutStyle.Absoulte?
+		v.X = null;
+		v.Y = 2;
+		v.Height = null;
+		v.Width = null;
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // We never automatically change to Absolute from Computed??
+		v.Dispose ();
+
+		v = new View (Rect.Empty);
+		v.X = Pos.Center ();
+		v.Y = Pos.Center ();
+		v.Width = Dim.Fill ();
+		v.Height = Dim.Fill ();
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // BUGBUG: v2 - Changing the Height or Width should change the LayoutStyle
+
+		// BUGBUG: v2 - If all of X, Y, Width, and Height are null or Absolute(n), isn't that the same as LayoutStyle.Absoulte?
+		v.X = null;
+		v.Y = null;
+		v.Height = 3;
+		v.Width = null;
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // We never automatically change to Absolute from Computed??
+		v.Dispose ();
+
+		v = new View (Rect.Empty);
+		v.X = Pos.Center ();
+		v.Y = Pos.Center ();
+		v.Width = Dim.Fill ();
+		v.Height = Dim.Fill ();
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // BUGBUG: v2 - Changing the Height or Width should change the LayoutStyle
+
+		// BUGBUG: v2 - If all of X, Y, Width, and Height are null or Absolute(n), isn't that the same as LayoutStyle.Absoulte?
+		v.X = null;
+		v.Y = null;
+		v.Height = null;
+		v.Width = 4;
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // We never automatically change to Absolute from Computed??
+		v.Dispose ();
+	}
+
+	[Fact] [TestRespondersDisposed]
+	public void AbsoluteLayout_Change_X_Y_Height_Width_Null ()
+	{
+		var v = new View (Rect.Empty);
+		v.X = null;
+		v.Y = null;
+		v.Height = null;
+		v.Width = null;
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute);
+
+		v.Dispose ();
+		v = new View (Rect.Empty);
+		v.X = Pos.Center ();
+		v.Y = Pos.Center ();
+		v.Width = Dim.Fill ();
+		v.Height = Dim.Fill ();
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // BUGBUG: v2 - Changing the Height or Width should change the LayoutStyle
+
+		// BUGBUG: v2 - If all of X, Y, Width, and Height are null or Absolute(n), isn't that the same as LayoutStyle.Absoulte?
+		v.X = null;
+		v.Y = null;
+		v.Height = null;
+		v.Width = null;
+		Assert.True (v.LayoutStyle == LayoutStyle.Absolute); // We never automatically change to Absolute from Computed??
+		v.Dispose ();
+	}
+
+	[Fact] [TestRespondersDisposed]
+	public void AbsoluteLayout_Layout ()
+	{
+		var superRect = new Rect (0, 0, 100, 100);
+		var super = new View (superRect, "super");
+		Assert.True (super.LayoutStyle == LayoutStyle.Absolute);
+		var v1 = new View () {
+			X = 0,
+			Y = 0,
+			Width = 10,
+			Height = 10
+		};
+		// BUGBUG: v2 - This should be LayoutStyle.Absolute
+		Assert.True (v1.LayoutStyle == LayoutStyle.Computed);
+
+		var v2 = new View () {
+			X = 10,
+			Y = 10,
+			Width = 10,
+			Height = 10
+		};
+		// BUGBUG: v2 - This should be LayoutStyle.Absolute
+		Assert.True (v1.LayoutStyle == LayoutStyle.Computed);
+
+		super.Add (v1, v2);
+		super.LayoutSubviews ();
+		Assert.Equal (new Rect (0, 0, 10, 10), v1.Frame);
+		Assert.Equal (new Rect (10, 10, 10, 10), v2.Frame);
+		super.Dispose ();
 	}
-}
+}

+ 7 - 0
UnitTests/Views/ComboBoxTests.cs

@@ -19,6 +19,7 @@ namespace Terminal.Gui.ViewsTests {
 			var cb = new ComboBox ();
 			cb.BeginInit ();
 			cb.EndInit ();
+			cb.LayoutSubviews ();
 			Assert.Equal (string.Empty, cb.Text);
 			Assert.Null (cb.Source);
 			Assert.False (cb.AutoSize);
@@ -28,6 +29,7 @@ namespace Terminal.Gui.ViewsTests {
 			cb = new ComboBox ("Test");
 			cb.BeginInit ();
 			cb.EndInit ();
+			cb.LayoutSubviews ();
 			Assert.Equal ("Test", cb.Text);
 			Assert.Null (cb.Source);
 			Assert.False (cb.AutoSize);
@@ -37,6 +39,7 @@ namespace Terminal.Gui.ViewsTests {
 			cb = new ComboBox (new Rect (1, 2, 10, 20), new List<string> () { "One", "Two", "Three" });
 			cb.BeginInit ();
 			cb.EndInit ();
+			cb.LayoutSubviews ();
 			Assert.Equal (string.Empty, cb.Text);
 			Assert.NotNull (cb.Source);
 			Assert.False (cb.AutoSize);
@@ -46,6 +49,7 @@ namespace Terminal.Gui.ViewsTests {
 			cb = new ComboBox (new List<string> () { "One", "Two", "Three" });
 			cb.BeginInit ();
 			cb.EndInit ();
+			cb.LayoutSubviews ();
 			Assert.Equal (string.Empty, cb.Text);
 			Assert.NotNull (cb.Source);
 			Assert.False (cb.AutoSize);
@@ -60,6 +64,9 @@ namespace Terminal.Gui.ViewsTests {
 			var cb = new ComboBox (new List<string> () { "One", "Two", "Three" }) {
 				SelectedItem = 1
 			};
+			cb.BeginInit ();
+			cb.EndInit ();
+			cb.LayoutSubviews ();
 			Assert.Equal ("Two", cb.Text);
 			Assert.NotNull (cb.Source);
 			Assert.False (cb.AutoSize);