Przeglądaj źródła

Merge branch 'view-load-event' into Initialized-event

BDisp 5 lat temu
rodzic
commit
e6806a56e0
2 zmienionych plików z 225 dodań i 2 usunięć
  1. 50 2
      Terminal.Gui/Core/View.cs
  2. 175 0
      UnitTests/ViewTests.cs

+ 50 - 2
Terminal.Gui/Core/View.cs

@@ -13,6 +13,7 @@
 using System;
 using System.Collections;
 using System.Collections.Generic;
+using System.ComponentModel;
 using System.Diagnostics;
 using System.Linq;
 using NStack;
@@ -110,7 +111,7 @@ namespace Terminal.Gui {
 	///    frames for the vies that use <see cref="LayoutStyle.Computed"/>.
 	/// </para>
 	/// </remarks>
-	public partial class View : Responder, IEnumerable {
+	public partial class View : Responder, IEnumerable, ISupportInitializeNotification {
 
 		internal enum Direction {
 			Forward,
@@ -665,7 +666,9 @@ namespace Terminal.Gui {
 				CanFocus = true;
 				view.tabIndex = tabIndexes.IndexOf (view);
 			}
-
+			if (IsInitialized) {
+				view.BeginInit ();
+			}
 			SetNeedsLayout ();
 			SetNeedsDisplay ();
 		}
@@ -1653,6 +1656,13 @@ namespace Terminal.Gui {
 		/// </remarks>
 		public Action<LayoutEventArgs> LayoutComplete;
 
+		/// <summary>
+		/// Event called only once when the <see cref="View"/> is being initialized for the first time.
+		/// Allows configurations and assignments to be performed before the <see cref="View"/> being shown.
+		/// This derived from <see cref="ISupportInitializeNotification"/> to allow notify all the views that are being initialized.
+		/// </summary>
+		public event EventHandler Initialized;
+
 		/// <summary>
 		/// Raises the <see cref="LayoutComplete"/> event. Called from  <see cref="LayoutSubviews"/> before all sub-views have been laid out.
 		/// </summary>
@@ -1757,6 +1767,12 @@ namespace Terminal.Gui {
 			}
 		}
 
+		/// <summary>
+		/// Get or sets if  the <see cref="View"/> was already initialized.
+		/// This derived from <see cref="ISupportInitializeNotification"/> to allow notify all the views that are being initialized.
+		/// </summary>
+		public bool IsInitialized { get; set; }
+
 		/// <summary>
 		/// Pretty prints the View
 		/// </summary>
@@ -1848,5 +1864,37 @@ namespace Terminal.Gui {
 			}
 			base.Dispose (disposing);
 		}
+
+		/// <summary>
+		/// This derived from <see cref="ISupportInitializeNotification"/> to allow notify all the views that are beginning initialized.
+		/// </summary>
+		public void BeginInit ()
+		{
+			if (!IsInitialized) {
+				Initialized?.Invoke (this, new EventArgs ());
+			}
+			if (subviews?.Count > 0) {
+				foreach (var view in subviews) {
+					if (!view.IsInitialized) {
+						view.BeginInit ();
+					}
+				}
+			}
+		}
+
+		/// <summary>
+		/// This derived from <see cref="ISupportInitializeNotification"/> to allow notify all the views that are ending initialized.
+		/// </summary>
+		public void EndInit ()
+		{
+			IsInitialized = true;
+			if (subviews?.Count > 0) {
+				foreach (var view in subviews) {
+					if (!view.IsInitialized) {
+						view.EndInit ();
+					}
+				}
+			}
+		}
 	}
 }

+ 175 - 0
UnitTests/ViewTests.cs

@@ -543,5 +543,180 @@ namespace Terminal.Gui {
 			Assert.Equal (2, v3.TabIndex);
 			Assert.True (v3.TabStop);
 		}
+
+		[Fact]
+		public void Initialized_Event_Comparing_With_Added_Event ()
+		{
+			Application.Init (new FakeDriver (), new NetMainLoop (() => FakeConsole.ReadKey (true)));
+
+			var t = new Toplevel () { Id = "0", };
+
+			var w = new Window () {Id = "t", Width = Dim.Fill (), Height = Dim.Fill () };
+			var v1 = new View () { Id = "v1", Width = Dim.Fill (), Height = Dim.Fill () };
+			var v2 = new View () { Id = "v2", Width = Dim.Fill (), Height = Dim.Fill () };
+			var sv1 = new View () { Id = "sv1", Width = Dim.Fill (), Height = Dim.Fill () };
+
+			int tc = 0, wc = 0, v1c = 0, v2c = 0, sv1c = 0;
+
+			w.Added += (e) => {
+				Assert.Equal (e.Frame.Width, w.Frame.Width);
+				Assert.Equal (e.Frame.Height, w.Frame.Height);
+			};
+			v1.Added += (e) => {
+				Assert.Equal (e.Frame.Width, v1.Frame.Width);
+				Assert.Equal (e.Frame.Height, v1.Frame.Height);
+			};
+			v2.Added += (e) => {
+				Assert.Equal (e.Frame.Width, v2.Frame.Width);
+				Assert.Equal (e.Frame.Height, v2.Frame.Height);
+			};
+			sv1.Added += (e) => {
+				Assert.Equal (e.Frame.Width, sv1.Frame.Width);
+				Assert.Equal (e.Frame.Height, sv1.Frame.Height);
+			};
+
+			t.Initialized += (s, e) => {
+				tc++;
+				Assert.Equal (1, tc);
+				Assert.Equal (0, wc);
+				Assert.Equal (0, v1c);
+				Assert.Equal (0, v2c);
+				Assert.Equal (0, sv1c);
+
+				Assert.True (t.CanFocus);
+				Assert.True (w.CanFocus);
+				Assert.False (v1.CanFocus);
+				Assert.False (v2.CanFocus);
+				Assert.False (sv1.CanFocus);
+
+				Application.Refresh ();
+			};
+			w.Initialized += (s, e) => {
+				wc++;
+				Assert.Equal (t.Frame.Width, w.Frame.Width);
+				Assert.Equal (t.Frame.Height, w.Frame.Height);
+			};
+			v1.Initialized += (s, e) => {
+				v1c++;
+				Assert.Equal (t.Frame.Width, v1.Frame.Width);
+				Assert.Equal (t.Frame.Height, v1.Frame.Height);
+			};
+			v2.Initialized += (s, e) => {
+				v2c++;
+				Assert.Equal (t.Frame.Width, v2.Frame.Width);
+				Assert.Equal (t.Frame.Height, v2.Frame.Height);
+			};
+			sv1.Initialized += (s, e) => {
+				sv1c++;
+				Assert.Equal (t.Frame.Width, sv1.Frame.Width);
+				Assert.Equal (t.Frame.Height, sv1.Frame.Height);
+				Assert.False (sv1.CanFocus);
+				sv1.CanFocus = true;
+				Assert.True (sv1.CanFocus);
+			};
+
+			v1.Add (sv1);
+			w.Add (v1, v2);
+			t.Add (w);
+
+			Application.Iteration = () => {
+				Application.Refresh ();
+				t.Running = false;
+			};
+
+			Application.Run (t, true);
+			Application.Shutdown (true);
+
+			Assert.Equal (1, tc);
+			Assert.Equal (1, wc);
+			Assert.Equal (1, v1c);
+			Assert.Equal (1, v2c);
+			Assert.Equal (1, sv1c);
+
+			Assert.True (t.CanFocus);
+			Assert.True (w.CanFocus);
+			Assert.False (v1.CanFocus);
+			Assert.False (v2.CanFocus);
+			Assert.True (sv1.CanFocus);
+		}
+
+		[Fact]
+		public void Initialized_Event_Will_Be_Invoked_When_Added_Dynamically ()
+		{
+			Application.Init (new FakeDriver (), new NetMainLoop (() => FakeConsole.ReadKey (true)));
+
+			var t = new Toplevel () { Id = "0", };
+
+			var w = new Window () { Id = "t", Width = Dim.Fill (), Height = Dim.Fill () };
+			var v1 = new View () { Id = "v1", Width = Dim.Fill (), Height = Dim.Fill () };
+			var v2 = new View () { Id = "v2", Width = Dim.Fill (), Height = Dim.Fill () };
+
+			int tc = 0, wc = 0, v1c = 0, v2c = 0, sv1c = 0;
+
+			t.Initialized += (s, e) => {
+				tc++;
+				Assert.Equal (1, tc);
+				Assert.Equal (0, wc);
+				Assert.Equal (0, v1c);
+				Assert.Equal (0, v2c);
+				Assert.Equal (0, sv1c);
+
+				Assert.True (t.CanFocus);
+				Assert.True (w.CanFocus);
+				Assert.False (v1.CanFocus);
+				Assert.False (v2.CanFocus);
+
+				Application.Refresh ();
+			};
+			w.Initialized += (s, e) => {
+				wc++;
+				Assert.Equal (t.Frame.Width, w.Frame.Width);
+				Assert.Equal (t.Frame.Height, w.Frame.Height);
+			};
+			v1.Initialized += (s, e) => {
+				v1c++;
+				Assert.Equal (t.Frame.Width, v1.Frame.Width);
+				Assert.Equal (t.Frame.Height, v1.Frame.Height);
+			};
+			v2.Initialized += (s, e) => {
+				v2c++;
+				Assert.Equal (t.Frame.Width, v2.Frame.Width);
+				Assert.Equal (t.Frame.Height, v2.Frame.Height);
+			};
+			w.Add (v1, v2);
+			t.Add (w);
+
+			Application.Iteration = () => {
+				var sv1 = new View () { Id = "sv1", Width = Dim.Fill (), Height = Dim.Fill () };
+
+				sv1.Initialized += (s, e) => {
+					sv1c++;
+					Assert.NotEqual (t.Frame.Width, sv1.Frame.Width);
+					Assert.NotEqual (t.Frame.Height, sv1.Frame.Height);
+					Assert.False (sv1.CanFocus);
+					sv1.CanFocus = true;
+					Assert.True (sv1.CanFocus);
+				};
+
+				v1.Add (sv1);
+
+				Application.Refresh ();
+				t.Running = false;
+			};
+
+			Application.Run (t, true);
+			Application.Shutdown (true);
+
+			Assert.Equal (1, tc);
+			Assert.Equal (1, wc);
+			Assert.Equal (1, v1c);
+			Assert.Equal (1, v2c);
+			Assert.Equal (1, sv1c);
+
+			Assert.True (t.CanFocus);
+			Assert.True (w.CanFocus);
+			Assert.False (v1.CanFocus);
+			Assert.False (v2.CanFocus);
+		}
 	}
 }