在 .NET MAUI UI 线程上创建一个线程

Browse sample. 浏览示例

本文介绍如何使用 .NET 多平台应用 UI (.NET MAUI) MainThread 类在主 UI 线程上运行代码。 大多数操作系统对涉及用户界面的代码采用单线程模式。 正确序列化用户界面事件(包括击键和触控输入)需要此模型。 此线程通常称为“主线程”“用户界面线程”“UI 线程”。 此模型的缺点是用于访问用户界面元素的所有代码必须在应用程序的主线程上运行。

MainThread 类可从 Microsoft.Maui.ApplicationModel 命名空间中获得。

何时需要

应用程序有时需要使用在辅助执行线程上调用事件处理程序的事件,例如 AccelerometerCompass 传感器。 当传感速度较快时,所有传感器都可能在二级线程上返回信息。 如果事件处理程序需要访问用户界面元素,则必须调用主线程上的代码。

在 UI 线程上运行代码

若要在主线程上运行代码,请调用静态 MainThread.BeginInvokeOnMainThread 方法。 参数是 Action 对象,它只是没有参数且没有返回值的方法:

MainThread.BeginInvokeOnMainThread(() =>
{
    // Code to run on the main thread
});

还可以为代码定义单独的方法,然后用 BeginInvokeOnMainThread 方法调用该代码:

void MyMainThreadCode()
{
    // Code to run on the main thread
}

MainThread.BeginInvokeOnMainThread(MyMainThreadCode);

确定是否需要调用

使用 MainThread 类,可以确定当前代码是否在主线程上运行。 如果调用该属性的代码在主线程上运行,MainThread.IsMainThread 属性返回 true,否则返回false。 按理说,在调用 MainThread.BeginInvokeOnMainThread 之前,你需要确定代码是否在主线程上运行。 例如,如果代码在主线程上运行,下面的代码会使用 IsMainThread 检测是否应直接调用 MyMainThreadCode 方法。 如果它不在主线程上运行,该方法就会传递给 BeginInvokeOnMainThread

if (MainThread.IsMainThread)
    MyMainThreadCode();

else
    MainThread.BeginInvokeOnMainThread(MyMainThreadCode);

不需要此检查。 BeginInvokeOnMainThread 本身测试当前代码是否在主线程上运行。 如果代码在主线程上运行,BeginInvokeOnMainThread 就会直接调用所提供的方法。 如果代码在辅助线程上运行,BeginInvokeOnMainThread 会在主线程上调用提供的方法。 因此,如果运行的代码相同,无论主线程还是辅助线程,只需调用 BeginInvokeOnMainThread 而无需检查是否需要。 这样做的开销微乎其微。

需要检查IsMainThread属性的唯一原因是,如果有根据线程执行不同操作的分支逻辑。

其他方法

MainThread 类包括以下附加 static 方法,可用于与背景线程中的用户界面元素进行交互:

方法 自变量 返回 目的
InvokeOnMainThreadAsync<T> Func<T> Task<T> 在主线程上调用 Func<T>,并等待其完成。
InvokeOnMainThreadAsync Action Task 在主线程上调用 Action,并等待其完成。
InvokeOnMainThreadAsync<T> Func<Task<T>> Task<T> 在主线程上调用 Func<Task<T>>,并等待其完成。
InvokeOnMainThreadAsync Func<Task> Task 在主线程上调用 Func<Task>,并等待其完成。
GetMainThreadSynchronizationContextAsync Task<SynchronizationContext> 返回主线程的 SynchronizationContext