填充数据网格控件时等待消息
Wait message while populating a datagrid control
我有一个带有选项卡控件和多个选项卡的 C# WinForms 应用程序。其中一个选项卡包含一个数据网格控件 - 它只有大约 10 个元素,但数据是通过查询多个服务器填充的,因此加载速度很慢。
当我 运行 我的应用程序和 select 带有数据网格控件的选项卡时,应用程序似乎挂起,同时它试图查询所有服务器并填充网格。
我希望应用程序能够响应并显示 "please wait..." 消息,而不是挂起,该消息将在填充数据网格后消失。
我尝试做的是创建一个这样的后台工作者:
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 填充不工作?
在您的 PopulateServicesDataGrid 中,我想您正在与一个 UI 控件进行交互,但该控件不起作用,因为后台工作人员在与您的 UI 上下文不同的线程上运行。您需要制定一种机制,以 returns 您想要放入网格的信息然后返回 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.
}
方法 bw_DoWork 运行 在 ThreadPool 的另一个线程中。从其他线程访问 WinForms 对象需要同步。执行此操作的最佳方法 - 使用 AsyncOperationManager。您应该在 GUI 线程中创建 AsyncOperation 并在 PopulateServicesDataGrid 中使用它来发送或 post 结果。
另一种方法 - 通过内部准备的数据更新 DataGrid bw_RunWorkerComplete - 它已经由 BackgroundWorker 组件同步。
更现代的方式来做同样的事情——使用异步任务,但它需要基本水平的 TPL 知识。
我有一个带有选项卡控件和多个选项卡的 C# WinForms 应用程序。其中一个选项卡包含一个数据网格控件 - 它只有大约 10 个元素,但数据是通过查询多个服务器填充的,因此加载速度很慢。
当我 运行 我的应用程序和 select 带有数据网格控件的选项卡时,应用程序似乎挂起,同时它试图查询所有服务器并填充网格。
我希望应用程序能够响应并显示 "please wait..." 消息,而不是挂起,该消息将在填充数据网格后消失。
我尝试做的是创建一个这样的后台工作者:
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 填充不工作?
在您的 PopulateServicesDataGrid 中,我想您正在与一个 UI 控件进行交互,但该控件不起作用,因为后台工作人员在与您的 UI 上下文不同的线程上运行。您需要制定一种机制,以 returns 您想要放入网格的信息然后返回 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.
}
方法 bw_DoWork 运行 在 ThreadPool 的另一个线程中。从其他线程访问 WinForms 对象需要同步。执行此操作的最佳方法 - 使用 AsyncOperationManager。您应该在 GUI 线程中创建 AsyncOperation 并在 PopulateServicesDataGrid 中使用它来发送或 post 结果。
另一种方法 - 通过内部准备的数据更新 DataGrid bw_RunWorkerComplete - 它已经由 BackgroundWorker 组件同步。
更现代的方式来做同样的事情——使用异步任务,但它需要基本水平的 TPL 知识。