繁体   English   中英

跨线程操作无效:从不是在其上创建线程的线程访问控件“ lbDatabase”

[英]Cross-thread operation not valid: Control 'lbDatabase' accessed from a thread other than the thread it was created on

我正在使用指纹,需要进行此操作,但出现错误,并且不知道如何解决

 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.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切换上下文了……代价很高)。

您在代码中有三个位置可以访问lbDatabase

  1. 循环lbDatabase.Items.Count
  2. 设置所选项目lbDatabase.SelectedItem = i
  3. 检索所选项目lbDatabase.SelectedItem

我假设在第二本上,您打算编写lbDatabase.SelectedIndex = i

您正在调用的仅第二个。 因此,其他两个正在后台工作线程上运行。 这就是为什么您得到错误。

对UI元素的所有访问(读写)都需要在UI线程上完成。

现在,由于您尝试使用后台工作人员执行此操作,因此您有一种方法可以冻结UI(如果它仅在UI线程上运行)。 因此,您需要访问控件的部件才能在UI上运行,而其他所有部件都可以在后台线程上运行。

不过,下一个问题是,调用lbDatabase.Invoke(new MethodInvoker(delegate { lbDatabase.SelectedItem = i; })); 将指令推送到UI,但是不能保证代码会立即运行-实际上,整个循环可能会运行并将所有调用排队。 您显然希望它同步发生,但是那不会发生。

看你的代码,你显然只希望访问所有的CData项目上lbDatabase列表框中。 有一种非常简单的方法可以完成这项工作。

致电后台工作人员时只需尝试以下操作:

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;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM