gpt4 book ai didi

c# - 奇怪的 InvokeRequired 问题

转载 作者:太空狗 更新时间:2023-10-29 22:33:30 25 4
gpt4 key购买 nike

我有一个 UserControl,上面有一个名为 mTreeView 的 TreeView 控件。我可以从多个不同的线程获取数据更新,这些会导致 TreeView 被更新。为此,我设计了以下模式:所有数据更新事件处理程序都必须获取锁,然后检查 InvokeRequired;如果是这样,请通过调用 Invoke 来完成工作。这是相关代码:

  public partial class TreeViewControl : UserControl
{
object mLock = new object();
void LockAndInvoke(Control c, Action a)
{
lock (mLock)
{
if (c.InvokeRequired)
{
c.Invoke(a);
}
else
{
a();
}
}
}

public void DataChanged(object sender, NewDataEventArgs e)
{
LockAndInvoke(mTreeView, () =>
{
// get the data
mTreeView.BeginUpdate();
// perform update
mTreeView.EndUpdate();
});
}
}

我的问题是,有时候,在启动时,我会在 mTreeView.BeginUpdate() 上得到一个 InvalidOperationException,说 mTreeView 正在从一个不同于它创建的线程的线程更新。我在调用堆栈中返回到我的 LockAndInvoke,你瞧,c.InvokeRequired 是 true 但 else 分支被采用了!就好像在采用 else 分支后,InvokeRequired 在另一个线程上被设置为 true。

我的方法有什么问题吗?我该怎么做才能避免这种情况?

编辑:我的同事告诉我,问题是在创建控件之前 InvokeRequired 为 false,所以这就是它在启动时发生的原因。不过他不确定该怎么办。有什么想法吗?

最佳答案

这是一个标准的线程竞赛。在创建 TreeView 之前,您启动线程的时间过早。因此,您的代码将 InvokeRequired 视为 false,并在一瞬间之后创建 native 控件时失败。通过仅在窗体的 Load 事件触发时启动线程来解决此问题,这是保证所有控制句柄有效的第一个事件。

顺便说一下,代码中的一些误解。使用 lock 是不必要的,InvokeRequired 和 Begin/Invoke 都是线程安全的。 InvokeRequired 是一种反模式。您几乎总是知道该方法将由工作线程调用。所以使用 InvokeRequired 只在它为 false 时抛出异常。这将允许及早诊断此问题。

关于c# - 奇怪的 InvokeRequired 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11473496/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com