c# - UI 线程 vs 后台线程 - UI 控制可访问性边界

标签 c# wpf office-interop

很可能我的问题无法得到一般性的回答,如果是这样,无论如何,这都是有趣的信息。我试图更好地理解 UI 控制交互,特别是非 UI 线程允许执行什么操作以及不允许执行什么操作。就我而言,我正在与 WPF 控件和位于 Microsoft.Office.Interop 命名空间中的对象(表示控件)进行交互。我在模型层的后台线程上做了很多工作,但是当我的 View 模型中接收到事件时,我会在 UI 线程上进行调度(这通常是在处理绑定(bind)到 WPF 控件的属性时) 。这对我来说很有意义,而且似乎效果很好。然而,我不确定后台线程可以做什么和不能做什么。本质上,我试图理解边界在哪里。为了发挥想象力,请参阅下面的一些问题。我知道我的请求有点开放,所以如果有人知道我可以阅读的外部资源,这对我来说同样好。

  • 我可以从后台线程获取绑定(bind)到 ui 的属性上的 get() 吗?也就是说,是否只有 set() 必须从 UI 线程完成?
  • 如果我有一个互操作对象,例如 Microsoft.Office.Interop.Slide,在我看来,我必须在 UI 线程上与它交互,因为它是一个实际的 ui 控件。但是我可以监听在非 ui 线程中返回此类对象的事件吗?我可以从非 ui 线程检查幻灯片是否为空吗?我可以从非 UI 线程 get() 获取 Slide 类型中包含的属性吗?

总之,在后台线程和 UI 线程之间切换时,有什么好的规则可以牢记吗?例如,“任何更改 ui 控件的操作都必须在 ui 线程上完成”,或“任何直接交互的操作,无论操作如何(例如检查 null) 与 ui 控件必须在 ui 线程上完成”。

最佳答案

任何与 UI 交互的东西都不是线程安全的,试图走捷径会给你带来麻烦。您可能认为抢夺属性(property)的人是无辜的,但事实并非如此。当用户在线程运行时继续与 UI 交互时,不会发生任何漂亮的事情,您将从过时的值计算结果并呈现与 UI 状态不一致的结果。您会知道不要更改对线程功能至关重要的值,您的用户也不会这样做。

没有锁可以解决这个问题,你不能在 UI 线程中加锁,也不能对用户加锁。除了明显的代码之外,您需要编写代码来防止用户在线程运行时更改该值。现在就没有必要获取线程内部的值了,你不妨在启动线程之前获取它。 lambda 表达式可以非常方便地将其传递给线程代码。

您当然可以允许用户更改 UI,但随后您必须编写更复杂的线程代码。您必须确保当前线程停止并启动一个新线程,现在使用更新后的值。很难正确地做到这一点,线程停止不是瞬时的并且容易导致死锁。

这同样适用于线程的结果,通常没有必要更新线程内的 UI。 BackgroundWorker 和 Task 类可帮助您在线程完成后在 UI 线程上启动代码,它可以使用结果安全地更新 UI。让线程做一些容易思考、容易互锁的小事情,对于避免麻烦非常重要。

Office 互操作与 WPF 略有不同,COM 中的线程安全是自动的。它会自动调用 Dispatcher.Invoke() 的等效项,并且不需要额外的帮助。当工作线程运行时,Office 文档更有可能保持静态。除非您允许用户也更改文档,否则您肯定会遇到 setter/getter 问题。 YMMV。

关于c# - UI 线程 vs 后台线程 - UI 控制可访问性边界,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38901230/

相关文章:

C# - 从基类获取页面的 BaseType.Name 和命名空间

c# - 在 WPF 中的 UserControl 中设置窗口所有者

wpf - 如何禁用某些按钮的加速键

c# - 使用c#删除书签的内容而不删除ms word中的书签

c# - 如何使用C#为Outlook配置缓存Exchange模式?

vb.net - GetOccurrence总是抛出异常

javascript - 某些语言的 SignalR 客户端调用失败

c# - 如何在代码隐藏中添加资源

c# - 关于在 winphone 8.1 RT 中在 ContentDialogResult 中换行文本

c# - 对 UserControl 进行验证工作