跨线程操作无效:控制从创建它的线程以外的线程访问的“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

  1. 循环 - lbDatabase.Items.Count
  2. 设置所选项目 - lbDatabase.SelectedItem = i
  3. 检索所选项目 - 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...成本高昂(。