【问题标题】:Cross-thread operation not valid: Control 'lbDatabase' accessed from a thread other than the thread it was created on跨线程操作无效:控件“lbDatabase”从创建它的线程以外的线程访问
【发布时间】:2016-05-21 14:15: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” 来自创建它的线程以外的线程

【问题讨论】:

    标签: c# multithreading


    【解决方案1】:

    您的代码中有三个地方可以访问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,但不能保证代码会立即运行 - 事实上,整个循环可能会运行并将所有调用排队。您显然希望它同步发生,但这不会发生。

    查看您的代码,您显然只想访问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;
    }
    

    【讨论】:

    • 嗨,有一个非常大的问题,我们可以通过 Skype 交谈吗?此代码来自我正在使用 DigitalPersona U.are.U 4500 使用 sdk 为指纹读取器制作的项目
    • 我调用这个方法的方式是这样的:RunWorkerCompletedEventArgs taskResult = BusyForm.RunLongTask("Waiting for fingerprint ...", new DoWorkEventHandler(doVerify), false, ((CData)lbDatabase.SelectedItem).EngineUser, new EventHandler(CancelScanningHandler));
    • 那里你可以看到我是如何调用 doVerify 方法的
    • @user2461687 - 您需要显示BusyForm.RunLongTask 的代码,它会在您的问题中调用。
    • 嗯,有点大,但我会贴在帖子里
    【解决方案2】:

    这个错误是不言自明的。您在不同的线程上运行,因此您无法与控件交互。这意味着无法访问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 切换上下文。 .. 昂贵)。

    【讨论】:

    • 它给我带来了一个错误:Cannot convert lambda expression to type Delegate because it's not a delegate type
    • @user2461687 我的错。固定。
    • 它编译但是当我使用该方法时程序被冻结
    • 运行后台工作程序然后将整个代码推回 UI 线程似乎有点违反直觉。
    猜你喜欢
    • 2011-01-15
    • 2016-06-11
    • 2015-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多