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

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

  1. 获取TextBox的Text属性。

  2. 枚举ListView。

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

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

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

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

我总是坚持在UI线程上访问UI以保证安全。

你正在做什么来确保UI线程在你读取它时没有修改控件? 编组到UI线程的全部原因是您不必担心这种情况。 特别是枚举列表框将是最容易打破的,因为它将花费最长的时间(这为竞争条件创建了最大的窗口)。 您应该为所有这三个方面的UI线程进行编组。

这不安全。 当您从另一个线程读取控件时,UI线程可能(并且可能会)更改控件的状态。 您的读取可能会在半生不熟的状态下捕获控件。 它似乎现在可以正常工作,但迟早它会失败……可能是不可预测和引人注目的。

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

  • 消除昂贵的InvokeBeginInvoke操作。
  • UI线程决定用新数据更新自己的时间和频率,而不是让工作线程指示这一点。
  • 您可以在工作线程上获得更多吞吐量,因为它不必等待Invoke返回。
  • BeginInvoke一样,不存在超出UI消息队列的风险。
  • 它解耦UI和工作线程交互。

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