- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
任何时候初学者都会问类似这样的问题:How to update the GUI from another thread in C#? ,答案很直接:
if (foo.InvokeRequired)
{
foo.BeginInvoke(...)
} else {
...
}
但是真的好用吗?在非 GUI 线程执行 foo.InvokeRequired
之后,foo
的状态会发生变化。例如,如果我们在 foo.InvokeRequired
之后但在 foo.BeginInvoke
之前关闭表单,调用 foo.BeginInvoke
将导致 InvalidOperationException
:在创建窗口句柄之前无法在控件上调用 Invoke 或 BeginInvoke。如果我们在调用 InvokeRequired
之前关闭窗体,则不会发生这种情况,因为即使从非 GUI 线程调用它也是 false
。
另一个例子:假设
foo
是一个
TextBox
。如果您关闭表单,并且在非 GUI 线程执行
foo.InvokeRequired
(这是错误的,因为表单已关闭)和
foo.AppendText
之后,它将导致
ObjectDisposedException
.
相比之下,我认为使用 WindowsFormsSynchronizationContext
更容易 - 使用 Post
发布回调只有在线程仍然存在时才会发生,并且使用 Send 进行同步调用
如果线程不再存在,则抛出 InvalidAsynchronousStateException
。
使用 WindowsFormsSynchronizationContext
不是更简单吗?我错过了什么吗?如果它不是真正的线程安全,我为什么要使用 InvokeRequired-BeginInvoke 模式?你觉得哪个更好?
最佳答案
WindowsFormsSynchronizationContext
通过将自身附加到绑定(bind)到创建上下文的线程的特殊控件来工作。
所以
if (foo.InvokeRequired)
{
foo.BeginInvoke(...)
} else {
...
}
可以替换为更安全的版本:
context.Post(delegate
{
if (foo.IsDisposed) return;
...
});
假设 context
是在与 foo
相同的 UI 线程上创建的 WindowsFormsSynchronizationContext
。
这个版本避免了你引起的问题:
Right after non-GUI thread executes foo.InvokeRequired the state of foo can change. For example, if we close form right after foo.InvokeRequired, but before foo.BeginInvoke, calling foo.BeginInvoke will lead to InvalidOperationException: Invoke or BeginInvoke cannot be called on a control until the window handle has been created. This wouldn't happen if we close the form before calling InvokeRequired, because it would be false even when called from non-GUI thread.
如果您使用多个消息循环或多个 UI 线程,请注意 WindowsFormsSynchronizationContext.Post
的一些特殊情况:
WindowsFormsSynchronizationContext.Post
仅当创建委托(delegate)的线程上仍有消息泵时才会执行委托(delegate)。如果没有什么都没有发生,也没有引发异常。Application.Run
例如)委托(delegate)将执行(这是由于系统为每个线程维护一个消息队列,而不知道是否有人从中提取消息这一事实)WindowsFormsSynchronizationContext.Send
将抛出 InvalidAsynchronousStateException
如果它绑定(bind)到的线程不再存在。但是如果它绑定(bind)的线程是事件的并且不运行消息循环它不会立即执行但仍然会被放置在消息队列中并在 Application.Run< 时执行
再次执行。如果 IsDisposed
在自动处理的控件(如主窗体)上调用,则这些情况都不应意外执行代码,因为委托(delegate)将立即退出,即使它在意外时间执行也是如此。
危险的情况是调用 WindowsFormsSynchronizationContext.Send
并考虑代码将被执行:它可能不会,现在有办法知道它是否做了任何事情。
我的结论是,只要使用得当,WindowsFormsSynchronizationContext
是更好的解决方案。
在复杂的情况下,它可能会产生一些微妙的问题,但具有一个消息循环的常见 GUI 应用程序只要应用程序本身就一直存在,就永远没问题。
关于c# - 为什么 InvokeRequired 优于 WindowsFormsSynchronizationContext?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5246023/
InvokeRequired 和 somecontrol.InvokeRequired 有什么区别? 像这样, delegate void valueDelegate(string value); p
这怎么可能?我有 Windows 窗体控件,从 System.Windows.Forms.Form 派生,WebBrowser 控件包含在此窗体中。 Webbrowser 对象实例是在表单的构造函数中
我有一个事件处理程序,我想在创建对象的原始线程中处理它,这样它就不会阻塞。使用表单,很容易使用 InvokeRequired 将其强制到原始线程。但是如果你的类不是表单,你怎么做呢? 谢谢, 下午 最
我知道您必须调用才能进行跨线程更新。但是,如果不需要 Invoke,您能否像需要 Invoke 时那样调用代码? 所以不是这个: if(rtbSearchResults.InvokeRequired)
这个问题在这里已经有了答案: What's wrong with calling Invoke, regardless of InvokeRequired? (6 个答案) 关闭 1 年前。 我的同
当我想在 Windows 窗体工作时使用委托(delegate)类进行调用时,我总是必须使用 InvokeRequired。没关系。但是谁在它工作时更改了 InvokeReuqired 属性。请检查这
UI 线程偶尔会在以下方法中的语句 'if (this.InvokeRequired)' 处挂起。 你能帮我找出问题的原因吗 public void OnModuleInitializationC
我一直在编写一个 API 来促进与串行端口的通信。我正在进行一些重构和一般清理,想知道是否有办法避免以下问题。 API 中的主类能够不断从端口读取数据,并在读取字节与特定正则表达式匹配时引发包含值的事
我想让我的 getter 线程安全。当我这样做时,出现错误: public ApplicationViewModel SelectedApplication { get
我来找你是想看看是否有人知道如何解决我在迁移到 ActiveMQ 时遇到的问题。我在这个项目中使用 ActiveMQ 发送通知(在 C# 中),在完成实现后我发现了一些关于线程问题的错误。 (我知道该
这是我的代码: foreach (var pathCartella in folderList) { try { // some operation i
我一直在寻找这个问题的答案,但似乎找不到满意的答案。也许这里有人可以启发我。 我有一个 BindingList 的后代存储对 SynchronizationContext 的引用对象以便在 UI 线程
我有一个 UserControl,上面有一个名为 mTreeView 的 TreeView 控件。我可以从多个不同的线程获取数据更新,这些会导致 TreeView 被更新。为此,我设计了以下模式:所有
这个问题在这里已经有了答案: Invoke or BeginInvoke cannot be called on a control until the window handle has been
在我的应用程序中,我有一个负责所有数据库操作的类。它从主类调用,并在操作完成后使用委托(delegate)调用方法。因为它是异步的,所以我必须在我的 GUI 上使用 invoke,所以我创建了一个简单
我是一名新手程序员,所以我在这里可能完全错了,但这个问题比它应该的更让我烦恼。 这实际上是 this 的跟进问题。 公认的答案是,您必须调用 InvokeRequired 以避免一些开销,因为您有可能
这个问题在这里已经有了答案: What's wrong with calling Invoke, regardless of InvokeRequired? (6 个答案) 关闭去年。 我知道,当从
我已经痛苦地意识到需要在事件驱动的 GUI 代码中编写以下代码模式的频率,其中 private void DoGUISwitch() { // cruisin for a bruisin' t
从.NET 4.0开始,TPL可以执行异步任务。如果您正在阅读msdn,则所有与窗体/UI交互的异步操作仍将使用InvokeRequire ... Invoke()模式。 我要问的是有原因吗?据我了解
首先,我在 Window.Forms 开发方面经验不足。但是我发现 InvokeRequired 检查,对于控件,在线程应用程序中使用时有点乏味。我创建了一个静态方法,我认为它可以解决我乏味的 Inv
我是一名优秀的程序员,十分优秀!