使用Parallel.Invoke时,跨线程操作无效

时间:2016-10-06 06:01:23

标签: c# multithreading parallel-processing

我已经阅读了许多关于线程的解释,但我仍然很难掌握。我在我的代码中尝试了它,我得到一个错误:“附加信息:跨线程操作无效:控制'dgvLocDatabase'从一个线程访问,而不是在上创建的线程。下面是我创建的代码。它必须将来自不同源的数据添加到2个不同的datagridview。

private void btnCountRecord_Click(object sender, EventArgs e)
{
    CountRecord();

    Parallel.Invoke(
        GetDevData,
        GetPcData
        );
}



private void GetDevData()
{

    if (bIsConnected == false)
    {
        MessageBox.Show(@"Please connect the device first", @"Error");
        return;
    }

    var sdwEnrollNumber = "";
    var idwTMachineNumber = 0;
    var idwEMachineNumber = 0;
    var idwVerifyMode = 0;
    var idwInOutMode = 0;
    var idwYear = 0;
    var idwMonth = 0;
    var idwDay = 0;
    var idwHour = 0;
    var idwMinute = 0;
    var idwSecond = 0;
    var idwWorkcode = 0;

    var idwErrorCode = 0;
    var iGlCount = 0;
    var iIndex = 0;

    dgvDevDatabase.Rows.Clear();


    axCZKEM1.EnableDevice(iMachineNumber, false); //disable the device
    if (axCZKEM1.ReadGeneralLogData(iMachineNumber)) //read all the attendance records to the memory
    {
        lblProgressBar.Text = @"Loading data. Please wait...";
        progBar.Visible = true;
        progBar.Maximum = _gRecCount;
        progBar.Minimum = 1;
        progBar.Value = 1;
        progBar.Step = 1;

        while (axCZKEM1.SSR_GetGeneralLogData(iMachineNumber, out sdwEnrollNumber, out idwVerifyMode,
                   out idwInOutMode, out idwYear, out idwMonth, out idwDay, out idwHour, out idwMinute, out idwSecond, ref idwWorkcode))//get records from the memory
        {
            iGlCount++;
            var bioId = sdwEnrollNumber;
            var timeLog = idwYear + "-" + idwMonth + "-" + idwDay + " " + idwHour + ":" 
                + idwMinute + ":" + idwSecond;
            dgvDevDatabase.Rows.Add(bioId, timeLog);
            progBar.PerformStep();
        }
        if (progBar.Value == _gRecCount) lblProgressBar.Text = @"";
    }
    else
    {
        Cursor = Cursors.Default;
        axCZKEM1.GetLastError(ref idwErrorCode);

        if (idwErrorCode != 0)
        {
            MessageBox.Show(@"Reading data from device failed. ErrorCode: " + idwErrorCode, @"Error");
        }
        else
        {
            MessageBox.Show(@"No data from terminal to return", @"Error");
        }
    }
    axCZKEM1.EnableDevice(iMachineNumber, true);//enable the device
}

private void GetPcData()
        {
            var tda = new TimeLogDataAccess();
            _rdr = tda.GetAllLogs();
            while (_rdr.HasRows && _rdr.Read())
            {
                dgvLocDatabase.Rows.Add(_rdr["bio_id"].ToString(), _rdr["time_log"].ToString());
            }
        }

如果我从Parallel.Invoke中删除“GetPcData”并将其替换为Messagebox.Show(“Call me too”);,我不会收到错误,如果我只是自己运行“GetPcData” ,我也没有得到错误。所以我认为这是导致问题的Parallel.Invoke中的“GetPcData”。

你能否告诉我我做错了什么,如果你能向我解释这个parallel.invoke或线程。谢谢。

1 个答案:

答案 0 :(得分:0)

问题是,您正在尝试修改线程以外的线程中的UI,UI是从中创建的。 查看SynchronizationContext类(https://msdn.microsoft.com/en-us/library/system.threading.synchronizationcontext(v=vs.110).aspx)并尝试以下操作: 在调用新线程分配之前     SynchronizationContext.Current  变量。然后启动新线程,如果要更新UI,请通过调用

来执行此操作
myContext.Post(cb => { doSomethingOnUi(); }, null);

并查看是否可以解决您的问题。