mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-30 09:47:58 +01:00
updated docs further, added UICatalog API, clean up
This commit is contained in:
@@ -1,161 +0,0 @@
|
||||
Event Processing and the Application Main Loop
|
||||
==============================================
|
||||
|
||||
The method `Application.Run` that we covered before will wait for
|
||||
events from either the keyboard or mouse and route those events to the
|
||||
proper view.
|
||||
|
||||
The job of waiting for events and dispatching them in the
|
||||
`Application` is implemented by an instance of the
|
||||
[`MainLoop`]()
|
||||
class.
|
||||
|
||||
Mainloops are a common idiom in many user interface toolkits so many
|
||||
of the concepts will be familiar to you if you have used other
|
||||
toolkits before.
|
||||
|
||||
This class provides the following capabilities:
|
||||
|
||||
* Keyboard and mouse processing
|
||||
* .NET Async support
|
||||
* Timers processing
|
||||
* Invoking of UI code from a background thread
|
||||
* Idle processing handlers
|
||||
* Possibility of integration with other mainloops.
|
||||
* On Unix systems, it can monitor file descriptors for readability or writability.
|
||||
|
||||
The `MainLoop` property in the the
|
||||
[`Application`](../api/Terminal.Gui/Terminal.Gui.Application.html)
|
||||
provides access to these functions.
|
||||
|
||||
When your code invokes `Application.Run (Toplevel)`, the application
|
||||
will prepare the current
|
||||
[`Toplevel`](../api/Terminal.Gui/Terminal.Gui.Toplevel.html) instance by
|
||||
redrawing the screen appropriately and then calling the mainloop to
|
||||
run.
|
||||
|
||||
You can configure the Mainloop before calling Application.Run, or you
|
||||
can configure the MainLoop in response to events during the execution.
|
||||
|
||||
The keyboard inputs is dispatched by the application class to the
|
||||
current TopLevel window this is covered in more detail in the
|
||||
[Keyboard Event Processing](keyboard.html) document.
|
||||
|
||||
|
||||
Async Execution
|
||||
---------------
|
||||
|
||||
On startup, the `Application` class configured the .NET Asynchronous
|
||||
machinery to allow you to use the `await` keyword to run tasks in the
|
||||
background and have the execution of those tasks resume on the context
|
||||
of the main thread running the main loop.
|
||||
|
||||
Once you invoke `Application.Main` the async machinery will be ready
|
||||
to use, and you can merely call methods using `await` from your main
|
||||
thread, and the awaited code will resume execution on the main
|
||||
thread.
|
||||
|
||||
Timers Processing
|
||||
-----------------
|
||||
|
||||
You can register timers to be executed at specified intervals by
|
||||
calling the [`AddTimeout`]() method, like this:
|
||||
|
||||
```csharp
|
||||
void UpdateTimer ()
|
||||
{
|
||||
time.Text = DateTime.Now.ToString ();
|
||||
}
|
||||
|
||||
var token = Application.MainLoop.AddTimeout (TimeSpan.FromSeconds (20), UpdateTimer);
|
||||
```
|
||||
|
||||
The return value from AddTimeout is a token value that you can use if
|
||||
you desire to cancel the timer before it runs:
|
||||
|
||||
```csharup
|
||||
Application.MainLoop.RemoveTimeout (token);
|
||||
```
|
||||
|
||||
Idle Handlers
|
||||
-------------
|
||||
|
||||
You can register code to be executed when the application is idling
|
||||
and there are no events to process by calling the
|
||||
[`AddIdle`]()
|
||||
method. This method takes as a parameter a function that will be
|
||||
invoked when the application is idling.
|
||||
|
||||
Idle functions should return `true` if they should be invoked again,
|
||||
and `false` if the idle invocations should stop.
|
||||
|
||||
Like the timer APIs, the return value is a token that can be used to
|
||||
cancel the scheduled idle function from being executed.
|
||||
|
||||
Threading
|
||||
---------
|
||||
|
||||
Like other UI toolkits, Terminal.Gui is generally not thread safe.
|
||||
You should avoid calling methods in the UI classes from a background
|
||||
thread as there is no guarantee that they will not corrupt the state
|
||||
of the UI application.
|
||||
|
||||
Generally, as there is not much state, you will get lucky, but the
|
||||
application will not behave properly.
|
||||
|
||||
You will be served better off by using C# async machinery and the
|
||||
various APIs in the `System.Threading.Tasks.Task` APIs. But if you
|
||||
absolutely must work with threads on your own you should only invoke
|
||||
APIs in Terminal.Gui from the main thread.
|
||||
|
||||
To make this simple, you can use the `Application.MainLoop.Invoke`
|
||||
method and pass an `Action`. This action will be queued for execution
|
||||
on the main thread at an appropriate time and will run your code
|
||||
there.
|
||||
|
||||
For example, the following shows how to properly update a label from a
|
||||
background thread:
|
||||
|
||||
```
|
||||
void BackgroundThreadUpdateProgress ()
|
||||
{
|
||||
Application.MainLoop.Invoke (() => {
|
||||
progress.Text = $"Progress: {bytesDownloaded/totalBytes}";
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
Integration With Other Main Loop Drivers
|
||||
----------------------------------------
|
||||
|
||||
It is possible to run the main loop in a way that it does not take
|
||||
over control of your application, but rather in a cooperative way.
|
||||
|
||||
To do this, you must use the lower-level APIs in `Application`: the
|
||||
`Begin` method to prepare a toplevel for execution, followed by calls
|
||||
to `MainLoop.EventsPending` to determine whether the events must be
|
||||
processed, and in that case, calling `RunLoop` method and finally
|
||||
completing the process by calling `End`.
|
||||
|
||||
The method `Run` is implemented like this:
|
||||
|
||||
```
|
||||
void Run (Toplevel top)
|
||||
{
|
||||
var runToken = Begin (view);
|
||||
RunLoop (runToken);
|
||||
End (runToken);
|
||||
}
|
||||
```
|
||||
|
||||
Unix File Descriptor Monitoring
|
||||
-------------------------------
|
||||
|
||||
On Unix, it is possible to monitor file descriptors for input being
|
||||
available, or for the file descriptor being available for data to be
|
||||
written without blocking the application.
|
||||
|
||||
To do this, you on Unix, you can cast the `MainLoop` instance to a
|
||||
[`UnixMainLoop`]()
|
||||
and use the `AddWatch` method to register an interest on a particular
|
||||
condition.
|
||||
Reference in New Issue
Block a user