C#
- Buscando e exibindo Registros em um DataGridView Usando
BackgroundWorker
Hoje eu vou voltar a escrever sobre o controle BackGroundWorker.
O controle BackgroundWorker pode executar tarefas com processamento intensivo em uma thread separada de forma que a interface do usuário (UI) não congela durante o processamento.
O componente BackgroundWorker componente oferece a capacidade de executar operações demoradas assincronamente ("em segundo plano"), em uma thread diferente do segmento de interface do usuário principal do seu aplicativo.
Para usar um BackgroundWorker, você simplesmente diz a ele que método deseja que seja executado em segundo plano e, em seguida, chame o método RunWorkerAsync.
A thread chamada continua a ser executada normalmente enquanto o método worker é executado de forma assíncrona. Quando o método for concluído, o BackgroundWorker alerta a thread chamada, acionando o evento RunWorkerCompleted, que contém, opcionalmente, os resultados da operação.
Desde que essas tarefas estão sendo executados em segundo plano e podem levar algum tempo, é necessário mostrar algumas mensagens personalizadas e atualizar a interface do usuário enquanto o trabalho esta em execução.
Vamos criar um projeto Windows Forms usando o Visual C# 2010 Express Edition que irá acessar um banco de dados SQL Server e exibir os dados de uma tabela em um controle DataGridView. Vamos usar os eventos do controle BackGroundWorker para exibir mensagens ao usuário durante o processamento.
Estamos usando a tabela Funcionarios do banco de dados Teste.mdf que possui a seguinte estrutura:
![]() |
Obs: Vamos definir a classe TabelaDados com os campos Id e nomeFuncionario para exibir somente os dois campos pertinentes da tabela.
Você pode usar qualquer banco de dados e tabela para preencher o controle DataGridView.
Crie então um novo projeto Windows Forms Application (menu File-> New Project) e informe o nome BackGroundWorkerExemplo;
A seguir vamos incluir a partir da ToolBox no formulário form1.cs os seguintes controles/componentes:
Disponha os controles conforme o leiaute abaixo:
![]() |
Vejamos as propriedades e métodos do controle BackGroundWorker que iremos usar em nosso projeto:
Propriedades:
Métodos:
Eventos:
1- DoWork - realiza o trabalho de execução da thread em background sendo chamado quando o método RunWorkerAsync é acionado;
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { //Logica para tarefa em background ser feita }
O DoWorkEventArgs e possui as propriedades e.Argument e e.Result:
2- ProgressChanged - reporta o progresso feito pela thread. Este evento é disparado a partir do evento DoWork usando o método ReportProgress();
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) { // Reporta o progresso do BackgroundWorker }
O ProgressChangedEventArgs contém as propriedades e.ProgressPercentage e e.UserState:
3- RunWorkerCompleted - Este evento é executado quando o BackgroundWorker terminou o a tarefa. Também é disparado quando o BackgroundWorker falhou ao realizar a tarefa atribuida ou a tarefa foi cancelada;
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { //Executado no termino de operação BackgroundTask/ Failure/ Cancellation. }
RunWorkerCompletedEventArgs e possui as seguinte propriedades:
- e.Cancelled: Indica que a operação BackgroundWorker foi cancelada;
- e.Error: Erro ocorrido no processo de execução background;
- e.Result: Indica o resultado na execução do processo em background;
Vamos declarar os seguintes namespaces no formulário:
using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.Threading;
A seguir declare a string de conexão a uma variável o para obter o total de registros:
SqlCommand Sqlcmd;
string ConnString = @"Data
Source=.\SQLEXPRESS;AttachDbFilename=C:\dados\Teste.mdf;Integrated
Security=True;Connect Timeout=30;User Instance=True";
int _TotalRegistros;
No construtor do formulário
public frmDados()
{
InitializeComponent();
// Para ativar o relatório de progresso do background worker precisamos definir esta propriedade
backgroundWorker1.WorkerReportsProgress = true;
}
|
Estamos ativando o componente backgroundWorker.
No evento Load do formulário configuramos alguns controles como o botão Cancelar, a barra de status e o controle DataGridView;
private void frmRetrive_Load(object sender, EventArgs e)
{
btnCancelar.Enabled = false;
statusStrip1.Visible = false;
toolStripStatusLabel1.Visible = false;
dataGridView1.ColumnCount = 2;
dataGridView1.Columns[0].Name = "No.";
dataGridView1.Columns[0].Width = 150;
dataGridView1.Columns[1].Width = 150;
dataGridView1.RowHeadersWidth = 21;
dataGridView1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.EnableResizing;
dataGridView1.ColumnHeadersHeight = 23;
dataGridView1.Columns[1].Name = "Nome Funcionário";
}
|
No evento Click do botão Executar usamos a propriedade IsBusy para indicar se o controle backgroundworker esta realizando uma operação assíncrona ou operação em background;
Limpamos o controle DataGridView e iniciamos a thread em background:
private void btnIniciar_Click(object sender, EventArgs e)
{
statusStrip1.Visible = true;
toolStripStatusLabel1.Visible = true;
toolStripProgressBar1.Maximum = GeTotalRegistros();
if (!backgroundWorker1.IsBusy)
{
TabelaDados TObj = new TabelaDados();
dataGridView1.Rows.Clear();
// Inicia a Thread em BackGround
backgroundWorker1.RunWorkerAsync(TObj);
btnIniciar.Enabled = false;
btnCancelar.Enabled = true;
}
}
|
No evento DoWork executamos a tarefa em segundo plano exibindo o seu processamento na barra de progresso:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
TabelaDados Obj = (TabelaDados)e.Argument;
string SqlcmdString = "SELECT id,funci_nome FROM Funcionarios";
SqlDataReader reader;
int i = 1;
try
{
using (SqlConnection conn = new SqlConnection(ConnString))
{
Sqlcmd = new SqlCommand(SqlcmdString, conn);
conn.Open();
reader = Sqlcmd.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
Obj.id = reader["id"].ToString();
Obj.nomeFuncionario = reader["funci_nome"].ToString();
// força uma delay no processamento
Thread.Sleep(2000);
// Relatorio de progresso
backgroundWorker1.ReportProgress(i,Obj);
if (backgroundWorker1.CancellationPending)
{
// Define a flag e.Cancel de forma que o evento WorkerCompleted
// saiba que o processo foi cancelado
e.Cancel = true;
backgroundWorker1.ReportProgress(0);
return;
}
i = i + 1;
}
conn.Close();
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
|
No evento RunWorkerCompleted verificamos se a tarefa foi concluída ou cancelada:
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
toolStripStatusLabel1.Text = "Cancelado pelo usuáio...";
toolStripProgressBar1.Value = 0;
}
// Verifica se ocorreu algum erro no processo em background
else if (e.Error != null)
{
toolStripStatusLabel1.Text = e.Error.Message;
}
else
{
// A tarefa em BackGround foi completada sem erros
toolStripStatusLabel1.Text = " Todos os registros foram carregados...";
}
}
|
O evento ProgressChanged exibimos os dados no controle DataGridView se a tarefa não foi cancelada:
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (!backgroundWorker1.CancellationPending)
{
//Obtem o status do usuário que enviado como parte do método ReportProgress() a partir do evento DoWork
TabelaDados Obj = (TabelaDados)e.UserState;
//Inclui os dados no dataGridView1
dataGridView1.Rows.Add(Obj.id.ToString(),Obj.nomeFuncionario.ToString());
toolStripProgressBar1.Value = e.ProgressPercentage;
toolStripStatusLabel1.Text = "Processando Linha.. " + e.ProgressPercentage.ToString() + " de " +_TotalRegistros;
}
}
|
No evento Click do botão Cancelar verificamos se o processo esta em execução e paramos a execução da thread:
private void btnCancelar_Click(object sender, EventArgs e)
{
//verifica se o processo background Process esta em execução
if (backgroundWorker1.IsBusy)
{
// Para a execução da Thread Background
backgroundWorker1.CancelAsync();
btnCancelar.Enabled = false;
btnIniciar.Enabled = true;
}
}
|
A rotina GetTotalRegistros obtém o total de registros da tabela acessada:
private int GeTotalRegistros()
{
SqlConnection con;
SqlCommand cmd;
try
{
using (con = new SqlConnection(ConnString))
{
cmd = new SqlCommand("SELECT COUNT(*) FROM Funcionarios", con);
con.Open();
_TotalRegistros = int.Parse(cmd.ExecuteScalar().ToString());
con.Close();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return _TotalRegistros;
}
|
A classe usada para criar a tabela e exibir os dados no DataGridView:
public class TabelaDados
{
public string id;
public string nomeFuncionario;
}
|
No evento FormClosing (este evento ocorre antes do formulário ser fechado) do formulário frmDados
Obs: Quando um formulário é fechado, ele é descartado, liberando todos os recursos associados ao formulário.Se você cancelar este evento, o formulário permanece aberto.Para cancelar o fechamento de um formulário, defina como true a propriedade Cancel do FormClosingEventArgs passado para o manipulador de eventos.
Nota: Lembrando também que os eventos Form.Closed e Form.Closing não são disparados quando o método Application.Exit é chamado para encerrar a aplicação.
private void frmDados_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing)
{
if (backgroundWorker1.IsBusy)
{
backgroundWorker1.CancelAsync();
btnCancelar.Enabled = false;
btnIniciar.Enabled = true;
}
}
}
|
A propriedade CloseReason retorna vários valores conforme o motivo pelo qual o formulário esta sendo fechado como fazia o VB6 com o QueryUnload.
Vejamos então quais os valores da enumeração CloseReason :
| Enumeração | Descrição do motivo do fechamento do formulário para cada valor |
| ApplicationExitCall | O fechamento esta sendo feito via chamada a Application.Exit() |
| MdiFormClosing | O formulário MDI do formulário esta sendo fechado |
| None | causas desconhecidas |
| FormOwnerClosing | O formulário proprietário esta sendo fechado |
| TaskManagerClosing | O administrador de tarefas do Windows esta fechando o formulário |
| UserClosing | O fechamento esta sendo feito via Close ou clicando no X do menu de controle |
| WindowsShutDown | O Windows esta sendo encerrado |
Se o controle backgroundworker estiver realizando uma operação assíncrona ou operação em background cancelamos a operação.
A seguir vemos o projeto em execução:
![]() |
Pegue o projeto completo
aqui:
BackGroundWorkerExemplo.zip
1Ts 4:13
Não queremos, porém, irmãos, que sejais ignorantes acerca dos que já dormem, para que não vos entristeçais como os outros que não têm esperança.1Ts 4:14
Porque, se cremos que Jesus morreu e ressurgiu, assim também aos que dormem, Deus, mediante Jesus, os tornará a trazer juntamente com ele.Referências: