VB .NET - Implementando o modo virtual do DataGridView


 Neste artigo vou mostrar como implementar o VirtualMode do controle DataGridView usando a linguagem VB .NET.

Quando você deseja exibir grandes quantidades de dados em um controle DataGridView, você pode definir a propriedade VirtualMode como true e gerenciar explicitamente a interação do controle com seu armazenamento de dados. Isso permite que você ajuste o desempenho do controle nessa situação.

O modo virtual é projetado para uso com repositórios muito grandes de dados. Quando a propriedade VirtualMode for igual a true, você cria um DataGridView com um número definido de linhas e colunas e, em seguida, invoca o evento CellValueNeeded para preencher as células.

O modo virtual requer a implementação de um cache de dados subjacente para lidar com o preenchimento, edição e exclusão das células do DataGridView com base em ações do usuário..

O DataGridView fornece vários eventos que você pode manipular para interagir com um armazenamento de dados personalizados. Neste artigo veremos o processo de implementação desses manipuladores de eventos.

No exemplo vamos usar uma fonte de dados bem simples. Em um ambiente de produção, você normalmente carrega apenas as linhas que você precisa exibir em um cache e lida com eventos do DataGridView  para interagir e atualizar o cache.

Recursos usados :

Criando o projeto no VS Community

Abra o VS Community 2015  e clique em New Project;

A seguir selecione Visual Basic -> Windows -> Windows Forms Application;

Informe o nome DataGridView_VirtualMode e clique no botão OK;

Vamos começar definindo a classe Cliente que será a nosso modelo de domínio e irá fornecer os dados para popular o DataGridView.

No menu Project clique em Add Class informe o nome Cliente e digite o código abaixo nesta classe:

Public Class Cliente
    Public Sub New()
    End Sub
    Public Sub New(ByVal _nome As String, ByVal _email As String, _fone As String, _idade As Integer)
        Nome = _nome
        Email = _email
        Telefone = _fone
        Idade = _idade
    End Sub
    Public Property Nome() As String
    Public Property Email() As String
    Public Property Telefone() As String
    Public Property Idade() As Integer
End Class

Agora vamos implementar o Datagridview usando o VirtualMode e os eventos necessários envolvidos neste processo.

1- Definindo o código inicial no formulário form1.vb

No formulário form1.vb vamos definir o código que contém uma inicialização básica, declarando algumas variáveis que serão usadas posteriormente no formulário.

Vamos definir também um método Main e definir um leiaute básico para o formulário no seu construtor.

Abaixo temos o código e resultado da execução do projeto neste estágio:

Public Class Form1
    'define um objeto do tipo DataGridView
    Private WithEvents dgvClientes As New DataGridView()

    ' Declara um ArrayList para servir como fonte de dados
    Private clientes As New System.Collections.ArrayList()

    ' Declare um objeto Cliente para armazenar dadaos para uma linha sendo editada
    Private clienteInEdit As Cliente

    ' Declare uma variável para armazenar o index da linha sendo editada
    ' O valor igual a -1 indica que não existe linha em edição
    Private linhaInEdit As Integer = -1

    ' Declare uma variável para indicar o escopo do commit
    ' Defina o valor para False para usar o comite a nível de célula
    Private linhaScopeCommit As Boolean = True

    'define o método Main() que irá abrir o formulário
    <STAThreadAttribute()>
    Public Shared Sub Main()
        Application.Run(New Form1())
    End Sub

   'no construtor do formulário vamos definir os valores de inicialização
   'e incluir o datagridview nos controles de formulário
    Public Sub New()
        ' Inicializa o formulário
        'define as dimensões
        Me.Width = 600
        Me.Height = 400
        'define o texto do formulário
        Me.Text = "Usando o DataGridView no modo Virtual"
        'preenche o form com o datagridview
        Me.dgvClientes.Dock = DockStyle.Fill
        'define a cor de fundo do datagridview
        dgvClientes.BackgroundColor = Color.BlanchedAlmond
        'incluir o datagridview nos controles do formulário
        Me.Controls.Add(Me.dgvClientes)
    End Sub
End Class

2- Definindo o código no evento Load para inicializar o datagridview e definir os dados

Agora no evento Load do formulário vamos digite o código abaixo:

  Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        ' habilita o modo virtual
        Me.dgvClientes.VirtualMode = True
        ' Adiciona colunas ao datagridview
        Dim colunaNome As New DataGridViewTextBoxColumn()
        With colunaNome
            .HeaderText = "Nome"
            .Name = "Nome"
        End With
        Dim colunaEmail As New DataGridViewTextBoxColumn()
        With colunaEmail
            .HeaderText = "Email"
            .Name = "Email"
        End With
        Dim colunaTelefone As New DataGridViewTextBoxColumn()
        With colunaTelefone
            .HeaderText = "Telefone"
            .Name = "Telefone"
        End With
        Dim colunaIdade As New DataGridViewTextBoxColumn()
        With colunaIdade
            .HeaderText = "Idade"
            .Name = "Idade"
        End With
        Me.dgvClientes.Columns.Add(colunaNome)
        Me.dgvClientes.Columns.Add(colunaEmail)
        Me.dgvClientes.Columns.Add(colunaTelefone)
        Me.dgvClientes.Columns.Add(colunaIdade)
        'define o modo de exibição das colunas
        Me.dgvClientes.AutoSizeColumnsMode =
            DataGridViewAutoSizeColumnsMode.AllCells
        ' Adiciona alguns dados a fonte de dados
        Me.clientes.Add(New Cliente("Macoratti", "macoratti@yahoo.com", "11-99850-6666", 45))
        Me.clientes.Add(New Cliente("Miriam", "mimi@hotmail.com.br", "11-8900-5200", 35))
        Me.clientes.Add(New Cliente("Jefferson", "jeffi@bol.com.br", "21-87550-1002", 25))
        Me.clientes.Add(New Cliente("Jessica", "jessicalang@hotmail.com", "61-9870-2580", 22))
        Me.clientes.Add(New Cliente("Janice", "janjan@uol.com.br", "21-8870-4509", 20))
        Me.clientes.Add(New Cliente("Larissa", "larissa@yahoo.com", "11-99850-6666", 15))
        ' Define a contagem da linha incluindo a linha para novos registros
        Me.dgvClientes.RowCount = 6
    End Sub

A figura ao lado mostra o resultado da execução do projeto neste estágio.

3- Implementar o tratamento do evento CellValueNeeded para exibir os dados no datagridview

O evento CellValueNeeded retorna o valor da células a partir da fonte de dados definida que é o objeto Cliente atualmente em edição.

Este evento ocorre sempre que o DataGridView desenha uma célula no grid.

Este evento é usado no modo virtual para popular as células com dados a partir da fonte de dados sem fazer com que as células se tornem não compartilhadas.

    Private Sub dgvClientes_CellValueNeeded(ByVal sender As Object,
    ByVal e As System.Windows.Forms.DataGridViewCellValueEventArgs) Handles dgvClientes.CellValueNeeded
        ' Se esta é a linha para novos registros nenhum valor é preciso
        If e.RowIndex = Me.dgvClientes.RowCount - 1 Then
            Return
        End If
        'define um objeto do tipo Cliente
        Dim clienteTmp As Cliente = Nothing
        ' Armazena a referencia para o objeto Cliente para a linha sendo desenhada
        If e.RowIndex = linhaInEdit Then
            clienteTmp = Me.clienteInEdit
        Else
            clienteTmp = CType(Me.clientes(e.RowIndex), Cliente)
        End If
        ' Defina o valor da célula a ser exibida usando o objeto Cliente retornado
        Select Case Me.dgvClientes.Columns(e.ColumnIndex).Name
            Case "Nome"
                e.Value = clienteTmp.Nome
            Case "Email"
                e.Value = clienteTmp.Email
            Case "Telefone"
                e.Value = clienteTmp.Telefone
            Case "Idade"
                e.Value = clienteTmp.Idade
        End Select
    End Sub

A figura ao lado mostra o resultado da execução do formulário neste estágio.

4- Implementar o tratamento do evento CellValuePushed para armazenar o valor de uma célula editada

O evento CellValuePushed ocorre no modo virtual sempre que o usuário confirma a alteração do valor de uma célula armazenando o valor na fonte de dados.

Este evento é usado para atualizar a fonte de dados. (Para retornar o valor da fonte de dados usamos o evento CellValueNeeded)

Private Sub dgvClientes_CellValuePushed(ByVal sender As Object,
    ByVal e As System.Windows.Forms.DataGridViewCellValueEventArgs) Handles dgvClientes.CellValuePushed
        'cria um objeto do tipo Cliente
        Dim clienteTmp As Cliente = Nothing
        ' Armazena a referência para o objeto CLiente para a nova linha sendo editada
        If e.RowIndex < Me.clientes.Count Then
            ' Se o usuário esta editando uma nova linha cria um novo objeto Cliente
            If Me.clienteInEdit Is Nothing Then
                Me.clienteInEdit = New Cliente(
                CType(Me.clientes(e.RowIndex), Cliente).Nome,
                CType(Me.clientes(e.RowIndex), Cliente).Email,
                CType(Me.clientes(e.RowIndex), Cliente).Telefone,
                CType(Me.clientes(e.RowIndex), Cliente).Idade)
            End If
            clienteTmp = Me.clienteInEdit
            Me.linhaInEdit = e.RowIndex
        Else
            clienteTmp = Me.clienteInEdit
        End If
        ' Define a propriedade do objeto Cliente para a célula informada
        Dim novoValor As String = TryCast(e.Value, String)
        Select Case Me.dgvClientes.Columns(e.ColumnIndex).Name
            Case "Nome"
                clienteTmp.Nome = novoValor
            Case "Email"
                clienteTmp.Email = novoValor
            Case "Telefone"
                clienteTmp.Telefone = novoValor
            Case "Idade"
                clienteTmp.Idade = novoValor
        End Select
    End Sub

5- Implementar o tratamento do evento NewRowNeeded para criar novos dados

Este evento ocorre sempre que o usuário informa um linha para novos registros permitindo que uma nova entrada seja criada na fonte de dados para uma nova linha. Permite também popular a linha com valores padrão.

    Private Sub dgvClientes_NewRowNeeded(ByVal sender As Object,
    ByVal e As System.Windows.Forms.DataGridViewRowEventArgs) Handles dgvClientes.NewRowNeeded
        ' Cria uma novo objeto Cliente quando o usuário edita a linha para novos registros
        Me.clienteInEdit = New Cliente()
        Me.linhaInEdit = Me.dgvClientes.Rows.Count - 1
    End Sub

6- Implementar o tratamento do evento RowValidated para salvar alterações

Este evento ocorre depois que uma linha teve a sua alteração finalizada ou seja quando o usuário altera a linha atual. Ele é similar ao evento Validate e é usado para realizar o processamento posterior em uma linha de valores.

   Private Sub dgvClientes_RowValidated(ByVal sender As Object,
    ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles dgvClientes.RowValidated
        ' Salva as alterações feitas em uma linha
        If e.RowIndex >= Me.clientes.Count AndAlso
        e.RowIndex <> Me.dgvClientes.Rows.Count - 1 Then
            ' Adiciona um novo objeto Cliente à fonte de dados
            Me.clientes.Add(Me.clienteInEdit)
            Me.clienteInEdit = Nothing
            Me.linhaInEdit = -1
        ElseIf (Me.clienteInEdit IsNot Nothing) AndAlso
        e.RowIndex < Me.clientes.Count Then
            ' Salva o objeto Cliente modificado na fonte de dados
            Me.clientes(e.RowIndex) = Me.clienteInEdit
            Me.clienteInEdit = Nothing
            Me.linhaInEdit = -1
        ElseIf Me.dgvClientes.ContainsFocus Then
            Me.clienteInEdit = Nothing
            Me.linhaInEdit = -1
        End If
    End Sub

7- Implementar o tratamento do evento RowDirtyStateNeeded

A implementação do evento RowDirtyStateNeeded indica se o evento CancelRowEdit irá ocorre quando o usuário pressiona a tecla ESC duas vezes no modo de edição ou uma vez fora do modo de edição.

Por padrão o evento CancelRowEdit ocorre sobre a reversão da operação em uma linha quando qualquer célula da linha atual foi modificada a menos que a propriedade QuestionEventArgs.Response seja definida como True no tratamento de evento RowDirtyStateNeeded.

Este evento é útil quando o escopo do commit dos dados for determinado em tempo de execução.

Private Sub dgvClientes_RowDirtyStateNeeded(ByVal sender As Object,
    ByVal e As System.Windows.Forms.QuestionEventArgs) Handles dgvClientes.RowDirtyStateNeeded
        If Not linhaScopeCommit Then
            ' No escopo de confirmação a nível de célula (cell-level)
            ' indica se o valor da célula atual foi modificado
            e.Response = Me.dgvClientes.IsCurrentCellDirty
        End If
    End Sub

8- Implementar o tratamento do evento CancelRowEdit para descartar os valores da linha atual

Este evento ocorre quando o usuário cancela a operação pressionando a tecla ESC duas vezes ou uma vez fora da edição. O evento não ocorre se nenhuma célula na linha atual foi modificado ou se o valor da propriedade QuestionEventArgs.Response foi definida como true no evento RowDirtyStateNeeded.

Private Sub dgvClientes_CancelRowEdit(ByVal sender As Object,
    ByVal e As System.Windows.Forms.QuestionEventArgs) Handles dgvClientes.CancelRowEdit
        If Me.linhaInEdit = Me.dgvClientes.Rows.Count - 2 AndAlso
        Me.linhaInEdit = Me.clientes.Count Then
            ' Se o usuário cancelou a edição de uma nova linha criada 
            ' substitui o objeto Cliente com um novo objeto vazio
            Me.clienteInEdit = New Cliente()
        Else
            ' Se o usuário cancelou a edição de uma linha existente
            ' libera o objeto cliente correspondente
            Me.clienteInEdit = Nothing
            Me.linhaInEdit = -1
        End If
    End Sub

8- Implementar o tratamento do evento UserDeletingRow que deleta dados

O evento UserDeletingRow ocorre sempre que o usuário deleta uma linha selecionando-a e pressionando a tecla DELETE.

Este evento deleta um objeto Cliente da fonte de dados ou descarta um objeto cliente ainda não salvo.

 Private Sub dgvClientes_UserDeletingRow(ByVal sender As Object,
    ByVal e As System.Windows.Forms.DataGridViewRowCancelEventArgs) Handles dgvClientes.UserDeletingRow
        If e.Row.Index < Me.clientes.Count Then
            ' Se o usuário deletou uma linha existente 
            ' remove o objeto Cliente correspondente da fonte de dados
            Me.clientes.RemoveAt(e.Row.Index)
        End If
        If e.Row.Index = Me.linhaInEdit Then
            ' Se o usuário deletou uma nova linha libera
            ' o objeto cliente correspondente
            Me.linhaInEdit = -1
            Me.clienteInEdit = Nothing
        End If
    End Sub

Dessa forma temos os eventos que ocorrem no modo virtual e que são necessários para realizar as operações de alteração, inclusão e exclusão de dados no DataGridView.

Assim, se você desejar usar o DataGridView no modo virtual você não deverá vincular dados ao controle usando a propriedade DataSource.

Ao invés disso você deverá trabalhar com a propriedade RowCount e fornecer o tratamento para os seguintes eventos que somente ocorrem no modo virtual:

Evento Descrição
CellValueNeeded Usado para retornar e exibir o valor da célula a partir da fonte de dados em cache. Esse evento ocorre somente para células com colunas não vinculadas.
CellValuePushed Usado para confirmar a entrada do usuário em uma célula para a fone de dados no cache.
Chame o método UpdateCellValue ao alterar um valor em uma fonte de dados em cache fora de um manipulador de eventos CellValuePushed para garantir que o valor atual será exibido no controle e para aplicar quaisquer modos de dimensionamento automáticos atualmente em vigor.
NewRowNeeded Usado para indicar a necessidade de uma nova linha na fonte de dados em cache.
RowDirtyStateNeeded Usado para determinar se uma linha possui qualquer alteração não confirmada.
CancelRowEdit Usado para indicar que uma linha deverá reverter as informações para o valores em cache.

Nota: Você deverá também inicializar manualmente as colunas do controle.

Pegue o projeto completo aqui :    DataGridView_VirtualMode.zip

Respondeu Jesus: O meu reino não é deste mundo; se o meu reino fosse deste mundo, pelejariam os meus servos, para que eu não fosse entregue aos judeus; mas agora o meu reino não é daqui.
João 18:36

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

Referências:


José Carlos Macoratti