Asi*_*sik 5 c# multithreading winforms
我有一个带有TreeView控件的UserControl,名为mTreeView.我可以从多个不同的线程获取数据更新,这些更新会导致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();
});
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题是,有时,在启动时,我会在mTreeView.BeginUpdate()上得到一个InvalidOperationException,说mTreeView是从一个不同于它创建的线程更新的.我在调用堆栈中返回到我的LockAndInvoke,并且看,c.InvokeRequired是真的但是其他分支已被占用!就像在调用else分支后,在另一个线程上将InvokeRequired设置为true一样.
我的方法有什么问题,我该怎么做才能防止这种情况发生?
编辑:我的同事告诉我,问题是InvokeRequired是错误的,直到创建控件,所以这就是它在启动时发生的原因.但他不知道该怎么办.有任何想法吗?
这是一个标准的穿线比赛.在创建TreeView之前,您将很快启动该线程.因此,您的代码将InvokeRequired视为false,并在创建本机控件后一瞬间失败.通过仅在窗体的Load事件触发时启动线程来修复此问题,第一个事件保证所有控件句柄都有效.
代码中的一些误解btw.使用锁是不必要的,InvokeRequired和Begin/Invoke都是线程安全的.而InvokeRequired是一种反模式.您几乎总是知道该方法将由工作线程调用.因此,只使用InvokeRequired在异常时抛出异常.哪个可以提前诊断出这个问题.
| 归档时间: |
|
| 查看次数: |
1615 次 |
| 最近记录: |