C# - DataGridView , BindingSource e BindingNavigator


Neste artigo veremos a utilização dos componentes BindingSource, BindingNavigator e DataGridView em aplicações C#.

Sabe porque é importante você conhecer estes componentes ?

O componente BindingSource oferece a maneira mais simples e fácil de navegar através de registros em uma fonte de dados; ele foi criado justamente para simplificar o processo de vinculação com os controles relacionados a uma fonte de dados.

Podemos fazer a vinculação do BindingSource qualquer um dos seguintes objetos/Interfaces:

ICollection , IList , IListSource, IBindingList e IBindingListViewObject ,  System.Type , IEnumerable ,

O componente BindingSource veio substituir o componente CurrencyManager, e, embora você ainda possa continuar usando o CurrencyManager, o BindingSource deve ter preferência quando houve a necessidade de vincular os controles de um formulário Windows a uma fonte de dados; dessa forma o componente BindingSource permite criar um vínculo entre os controles e a fonte de dados. Ele fornece as seguintes vantagens sobre as técnicas de vinculação anteriores:

A propriedade DataSource é a propriedade padrão para a classe BindingSource e o evento padrão é o evento CurrentChanged. Além disso o BindingSource fornece métodos, propriedades e eventos como os eventos CurrentItemChanged e DataSourceChanged que permite uma certa customização.

A propriedade Positon obtêm ou define o índice para o item atual na fonte de dados atual enquanto que o método MoveLast() altera o valor atual da propriedade Position para o índice do último item na fonte de dados que é a mesma coisa que obter o valor pela propriedade Count. Ex: Count -1.

O item atual pode ser retornado através da propriedade Current, e lista inteira pode ser retornada através da propriedade List

As operações de edição são suportadas no item atual através dos métodos : Current , RemoveCurrent, EndEdit, CancelEdit, Add e AddNew.

Embora o tratamento de valores atualizados é feito automaticamente para todos os tipos de fonte de dados, a classe fornece os eventos CurrentItemChanged and DataSourceChanged, que permitem uma customização.

A fonte de dados que são vinculadas ao BindingSource podem ser percorridas e gerenciadas com a classe BindingNavigator que fornece uma interface para navegação pelos itens da lista. Embora o BindingNavigator possa ser vinculado a qualquer fonte de dados ele foi criado para ser integrado com o BindingSource através da propriedade BindingNavigator.BindingSource

Muitos membros da classe BindingSource operam na lista relacionada representada pela propriedade List, e, simplesmente referencia suas operações para lista relacionada. Desta forma quando o BindingSource esta vinculado a uma implementação customizada de IList, o comportamento dos membros podem diferir do comportamento descrito na documentação da classe.  Assim, o método RemoveAt chama IList.RemoveAt. Na documentação o método RemoveAt é descrito considerando que a implementação de IList foi corretamente implementada.

A propriedade padrão para a classe  BindingSource  é DataSource e o evento padrão é CurrentChanged.

Nota: Como o BindingSource suporta a vinculação a fonte de dados simples e a complexas, a terminologia pode ser confusa. O temo list refere-se a coleção de dados da fonte de dados , item denota um simples elemento. Para fonte de dados complexas os termos equivalentes table e row são usados

Exemplos de utilização:
//vincular o BindingSource a um componente DataGridView
this.DataGridView1.DataSource = this.clientesBindingSource1;

ou

//obter o número total de items em uma fonte de dados
int count = this.clientesBindingSource.Count;

ou

//obtem ou define um indice para o item atual
int pos = this.clientesBindingSource1.Position;

ou

//move para o último item na lista
this.bindingSource1.Position = this.bindingSource1.Count - 1;
ou
//move para o último item na lista
this.bindingSource1.Position = this.bindingSource1.MoveLast();

Usando BindingSource, BindingNavigator e DataGridView

Veremos agora um exemplo prático usando estes componentes e algumas de suas propriedades e métodos.

Se você deseja navegar através dos registros de uma fontes de dados basta vincular o componente BindingSource a fonte de dados e em seguida vincular os controles do formulário (TextBox) ao controle BindingSource. Assim poderemos usar os métodos : MoveNext(), MovePrevious(), MoveFirst(), and MoveLast() para realizar tal tarefa.

Para o exemplo deste artigo eu vou usar um banco de dados Microsoft Access que foi criado com o nome Cadastro.mdb  que estará em uma pasta c:\dados e uma tabela Clientes com a seguinte estrutura:

 Abra o Visual C# 2008 Express Edition ou o SharpDevelop 2.2 e crie uma nova aplicação do tipo Windows com o nome DataGridViewBinding;

 Neste ponto se você selecionar no menu Data a opção Add New Data Source e estabelecer uma conexão com o banco de dados Cadastro.mdb, selecionar um DataSet e escolher a tabela Clientes você criará um DataSet e a partir da janela DataSource poderá selecionar os campos e arrastar para o formulário criando assim de forma automática toda a interface para navegação pelos registros da tabela e o acesso ao banco de dados conforme pode ser visto na figura abaixo:

Observe que são criados de forma automática os objetos TableAdapter, BindingSource e BindingNavigator além do DataSet.

Mas não é isso que queremos mostrar. Queremos mostrar outra forma de obter o mesmo resultado e aproveitar e para mostrar como os componentes  BindingSource e BindingNavigator trabalham em conjunto.

Nosso objetivo será:

Vamos limpar o projeto e ficar somente com o formulário form1.cs. Agora a partir da ToolBox inclua os seguintes controles no formulário:

Vamos agora ao código do formulário clicando na opção View Code.

A primeira coisa que temos que definir é a conexão com o banco de dados, no exemplo estou usando um banco de dados Access, mas poderia usar o SQL Server.

Vamos incluir então no início do código do formulário a linha de código abaixo para podermos usar as classes para efetuar a conexão com o banco de dados Cadastro.mdb;

using System.Data.OleDb;

A seguir no interior da seção :

public partial class Form1 : Form
{

Vamos incluir o código a seguir onde estaremos definindo um objeto do tipo BindingSource:

BindingSource bs = new BindingSource();

Iremos atribuir os dados obtidos do banco de dados para o objeto bs e assim o DataGridView e o BindingNavigator podem usá-lo como fonte de dados.

Vamos agora extrair os dados da nossa base de dados.

Vamos usar o evento Load do formulário para efetuar a conexão com o banco de dados usando a seguinte linha de código:

OleDbConnection myConn = new OleDbConnection ("Provider=Microsoft.Jet.OleDb.4.0; Data Source=c:/dados/Cadastro.mdb");

Nota: O provedor para um banco de dados Access pode ser definido assim:

"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=seu.mdb;Jet OLEDB:Database Password=suasenha;";

Como tratar com banco de dados sempre é uma tarefa sujeita a erros vamos usar o bloco Try/Catch/Finally para tratar eventuais erros usando o seguinte código:

private void Form1_Load(object sender, EventArgs e)
{

string conexaoBD = "Provider=Microsoft.Jet.OleDb.4.0; Data Source=c:/dados/Cadastro.mdb"

OleDbConnection conexao = new OleDbConnection (conexaoBD);

try

{

   //abre a conexão

   conexao.Open();

 

   //define o comando sql para selecionar os dados das tabela Clientes

     OleDbCommand sql = new OleDbCommand("SELECT * from Clientes", conexao);

 

   //cria um adapter para preencher um dataset

     OleDbDataAdapter da = new OleDbDataAdapter(sql);

 

   //define um objeto DataSet
   DataSet
ds = new DataSet();

   da.Fill(ds);

 

    //atribui o dataset ao DataSource do BindingSource

    bs.DataSource = ds;

 

    //atribui o BindingSource ao BindingNavigator

    bs.DataMember = ds.Tables[0].TableName;

 

    //Atribui o BindingSource ao DataGridView

    dataGridView1.DataSource = bs;

}

catch (Exception)

{

    MessageBox.Show("erro ao obter os dados.");

}

finally

{

    conexao.Close();

}

}

Executando o projeto iremos obter o seguinte:



Agora vamos usar um recurso do BindingSource para filtrar os dados na exibição do DataGridView. Inclua um controle Combobox no formulário e ativando o ComboBox Tasks clique no link Edit Items e informe os valores 10, 20, 30 e 40.  Inclua uma Label com o texto : Exibir Clientes com idade menor ou igual a:

Agora no evento SelectedIndexChanged do Combobox inclua o código abaixo onde estamos usando a propriedade Filter do BindingSource.

private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)

{

   if (comboBox1.Text == "10")

        bs.Filter = "idade <= 10";

   if (comboBox1.Text == "20")

        bs.Filter = "idade <= 20";

   if (comboBox1.Text == "30")

        bs.Filter = "idade <= 30";

    if (comboBox1.Text == "40")

        bs.Filter = "idade <= 40";

}

A propriedade Filter obtém ou define a expressão usada para filtrar quais linhas serão exibidas.

Geralmente usada em cenários de ligação de dados complexos, a propriedade Filter permite que você exiba um subconjunto da sua fonte de dados. Somente listas subjacentes que implementam a interface IBindingListView oferece suporte a filtragem.

Quando  o filtro for não for referência nula, o BindingSource passa essa propriedade para a lista subjacente. Se você definir essa propriedade durante a inicialização de objeto, a chamada será ser adiada até depois de inicialização for concluída.

Para formar um valor de filtro, especifique o nome de uma coluna seguido por um operador e um valor para filtrar.

O valor da propriedade Filter serão mantidas quando  fonte de dados for alterada. Para interromper a filtragem de da fonte de dados, chame o método RemoveFilter

Executando o projeto iremos obter :

Inclua também um botão de comando no formulário e no seu evento Click inclua o código para remover o filtro aplicado usando a propriedade RemoveFilter:

private void button1_Click(object sender, EventArgs e)
{
      bs.RemoveFilter();
}

Ao clicar no botão o filtro será removido e todos os dados serão exibidos novamente.

Podermos implementar outros filtros, como por exemplo filtrar por nome de forma que ao digitar os caracteres de um nome em uma caixa de texto os dados serão sendo filtrados e exibidos dinamicamente no DataGridView.

Para implementar este recurso inclua uma Label com o texto : Filtrar por nome e um TextBox - txtNome - no formulário form1.cs e no evento TextChanged do TextBox inclua o código abaixo que usar a propriedade Filter:

private void textBox1_TextChanged(object sender, EventArgs e)
{
    bs.Filter = "Nome like '%" + txtNome.Text + "%'";
}

Executando projeto e digitando as letras Ma teremos:

Você pode aplicar um filtro e sobre os dados filtrados aplicar outro filtro obtendo assim como resultado os dados que foram filtrados por critérios distintos em duas etapas. No exemplo você pode filtrar a idade primeiro e depois filtrar por nome.

Podemos ainda efetuar combinações de condições para criar um filtro com múltiplos critérios sendo aplicados de uma vez. No exemplo acima podemos definir um critério para filtrar por idade e por cidade.

Vamos então incluir um controle GroupBox e no seu interior dois controles Label : Cidade e Idade e dois TextBox : txtCidade e txtIdade e um Button - btnFiltrar. Defina o leiaute conforme a figura abaixo:

 No evento Click do botão de comando Aplicar Filtro inclua o código abaixo que aplica o filtro usando dois critérios:

  1. Cidade que contenha o caractere digitado;
  2. E idade maior que a informada;
private void btnFiltrar_Click(object sender, EventArgs e)

{
   int
id = Convert.ToInt32(txtIdade.Text);

  
 bs.Filter = "cidade like '%" + txtCidade.Text + "%' AND idade > " + id;

}

Executando o projeto e aplicando o filtro para os dois critérios definidos teremos exibidos os clientes cuja idade for maior que 25 e que a cidade inicie com San;

Como o foco é mostrar como usar a propriedade Filter do BindingSource eu não estou efetuando validações, o que deve ser feito em uma aplicação de produção.

Pegue o projeto completo aqui: DataGridViewBinding.zip

Eu sei é apenas C# , mas eu gosto...

Referências:


José Carlos Macoratti