mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
Add support for ISupportInitialize/ISupportInitializeNotification for UIs (#261)
When building UIs, it's quite common to separate the UI/control building code from the interaction logic by placing it all in a single method, usually `InitializeComponent` or similar. This also allows other tooling to generate such a method from potentially other UI languages (XML/Json/Yaml/whatever) at build-time. Even if no codegen is involved, having the UI building in a single place allows for creating base views that provide some common boilerplate that derived views can subsequently extend by overriding the base "initialize" method. The tricky part is that the base class cannot provide (at least that's against the .NET guidelines and it certainly makes for some confusing and potentially hard to reason bugs) a *virtual* method to do so and invoke it from the constructor, since the base class constructor is called and finishes *before* the derived class constructor does. This means that fields that may be required by the derived view to build its UI in its override of the "initialize" method would not be available by the time the base class calls it. Which is why the best place to handle such an approach is in the library itself, which controls the exact time when a view is about to be shown. Since no other method is provided for "initialize once before showing for the first time" scenario, a good trade-off is to simply enable this mechanism as totally opt-in by allowing views to implement `ISupportInitialize` (which provides the `BeginInit`/`EndInit` pair) or `ISupportInitializeNotification` (which adds `IsInitialized`/`Initialized` property/event). If the former is implemented, the Begin/End will be called on every `Run`, since the library has no way of knowing if the view has already been initialized before. In these cases, the views could just clear all its controls in the `BeginInit` and reconstruct the UI entirely in `EndInit`. The `ISupportInitializeNotification` interface allows more control for views that require that Begin/End init are called exactly once.
This commit is contained in:
committed by
Miguel de Icaza
parent
00c5997daa
commit
ebb3c186ce
@@ -18,6 +18,7 @@ using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Linq;
|
||||
using NStack;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Terminal.Gui {
|
||||
|
||||
@@ -1910,6 +1911,14 @@ namespace Terminal.Gui {
|
||||
var rs = new RunState (toplevel);
|
||||
|
||||
Init ();
|
||||
if (toplevel is ISupportInitializeNotification initializableNotification &&
|
||||
!initializableNotification.IsInitialized) {
|
||||
initializableNotification.BeginInit();
|
||||
initializableNotification.EndInit();
|
||||
} else if (toplevel is ISupportInitialize initializable) {
|
||||
initializable.BeginInit();
|
||||
initializable.EndInit();
|
||||
}
|
||||
toplevels.Push (toplevel);
|
||||
Current = toplevel;
|
||||
Driver.PrepareToRun (MainLoop, ProcessKeyEvent, ProcessMouseEvent);
|
||||
|
||||
Reference in New Issue
Block a user