跨线程操作无效:控制从创建它的线程以外的线程访问的“lbDatabase”
本文关键字:线程 访问 lbDatabase 创建 无效 操作 控制 | 更新日期: 2023-09-27 18:34:10
我正在处理指纹,我需要执行此操作,但出现错误,但不知道如何解决
private void doVerify(object sender, DoWorkEventArgs args)
{
VerificationResult verificationResult = new VerificationResult();
for (int i = 0; i < lbDatabase.Items.Count || verificationResult.score > 0; i++)
{
lbDatabase.Invoke(new MethodInvoker(delegate { lbDatabase.SelectedItem = i; }));
verificationResult.score = _engine.Verify(((CData)lbDatabase.SelectedItem).EngineUser, 20000, out verificationResult.engineStatus);
}
args.Result = verificationResult;
}
错误:跨线程操作无效:已访问控件"lbDatabase" 从创建它的线程以外的线程
代码中有三个位置可以访问lbDatabase
。
- 循环 -
lbDatabase.Items.Count
- 设置所选项目 -
lbDatabase.SelectedItem = i
- 检索所选项目 -
lbDatabase.SelectedItem
我假设你打算写lbDatabase.SelectedIndex = i
的第二个.
只有您正在调用的第二个。因此,其他两个在后台工作线程上运行。这就是您收到错误的原因。
对 UI 元素的所有访问(读取和写入(都需要在 UI 线程上完成。
现在,由于您尝试使用后台工作线程执行此操作,因此您有一个方法,如果 UI 仅在 UI 线程上运行,该方法将冻结 UI。因此,您需要访问控件的部分在 UI 上运行,但其他所有部件都需要在后台线程上运行。
下一个问题是,调用lbDatabase.Invoke(new MethodInvoker(delegate { lbDatabase.SelectedItem = i; }));
会将指令推送到 UI,但不能保证代码会立即运行 - 实际上整个循环可能会运行并将所有调用排队。你显然希望它同步发生,但这不会发生。
查看代码,您显然只想访问lbDatabase
列表框中的所有CData
项。有一种非常简单的方法可以完成这项工作。
只需在调用后台工作线程时尝试以下操作:
backgroundWorker1.RunWorkerAsync(lbDatabase.Items.Cast<CData>().ToArray());
然后将您的doVerify
更改为:
private void doVerify(object sender, DoWorkEventArgs args)
{
CData[] items = (CData[])args.Argument;
VerificationResult verificationResult = new VerificationResult();
for (int i = 0; i < items.Length || verificationResult.score > 0; i++)
{
verificationResult.score = _engine.Verify(items[i].EngineUser, 20000, out verificationResult.engineStatus);
}
args.Result = verificationResult;
}
这个错误是非常自我解释的。你在不同的线程上运行,因此无法与控件交互。这意味着访问lbDatabase.Items.Count
已结束。
相反,如果您:
lbDatabase.Invoke((MethodInvoker)(() => {
VerificationResult verificationResult = new VerificationResult();
for (int i = 0; i < lbDatabase.Items.Count || verificationResult.score > 0; i++)
{
lbDatabase.SelectedItem = i;
verificationResult.score = _engine.Verify(((CData)lbDatabase.SelectedItem).EngineUser, 20000, out verificationResult.engineStatus);
}
args.Result = verificationResult;
}));
然后你可能会重新开始营业。现在,对控件的所有访问都排队等待在 UI 线程上运行(并且您不再在循环中间切换上下文Invoke
...成本高昂(。