是否有可能从另一个线程访问一个UI元素,如果线程没有修改该元素

本文关键字:元素 线程 UI 如果 一个 修改 另一个 有可能 访问 是否 | 更新日期: 2023-09-27 17:49:15

让我们假设在实例化form/control/element的线程(通常是主线程)中运行的代码没有同时修改/访问该元素,是否有可能:

  1. 获取Text属性

  2. 枚举ListView

  3. 订阅表单的关闭事件。(知道钩子将从实例化该表单的线程调用)

我已经尝试了所有的3和程序似乎没有抱怨它。我一直认为你必须调用任何想要远程触摸任何与UI相关的调用(读或写)。

我非常清楚地理解为什么在修改元素时需要使用isinvokerrequied/Invoke模式,但是我不明白为什么访问属性/事件会导致任何问题。

是否有可能从另一个线程访问一个UI元素,如果线程没有修改该元素

这绝对是可能的,但是,它可能会导致意外的行为。此外,其他与线程相关的bug也需要考虑,例如竞争条件/死锁,请参阅托管线程最佳实践。

为了安全起见,我总是坚持在UI线程上访问UI。

你在做什么来确保UI线程不修改控件,而你正在从它读取?将数据封送到UI线程的全部原因是您不需要担心这种情况。枚举列表框是最容易打破的,因为它将花费最长的时间(这会为竞争条件创建最大的窗口)。你应该把这3件事都封送到UI线程。

这不安全。当您从另一个线程读取控件时,UI线程可以(也可能会)更改控件的状态。您的读取可能会在未完成的状态下捕获控件。它现在似乎行得通,但迟早会失败。可能是不可预测的和壮观的。

不,您可能不需要使用Invoke模式。坦率地说……这种模式通常是最糟糕的选择。通常最好是让工作线程完成繁重的工作,然后通过队列向UI线程发送新的数据或进度信息,并让UI线程通过计时器拾取这些信息。这有几个优点。

  • 消除昂贵的InvokeBeginInvoke操作。
  • UI线程可以决定何时以及多久用新数据更新自己,而不是让工作线程来决定。
  • 你在工作线程上获得更多的吞吐量,因为它不必等待Invoke返回。
  • 不存在像BeginInvoke那样超过UI消息队列的风险。
  • 它解耦了UI和工作线程的交互。

您需要枚举ListView并构建一个单独的数据结构,然后工作线程可以安全地访问该数据结构。如果ListView包含很多项目,考虑维护一个单独的集合与控件串联。通过这种方式,您可以在更长的时间内分散处理数据的代价,在此期间可能不会被注意到。毕竟,我们不希望复制操作冻结UI线程,否则用户会注意到。ConcurrentBag或类似的可能是一个不错的选择,因为它可以安全地由UI线程修改,而工作线程正在读取它。