2016-08-11 64 views
2

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

  • 我可以get()从后台线程绑定到用户界面的属性,即是只set()必须从UI线程来完成?
  • 如果我有一个互操作对象,比如说Microsoft.Office.Interop.Slide,在我看来,我必须在UI线程上与它交互,因为它是一个实际的UI控件。但是,我可以听听在非UI线程中返回这些对象的事件吗?我可以从非UI线程检查幻灯片为null吗?对于来自非UI线程的Slide类型中包含的属性,我可以吗?

总之,在后台线程和UI线程之间切换时,我能记住一条好规则吗?例如“更改必须在UI线程上完成的任何动作”或“直接交互的任何动作,而不管动作(例如检查是否为null)必须在UI上完成线”。

回答

2

任何与UI交互不是线程安全的,试图削减角落会给你带来麻烦。你可能认为一个财产获得者是无辜的,但事实并非如此。当用户在线程运行时继续与UI进行交互时,没有什么事情发生,您将计算一个陈旧值的结果并显示与UI状态不一致的结果。你会知道不会改变对线程所做的事情至关重要的价值,你的用户不会这样做。

没有锁定可以解决这个问题,你不能在UI线程中放置一个锁,并且你不能对用户进行锁定。除了显而易见的之外,您需要编写代码,以防止用户在线程滚动时更改值。现在,它使得在线程内部获得值非常没有必要,您可能还需要在启动线程之前获取它。 lambda表达式非常方便将其传递给线程代码。

您当然可以可以允许用户更改UI,但是您必须编写更复杂的线程代码。您必须确保当前线程停止并且新线程启动,现在使用更新后的值。很难做到正确,线程停止不是瞬时的,容易陷入僵局。

同样适用于线程的结果,在线程内更新UI通常没有意义。 BackgroundWorker和Task类可以帮助您在线程完成后在UI线程上启动代码,它可以安全地更新UI的结果。让线程做一些容易想到且易于互锁的小东西,对于避免麻烦非常重要。

Office interop与WPF有点不同,在COM中线程安全是自动的。它自动调用Dispatcher.Invoke()的等价物,不需要额外的帮助。在工作线程运行时,Office文档更可能保持静态。除了允许用户更改文档之外,您还可以将getter问题带回黑桃。因人而异。

+0

感谢汉斯,我会接受你的回答。清理为什么属性获取者可能会危险地调用工作线程特别有用! –