填充数据网格控件

时间:2016-03-30 19:07:41

标签: c# winforms datagrid backgroundworker

我有一个带有选项卡控件和几个选项卡的C#WinForms应用程序。其中一个选项卡包含一个数据网格控件 - 它只有大约10个元素,但是通过查询多个服务器来填充数据,因此加载速度很慢。

当我运行我的应用程序并选择带有datagrid控件的选项卡时,应用程序似乎挂起,同时它尝试查询所有服务器并填充网格。

而不是挂起我希望应用程序能够响应并显示“请稍候......”消息,该消息将在填充数据网格后消失。

我试图做的是创建一个后台工作者:

if (tabctrl.SelectedTab == tabctrl.TabPages["tabServices"])
{

    this.dgrdServices.RowPrePaint += new DataGridViewRowPrePaintEventHandler(dgrdServices_RowPrePaint);
    this.dgrdServices.CellContentClick += new DataGridViewCellEventHandler(dgrdServices_CellClick);

    BackgroundWorker bw = new BackgroundWorker();
    lblLoading.Visible = true;
    bw.RunWorkerAsync();
    bw.DoWork += new DoWorkEventHandler(bw_DoWork);
    bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);


}

private void bw_DoWork(object sender, DoWorkEventArgs e)
{

    PopulateServicesDataGrid();
}

private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    lblLoading.Visible = false;
}

private void PopulateServicesDataGrid()
{
    int x = 0;

    foreach (Service Service in Globals.Services)
    {
        // Add a row to the datagrid for each service
        this.dgrdServices.Rows.Add();

        // Update the current service status
        Service.Status = Service.Query(Service.Server, Service.Name);
        if (Service.Status == "running")
        {
            this.dgrdServices.Rows[x].Cells[0].Value = Properties.Resources.green_dot;
            this.dgrdServices.Rows[x].Cells[4].Value = Properties.Resources.stop_enabled;
        }
        else
        {
            this.dgrdServices.Rows[x].Cells[0].Value = Properties.Resources.grey_dot;
            this.dgrdServices.Rows[x].Cells[4].Value = Properties.Resources.start_enabled;
        }

        this.dgrdServices.Rows[x].Cells[1].Value = Service.Server.ToUpper();
        this.dgrdServices.Rows[x].Cells[2].Value = Service.FreindlyName;
        this.dgrdServices.Rows[x].Cells[3].Value = Service.Status;
        this.dgrdServices.Rows[x].Cells[5].Value = "Uninstall";
        this.dgrdServices.Rows[x].Cells[6].Value = Service.Name;
        x++;
    }
}

PopulateServicesDataGrid()包含迭代某些对象并查询多个不同服务器以获取服务状态的代码。

当我尝试运行上面的内容时,虽然网格没有填充。如果我不使用后台工作程序并直接调用PopulateServicesDataGrid它确实有效(尽管应用程序挂起)。

为什么后台worker / datagrid不能正常工作?

2 个答案:

答案 0 :(得分:1)

在你的PopulateServicesDataGrid中,我想你正在与UI控件进行交互,因为后台工作程序在与UI上下文不同的线程上运行,因此无法解决问题。您需要设计一种机制来以一种方式完成工作,该方式返回您想要放入网格中的信息,然后返回到您的UI线程上下文(RunWorkerCompleted),使用您提供的信息填充网格。 DoWork的。

无论何时使用后台工作人员,您都需要拆分与UI控件的交互,并在后台工作人员完成与UI的简历交互之后。

您还在调用RunWorkerAsync之后连接事件,首先连接事件然后调用RunWorkerAsync。

使用示例进行编辑以反映评论:

基于我看到的代码,您可以如何做到这一点的粗略示例。

private void bw_DoWork(object sender, DoWorkEventArgs e)
{
     QueryServices()
}

private void QueryServices()
{
   foreach (Service Service in Globals.Services)
   {
       Service.Status = Service.Query(Service.Server, Service.Name);
   }
}

    private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        PopulateServicesDataGrid();
        lblLoading.Visible = false;
    }

    private void PopulateServicesDataGrid()
    {
        //Do everything else you are doing originally in this method minus the Service.Query calls.
    }

答案 1 :(得分:1)

方法bw_DoWork在ThreadPool的另一个线程中运行。从其他线程访问WinForms对象需要同步。最好的方法 - 使用AsyncOperationManager。您应该在GUI线程中创建AsyncOperation并在PopulateServicesDataGrid中使用它来发送或发布结果。

另一种方法 - 通过bw_RunWorkerComplete中的准备数据更新DataGrid - 它已经由BackgroundWorker组件同步。

更现代的方法 - 使用异步任务,但它需要基础级别的TPL知识。