这是否意味着必须在每个UI控件上调用Invoke()方法?

本文关键字:Invoke 调用 方法 控件 UI 意味着 是否 | 更新日期: 2023-09-27 18:10:54

下面是一个将Insert放入数据库表的方法。我在BackGroundWorker线程的DoWork()中调用这个方法。它显然给我抛出了"跨线程操作无效……"错误。据我所知,如果要在DoWork()中访问,我可以在UI控件上使用Invoke()方法。但是,这是否意味着以下每个UI控件都必须被调用?有更好的方法来实现这一点吗?

    private void AddToOccupations()
    {
        if (dataGridViewSearch.SelectedRows.Count > 0)
        {
            foreach (DataGridViewRow datarow in dataGridViewSearch.SelectedRows)
            {
                try
                {
                    AllocationModel occupation = new AllocationModel()
                    {
                        User_ID = userID,
                        Merge_Status = (int)((MergeStatus)Enum.Parse(typeof(MergeStatus), cmbMergeStatus.SelectedItem.ToString())),
                        Start_Date = dateTimePickerFROMDate.Value,
                        Seat_Type = datarow.Cells[2].Value.ToString(),
                        Occupation_Status = cmbStatus_Type.SelectedItem.ToString(),
                        Session = datarow.Cells[3].Value.ToString(),
                        Seat_Number = (Int32)datarow.Cells[0].Value,
                        Number_of_Guests = (Int32)datarow.Cells[1].Value
                    };
                    // Call the service method 
                    var success = this.allocationService.AddToOccupation(occupation);
                    if (success)
                    {
                        // display the message box
                        MessageBox.Show(
                            Resources.Add_Occupation_Success_Message,
                            Resources.Add_Occupation_Success_Title,
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Information);
                        // Reset the screen
                        //this.Reset();
                        DoCurrentFreeSearch();
                    }
                    else
                        MessageBox.Show("No Records Inserted!");
                }
                catch (FormatException ex)
                {
                    errorMessage = "Insert Error: 'n";
                    errorMessage += ex.Message;
                    MessageBox.Show(errorMessage);
                }
            }
        }
        else
            MessageBox.Show("Warning! No Row is selected...");
    }

这是否意味着必须在每个UI控件上调用Invoke()方法?

您应该将worker代码与GUI代码分开。你在那个数据网格上没有DataSource吗?基本上,您应该首先从网格(选定的行)中获取所需的数据,并将它们从GUI代码(按钮单击或其他)传递给后台worker。然后,您可以通过BackgroundWorker.ReportProgress(它在GUI线程上执行进度事件)报告工作进度。

如果您不能将GUI代码与工作代码完全解耦,那么您将不得不使用Invoke来完成其余部分。但是,从您的代码中不清楚为什么需要这样做,ReportProgress应该足够了。

你的标题问题的一般答案是:是的。

如果一个后台工作线程需要访问一个UI项目,它只能通过Invoking的一个方法来实现。

将数据从BW放入DGV的问题最好通过以解耦的方式访问其数据源来解决。我刚刚做了一个小测试,看看我的建议是否从原来的帖子工作,它看起来很好。

因此,与位图一样,您可以创建两个DataSources作为属性;一个从后台工作器填充,一个用作DGV的Datasource

public List<SeatData> theSeats_buffer { get; set; }
public List<SeatData> theSeats_DS { get; set; }

在BW线程DoWork()中,您通过调用适当的函数void或bool getSeatData()来填充theSeats_buffer列表,当您完成工作负载时,您将数据传递到theSeats_DS,可能像这样:

theSeats_DS= new List<Cols>(); theSeats_DS.AddRange(theSeats_buffer);

同样,这个操作必须是线程安全的,可能通过锁定接收列表theSeats_DS

由于DataSource已经被重新创建,它应该在bw_RunWorkerCompleted事件中被重新分配;我这样做是正确的,同时使display panel1:

无效。
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if ((e.Cancelled == true))
    { this.tbProgress.Text += "Cancelled!";    }
    else if (!(e.Error == null))
    {  this.tbProgress.Text += ("Error: " + e.Error.Message);    }
    else
    { panel1.Invalidate(); DGV.DataSource = theSeats_DS; }
}

关于DB insert,我不知道它是如何关联的。这个答案只是关于异步地从某处获取数据并将它们发送到UI。

从DGV获取数据到数据库并不是在BW线程中发生的事情,至少不是在传入更改时被触发的那个。如果您使用DGV作为输入,并发性将是一个问题!!如果你想预定的座位在你按回车键的时候已经有人了,那就够糟糕的了。但这是无法阻止的。但是,您需要确保输入不会被传入的更改所清除。噢,要是有信号就好了。

并发是棘手的!

由于控件运行在UI线程上,而不是在后台工作线程上,因此需要调用它们的所有函数