Blazor - 如何从非 UI 组件在 UI 调度程序线程上启动任务?
Blazor - How to launch task on UI Dispatcher thread from a non-UI component?
我正在使用 Xamarin Mobile Blazor Bindings 开发一个 Android/iOS 位置跟踪器应用程序。我不认为我使用 Xamarin Mobile Blazor Bindings 的事实特别相关,但我提到它是为了完整性。
该应用程序每 15 秒轮询一次移动设备的当前 GPS 位置,并在收到新位置时调用自定义事件,通知任何已注册该事件的 Blazor UI 组件。
所有 GPS 逻辑和事件处理都在一个简单的(非 UI)单例 class 中完成,如下所示:
public class MyLocationManager
{
public event EventHandler<LocationUpdatedEventArgs> OnLocationUpdateReceived;
private Timer _timer;
public void StartLocationTracking()
{
if (DeviceInfo.Platform == DevicePlatform.Android)
{
// On Android, Location can be polled using a timer
_timer = new Timer(
async stateInfo =>
{
var newLocationCoordinates = await _addCurrentLocationPoint();
var eventArgs = new LocationUpdatedEventArgs
{
Latitude = newLocationCoordinates.Latitude,
Longitude = newLocationCoordinates.Longitude
};
// **** The following line generates an Exception ****
OnLocationUpdateReceived?.Invoke(this, eventArgs)
},
new AutoResetEvent(false),
15000 /* Wait 15 seconds before initial call */,
15000 /* Then repeat every 15 seconds */
);
}
}
}
不幸的是,当计时器触发时,以下代码会产生异常:
OnLocationUpdateReceived?.Invoke(this, eventArgs)
例外情况是:
System.InvalidOperationException: 'The current thread is not associated with the Dispatcher. Use InvokeAsync() to switch execution to the Dispatcher when triggering rendering or component state.'
现在,我明白异常在说什么,当前 运行 的非 UI 线程不能用于调用事件,所以我需要以某种方式使用改为调度程序线程。
但是,提到的“InvokeAsync()”方法似乎只存在于class 组件的基础class 中,而“MyLocationManager”class 不存在。
任何人都可以就如何从非 UI class 中实现相同目标提供任何建议吗?
非常感谢收到任何建议。
您是否尝试过通过组件上的状态处理程序使用 InvokeAsync?
您可以使用以下方法,而不是在管理器上使用它:
实际上,您注册一个更改处理程序事件并在组件端执行 InvokeAsync:
private async void OnMyChangeHandler(object sender, EventArgs e)
{
// InvokeAsync is inherited, it syncs the call back to the render thread
await InvokeAsync(() => {
DoStuff();
StateHasChanged());
}
}
}
我正在使用 Xamarin Mobile Blazor Bindings 开发一个 Android/iOS 位置跟踪器应用程序。我不认为我使用 Xamarin Mobile Blazor Bindings 的事实特别相关,但我提到它是为了完整性。
该应用程序每 15 秒轮询一次移动设备的当前 GPS 位置,并在收到新位置时调用自定义事件,通知任何已注册该事件的 Blazor UI 组件。
所有 GPS 逻辑和事件处理都在一个简单的(非 UI)单例 class 中完成,如下所示:
public class MyLocationManager
{
public event EventHandler<LocationUpdatedEventArgs> OnLocationUpdateReceived;
private Timer _timer;
public void StartLocationTracking()
{
if (DeviceInfo.Platform == DevicePlatform.Android)
{
// On Android, Location can be polled using a timer
_timer = new Timer(
async stateInfo =>
{
var newLocationCoordinates = await _addCurrentLocationPoint();
var eventArgs = new LocationUpdatedEventArgs
{
Latitude = newLocationCoordinates.Latitude,
Longitude = newLocationCoordinates.Longitude
};
// **** The following line generates an Exception ****
OnLocationUpdateReceived?.Invoke(this, eventArgs)
},
new AutoResetEvent(false),
15000 /* Wait 15 seconds before initial call */,
15000 /* Then repeat every 15 seconds */
);
}
}
}
不幸的是,当计时器触发时,以下代码会产生异常:
OnLocationUpdateReceived?.Invoke(this, eventArgs)
例外情况是:
System.InvalidOperationException: 'The current thread is not associated with the Dispatcher. Use InvokeAsync() to switch execution to the Dispatcher when triggering rendering or component state.'
现在,我明白异常在说什么,当前 运行 的非 UI 线程不能用于调用事件,所以我需要以某种方式使用改为调度程序线程。
但是,提到的“InvokeAsync()”方法似乎只存在于class 组件的基础class 中,而“MyLocationManager”class 不存在。
任何人都可以就如何从非 UI class 中实现相同目标提供任何建议吗?
非常感谢收到任何建议。
您是否尝试过通过组件上的状态处理程序使用 InvokeAsync?
您可以使用以下方法,而不是在管理器上使用它:
实际上,您注册一个更改处理程序事件并在组件端执行 InvokeAsync:
private async void OnMyChangeHandler(object sender, EventArgs e)
{
// InvokeAsync is inherited, it syncs the call back to the render thread
await InvokeAsync(() => {
DoStuff();
StateHasChanged());
}
}
}