【问题标题】:C# UWP The application called an interface that was marshalled for a different threadC# UWP 应用程序调用了为不同线程编组的接口
【发布时间】:2023-03-20 21:52:01
【问题描述】:

我有一个 C# UWP 应用程序,其中包含一个我想每 5 秒调用一次的函数。 当从按钮调用时,该函数运行良好,并且 Timer 每 5 秒写入调试控制台一次......当我从 Timer 调用该函数时,一切都变得松散了。我明白了:

System.Exception 未被用户代码处理 H结果=-2147417842 Message=应用程序调用了为不同线程编组的接口。 (来自 HRESULT 的异常:0x8001010E (RPC_E_WRONG_THREAD))

【问题讨论】:

  • 你用的是什么定时器?

标签: c# multithreading uwp


【解决方案1】:

我假设您的函数会触及应用的 UI。任何接触 UI 的东西都需要在 UI 的调度线程上运行(大多数应用只有一个,直到您进入多个窗口应用)。

您可以使用 Windows.UI.Xaml.DispatcherTimer 在调度程序线程上运行您的计时器。

如果您需要在工作线程上运行代码,然后在调度程序线程上触摸 UI,您可以调用 Dispatcher.RunAsync 将调用编组回调度程序线程。

您通常可以通过Window.Dispatcher 从您的窗口中找到您的调度员。

var ignored = Window.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
   // Do something on the dispatcher thread
});

【讨论】:

  • 如果你有一个不是窗口的容器,或者你的整个进程是脱离 UI 线程:container.Dispatcher.RunAsync(...) 是一个更好的选择。据我所知,您可以将其存储起来以备后用。
【解决方案2】:

您很可能正在使用来自System.ThreadingTimer。该计时器的事件不会被视为常规 GUI 事件,如果您从该计时器调用的方法访问 GUI 项,则会导致问题,因为该线程不是 GUI 项的所有者。

使用来自System.Windows.FormsTimer。该计时器可以访问您的 GUI 项目。

【讨论】:

  • 原则上正确,但 UWP 应用中的 System.Windows.Forms 似乎不太可能。
  • @spender 你的意思是它在 UWP 中不可用?
【解决方案3】:

您实际上可以使用Observable.Interval from Reactive Extensions 并明确指定要在哪个调度程序上观察计时器事件:

Observable.Interval(TimeSpan.FromSeconds(1), Scheduler.Default)
    .ObserveOn(coreWindow.Dispatcher)
    .Subscribe(_ => Log.Warning("Dispatcher.HasThreadAccess: " + coreWindow.Dispatcher.HasThreadAccess));

我喜欢这种方法的一点是,您明确说明了在哪个线程上发生了什么(请参阅SubscribeOn and ObserveOn)。

【讨论】:

    猜你喜欢
    • 2018-12-26
    • 2017-12-18
    • 1970-01-01
    • 1970-01-01
    • 2018-05-21
    • 1970-01-01
    • 1970-01-01
    • 2011-04-05
    • 1970-01-01
    相关资源
    最近更新 更多