diff --git a/UICatalog/Scenarios/KeyBindings.cs b/UICatalog/Scenarios/KeyBindings.cs index b51fb81fc..afb69ec4e 100644 --- a/UICatalog/Scenarios/KeyBindings.cs +++ b/UICatalog/Scenarios/KeyBindings.cs @@ -125,41 +125,35 @@ public sealed class KeyBindings : Scenario }; appWindow.Add (_focusedBindingsListView); - appWindow.HasFocusChanged += AppWindow_HasFocusChanged; - appWindow.DrawContent += AppWindow_DrawContent; + Application.Navigation!.FocusedChanged += Application_HasFocusChanged; // Run - Start the application. Application.Run (appWindow); + Application.Navigation!.FocusedChanged -= Application_HasFocusChanged; appWindow.Dispose (); // Shutdown - Calling Application.Shutdown is required. Application.Shutdown (); } - private void AppWindow_DrawContent (object sender, DrawEventArgs e) - { - _focusedBindingsListView.Title = $"_Focused ({Application.Top.MostFocused.GetType ().Name}) Bindings"; - _focusedBindings.Clear (); - foreach (var binding in Application.Top.MostFocused.KeyBindings.Bindings.Where (b => b.Value.Scope == KeyBindingScope.Focused)) + private void Application_HasFocusChanged (object sender, EventArgs e) + { + View focused = Application.Navigation!.GetFocused (); + + if (focused == null) + { + return; + } + + _focusedBindingsListView.Title = $"_Focused ({focused?.GetType ().Name}) Bindings"; + + _focusedBindings.Clear(); + foreach (var binding in focused?.KeyBindings!.Bindings.Where (b => b.Value.Scope == KeyBindingScope.Focused)!) { _focusedBindings.Add ($"{binding.Key} -> {binding.Value.Commands [0]}"); } } - - private void AppWindow_HasFocusChanged (object sender, HasFocusEventArgs e) - { - if (e.NewValue) - { - if (Application.Top is { MostFocused: {} }) - { - foreach (var binding in Application.Top.MostFocused.KeyBindings.Bindings.Where (b => b.Value.Scope == KeyBindingScope.Focused)) - { - _focusedBindings.Add ($"{binding.Key} -> {binding.Value.Commands [0]}"); - } - } - } - } } public class KeyBindingsDemo : View diff --git a/UnitTests/UICatalog/ScenarioTests.cs b/UnitTests/UICatalog/ScenarioTests.cs index f8a9e3cb6..082cd7879 100644 --- a/UnitTests/UICatalog/ScenarioTests.cs +++ b/UnitTests/UICatalog/ScenarioTests.cs @@ -41,9 +41,9 @@ public class ScenarioTests : TestsAllViews var scenario = (Scenario)Activator.CreateInstance (scenarioType); uint abortTime = 1500; + object timeout = null; var initialized = false; var shutdown = false; - object timeout = null; int iterationCount = 0; Application.InitializedChanged += OnApplicationOnInitializedChanged; @@ -145,6 +145,9 @@ public class ScenarioTests : TestsAllViews [MemberData (nameof (AllScenarioTypes))] public void All_Scenarios_Time (Type scenarioType) { + Assert.Null (_timeoutLock); + _timeoutLock = new (); + // Disable any UIConfig settings ConfigurationManager.ConfigLocations savedConfigLocations = ConfigurationManager.Locations; ConfigurationManager.Locations = ConfigurationManager.ConfigLocations.DefaultOnly; @@ -152,8 +155,13 @@ public class ScenarioTests : TestsAllViews // If a previous test failed, this will ensure that the Application is in a clean state Application.ResetState (true); - int iterationCount = 0; + uint maxIterations = 1000; + uint abortTime = 2000; + object timeout = null; + var initialized = false; + var shutdown = false; + int iterationCount = 0; int clearedContentCount = 0; int refreshedCount = 0; int updatedCount = 0; @@ -165,22 +173,35 @@ public class ScenarioTests : TestsAllViews Stopwatch stopwatch = null; Application.InitializedChanged += OnApplicationOnInitializedChanged; - Application.ForceDriver = "FakeDriver"; scenario!.Main (); scenario.Dispose (); scenario = null; Application.ForceDriver = string.Empty; - Application.InitializedChanged -= OnApplicationOnInitializedChanged; + lock (_timeoutLock) + { + if (timeout is { }) + { + timeout = null; + } + } + + Assert.True (initialized); + Assert.True (shutdown); + + lock (_timeoutLock) + { + _timeoutLock = null; + } + _output.WriteLine ($"Scenario {scenarioType}"); _output.WriteLine ($" took {stopwatch.ElapsedMilliseconds} ms to run."); _output.WriteLine ($" called Driver.ClearContents {clearedContentCount} times."); _output.WriteLine ($" called Driver.Refresh {refreshedCount} times."); _output.WriteLine ($" which updated the screen {updatedCount} times."); - _output.WriteLine ($" called Application.Top.Draw {drawCompleteCount} times."); -// _output.WriteLine ($" called View.Draw {drawCompleteCount} times."); + _output.WriteLine ($" called View.Draw {drawCompleteCount} times."); // Restore the configuration locations ConfigurationManager.Locations = savedConfigLocations; @@ -192,6 +213,12 @@ public class ScenarioTests : TestsAllViews { if (a.CurrentValue) { + lock (_timeoutLock) + { + timeout = Application.AddTimeout (TimeSpan.FromMilliseconds (abortTime), ForceCloseCallback); + } + + initialized = true; Application.Iteration += OnApplicationOnIteration; Application.Driver!.ClearedContents += (sender, args) => clearedContentCount++; Application.Driver!.Refreshed += (sender, args) => @@ -209,6 +236,7 @@ public class ScenarioTests : TestsAllViews } else { + shutdown = true; Application.NotifyNewRunState -= OnApplicationNotifyNewRunState; Application.Iteration -= OnApplicationOnIteration; stopwatch!.Stop (); @@ -219,7 +247,7 @@ public class ScenarioTests : TestsAllViews void OnApplicationOnIteration (object s, IterationEventArgs a) { iterationCount++; - if (iterationCount > 1000) + if (iterationCount > maxIterations) { // Press QuitKey _output.WriteLine ($"Attempting to quit with {Application.QuitKey}"); @@ -230,9 +258,43 @@ public class ScenarioTests : TestsAllViews void OnApplicationNotifyNewRunState (object sender, RunStateEventArgs e) { - Application.Top.DrawComplete += (sender, args) => drawCompleteCount++; + // Get a list of all subviews under Application.Top (and their subviews, etc.) + // and subscribe to their DrawComplete event + void SubscribeToDrawComplete (View view) + { + view.DrawComplete += (s, a) => drawCompleteCount++; + foreach (View subview in view.Subviews) + { + SubscribeToDrawComplete (subview); + } + } + + SubscribeToDrawComplete (Application.Top); } + // If the scenario doesn't close within the abort time, this will force it to quit + bool ForceCloseCallback () + { + lock (_timeoutLock) + { + if (timeout is { }) + { + timeout = null; + } + } + + _output.WriteLine( + $"'{scenario.GetName ()}' failed to Quit with {Application.QuitKey} after {abortTime}ms and {iterationCount} iterations. Force quit."); + + Application.RequestStop (); + //// Restore the configuration locations + //ConfigurationManager.Locations = savedConfigLocations; + //ConfigurationManager.Reset (); + + //Application.ResetState (true); + + return false; + } } public static IEnumerable AllScenarioTypes =>