【问题标题】:Blazor - How to launch task on UI Dispatcher thread from a non-UI component?Blazor - 如何从非 UI 组件在 UI 调度程序线程上启动任务?
【发布时间】:2021-10-18 03:28:10
【问题描述】:

我正在使用 Xamarin Mobile Blazor Bindings 开发 Android/iOS 位置跟踪器应用程序。我不认为我专门使用 Xamarin Mobile Blazor 绑定这一事实是相关的,但为了完整起见,我提到它。

应用每 15 秒轮询一次移动设备的当前 GPS 位置,并在收到新位置时调用自定义事件,通知已注册该事件的所有 Blazor UI 组件。

所有 GPS 逻辑和事件处理都在一个简单的(非 UI)单例类中完成,如下所示:

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: '当前线程未与 Dispatcher 关联。触发渲染或组件状态时,使用 InvokeAsync() 将执行切换到 Dispatcher。'

现在,我明白 Exception 的意思了,当前正在运行的非 UI 线程不能用于调用事件,所以我需要以某种方式使用 Dispatcher 线程。

但是,提到的“InvokeAsync()”方法似乎只存在于 UI 组件的基类中,而“MyLocationManager”类不存在。

任何人都可以就我如何从像这个这样的非 UI 类中实现同样的目标提供任何建议吗?

感谢您的任何建议。

【问题讨论】:

  • 错误来自订阅 OnLocationUpdateReceived 的事件处理程序。发布,这是必须找到解决方案的地方。它在组件中吗?

标签: blazor blazor-webassembly


【解决方案1】:

您是否尝试过通过组件上的状态处理程序使用 InvokeAsync? 您可以使用以下方法,而不是在管理器上使用它: How to fix 'The current thread is not associated with the renderer's synchronization context'?

实际上,您注册一个更改处理程序事件并在组件端执行 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());
        }
    }
}

【讨论】:

  • 现在工作!感谢您的建议 - 它引导我找到答案。我已经在做类似于您建议的事情,省略了在 UI 组件中不使用“InvokeAsync”来调用“StateHasChanged()”,实际上正在生成异常。在 UI 组件的 InvoiceAsync 中包装对 StateHasChanged 的​​调用起到了作用。我应该自己发现的——当地时间凌晨 3 点左右,所以我把它归结为疲倦!再次感谢:)
猜你喜欢
  • 2014-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-30
相关资源
最近更新 更多