Visual Basic em Português

Página pessoal de Jorge Paulino sobre o Visual Basic (VB.NET, ASP.NET, VB6, VBA) e algumas noticias de tecnologia

VB.NET: MergedDataGridView Control

Este artigo foi originalmente escrito para o site www.codeproject.com e agora traduzido para Português. Deste modo não terá o formato normal dos artigos disponíveis neste blog. Se quiserem ver o artigo original ou simplesmente votar, podem fazê-lo no seguinte endereço: MergedDataGridView Control 

 

Introdução
Como todos sabemos, o controlo DataGridView não nos permite juntar células e se pensarmos um pouco nisso podemos perguntar: "Porque motivo ?". Bem, a DataGridView está ligada a uma fonte de dados (mesmo que não tenhamos definido) e cada célula representa um campo de um registo, então a que registo essa célula unida pertenceria? Provavelmente foi por causa disto que a Microsoft não incluiu esta funcionalidade.

Mas às vezes podemos querer mostrar alguma informação adicional e a única solução é criando uma mensagem/formulário ou então “roubar” algum espaço ao form e preencher com textboxes, combo’s, etc

O objectivo desta personalização é mostrar alguma informação adicional numa DataGridView. Basicamente usa uma RichTextBox que é inserida na grelha e redimensionada de acordo com a linha dependente. Esta linha dependente tem de ter um número único, que servirá para  o nome da RichTextBox. Isto será então usado para redimensionar e posicionar a RichTextBox no sítio correcto.

Também inclui alguma animação de ícones e personalização da grelha para melhorar o aspecto final.

Usando o Código

Para começar é necessário incluir a classe MergedDataGridView.vb na aplicação. Depois de compilar o projecto, o controlo MergedDataGridView estará disponível na toolbox. Depois, é só arrastar para o form.

De seguida, é necessário definir algumas propriedades da MergedDataGridView:

With Me.MergedDataGridView1

    ' Define a datasource
   
.DataSource = ds.Tables(0).DefaultView

    '  Definições personalizadas para a RichTextBox
   
.StartColumnIndex = 1
    .EndColumnIndex = 7
    .RowHeight = 60

    ' Definições personalizadas para a DataGridView
   
.AllowUserToAddRows = False
   
.AllowUserToDeleteRows = False

   
.RowsDefaultCellStyle.BackColor = Color.White
    .AlternatingRowsDefaultCellStyle.BackColor = Color.AliceBlue
    .AutoResizeColumns(DataGridViewAutoSizeColumnsMode.DisplayedCells)

End With

Depois disto pode-se incluir duas DataGridViewImageColumns que serão usadas para mostrar a RichTextBox e para mostrar uma MessageBox com a informação.

' Cria uma coluna de imagens na datagrid que irá abrir a linha unica
Dim ImageColumn1 As New DataGridViewImageColumn
ImageColumn1.DefaultCellStyle.Alignment = DataGridViewContentAlignment.TopCenter
ImageColumn1.Image = My.Resources.DownArrow
ImageColumn1.Width = 25

' Cria uma coluna de imagens na datagrid que irá mostrar uma msgbox
Dim ImageColumn2 As New DataGridViewImageColumn
ImageColumn2.DefaultCellStyle.Alignment = DataGridViewContentAlignment.TopCenter
ImageColumn2.Image = My.Resources.Info
ImageColumn2.Width = 25

' Adiciona as duas colunas à DataGridView
Me.MergedDataGridView1.Columns.AddRange(New DataGridViewImageColumn() {ImageColumn1, ImageColumn2})


Finalmente, no evento CellMouseClick, detecta-se se o utilizador carregou na coluna correcta, e se sim, adiciona-se uma nova linha:

' Adiciona uma nova linha na posição correcta (e.RowIndex + 1)
Dim rowPos As Integer = e.RowIndex + 1

Dim dv AsDataView = Me.MergedDataGridView1.DataSource
Dim row AsDataRow = dv.Table.NewRow()
dv.Table.Rows.InsertAt(row, rowPos)

' Recolhe o texto das colunas escondidas que serão usadas para preencher a RichTextBox
Dim mergedRowText As New System.Text.StringBuilder
mergedRowText.AppendLine(Me.MergedDataGridView1("Description", e.RowIndex).Value.ToString)
mergedRowText.AppendLine(Me.MergedDataGridView1("Link", e.RowIndex).Value.ToString)

' Chama o método AddMergedRow
Me.MergedDataGridView1.AddMergedRow(rowPos, mergedRowText.ToString)

Ou apaga-a:

' Remove a linha da datasource
Dim rowPos As Integer = e.RowIndex + 1

Dim dv AsDataView = Me.MergedDataGridView1.DataSource
dv.Table.Rows.RemoveAt(rowPos)

' Chama o método RemoveMergedRow
Me.MergedDataGridView1.RemoveMergedRow(Me.MergedDataGridView1(0, e.RowIndex).Value)


O restante código usado no form, como podem ver no exemplo em anexo, é para validações, tratamento de erros e animação geral.

Olhando para o Controlo

O controlo tem apenas dois métodos: AddMergedRow e RemoveMergedRow, e três propriedades. As propriedades apenas guardam a indicação da coluna onde a RichTextBox irá começar e terminar, e da altura que terá.

O AddMergedRow olha para o número (ID) da linha anterior, que será a linha dependente, e cria uma nova nova RichTextBox na nova linha, usando o ID como o nome.

''' <summary>
''' Adiciona a nova linha com uma célula unida usando a RichTextBox
'''
</summary>
'''<param name="rowIndex">Index onde a linha será adicionada</param>
'''<param name="cellText">Texto que irá ser mostrado na RichTextBox</param>
'''<remarks></remarks>
Public Sub AddMergedRow(ByVal rowIndex As Integer, ByVal cellText As String)

    Try

        Me
.SuspendLayout()

        ' Define a localização/tamanho da RichTextBox
      
Dim x As Integer = Me.GetColumnDisplayRectangle(Me.StartColumnIndex, False).Left + 1
        Dim y As Integer = Me.GetRowDisplayRectangle(rowIndex, False).Top
        Dim w As Integer = Me.GetColumnDisplayRectangle(Me.EndColumnIndex, False).Right - x - 2
        Dim h As Integer = Me.GetRowDisplayRectangle(rowIndex, False).Size.Height - 1

        ' Verifica o ID da linha anterios, que será usado como nome da RichTextBox
      
Dim parentRowID As Integer = Me(0, rowIndex - 1).Value


        ' Cria a nova RichTextBox e coloca-a na posição correcta
      
Dim rtb As New RichTextBox
        With rtb
            .Name = parentRowID
            .Text = cellText
            .Multiline = True
          
.BorderStyle = BorderStyle.None
            .ScrollBars = ScrollBars.Vertical
            .ReadOnly = True
          
.Font = New Font(Me.DefaultCellStyle.Font, Me.DefaultCellStyle.Font.Style)
            .SetBounds(x, y, w, h)
        End With

        Me
.Controls.Add(rtb)


        ' Define para a RichTextBox a mesma cor que a da linha
       
rtb.BackColor = Me(0, rowIndex).InheritedStyle.BackColor

        ' Define a altura da linha
       
Me.Rows(rowIndex).Height = Me.RowHeight

        ' Define a nova imagem para a coluna (seta para cima)
       
Dim arrow As DataGridViewImageCell = Me(Me.ColumnCount - 2, rowIndex - 1)
        arrow.Value = My.Resources.UpArrow


    Catchex AsException
        Throw NewArgumentException(ex.Message)
    Finally
        Me
.ResumeLayout()
    End Try

End Sub

O segundo método, RemoveMergedRow, verifica o ID da linha anterior e remove a RichTextBox da grelha.

''' <summary>
''' Remove a RichTextBox da DataGridView
'''
</summary>
''' <param name="rowID">ID da linha</param>
''' <remarks></remarks>
Public Sub RemoveMergedRow(ByVal rowID As Integer)

    Try

       
' Procura o controlo na DataGridView e remove-o
       
Dim ctrl() As Control = Me.Controls.Find(rowID.ToString, False)
        If ctrl.Length = 1 Then
            Me
.Controls.Remove(ctrl(0))
        End If

       
' Define a nova imagem para a imagecell (seta para baixo)
       
Dim arrow As DataGridViewImageCell = Me(Me.ColumnCount - 2, Me.CurrentRow.Index)
        arrow.Value = My.Resources.DownArrow


    Catch ex As Exception
        Throw New ArgumentException(ex.Message)
    Finally
        Me
.ResumeLayout()
    End Try

End Sub

No evento Paint define-se a posição da RichTextBoxes a ajusta-se o tamanho.

Uma vez que não é simples de calcular a posição, de modo e deixar a linha em branco por baixo da linha mãe depois de ordenar a lista, foi desabilitada a ordenação no evento ColumnAdded


Pontos de Interesse

Este controlo não só possibilita mostra informação adicionar na DataGridView como também demonstra como personalizar a grelha e manipular o posicionamento nas linhas, que poderá ser útil em outros projectos.

Eu realmente espero que isto ajude a melhorar os vossos projecto ou ajudar a ter algumas novas ideias.

Download do Exemplo

8 comentários:

Luis Silva disse...

Ola, como posso eu usar isto mas a ir buscar dados a uma base de dados, nao entendi muito bem :S

jpaulino disse...

Olá Luís,

Tens de mostrar como tentaste. ´

Viste o exemplo ? Ele carregar num DataSet uma tabela que servirá para preencher a DataGridView, estando uma coluna escondida, que servirá para a nova linha.

Luis Silva disse...

Pois mas eu não percebi onde era carregado o dataset, dai a minha confusão

Luis(Queijo) disse...
Este comentário foi removido pelo autor.
Luis(Queijo) disse...

Boas jorge, estou novamente a percisar deste control xD
Mesmo que da outra vez nao tenha conseguido, o que eu queria era, mostrar os dados no gridview de uma tabela chamada "Alugueres", ate ai tudo ok, mas depois eu queria com este control mostrar a lista de maquinas que estao associadas a este alugueres e para isso faço um SELECT que pesquisa na tabela "List_Maquinas" no campo "rel_aluguer" pelo id do aluguer, isso e possivel com este control?

Jorge Paulino disse...

Luís,

O controlo que criei está preparado e pensado para mostrar mais alguma informação (como no exemplo) e não uma lista de mais resultados.

Penso que a melhor solução e mais simples também é usar outra DataGridView para mostrar essa informação (por baixo da existente).

ViMiranda disse...

onde consigo descarregar o MergedDataGridView.vb ????
forte abraço

outra coisa:
é possivel fazer que o comentário so apareça quando a linha for clicada? tipo, colocando um checkbox ou algo do tipo? obrigado

Jorge Paulino disse...

ViMiranda,

Está no exemplo disponível para download.

Sim, é possível. Eu utilizei uma imagem, mas facilmente se pode adaptar.

Mensagens Recentes



Microsoft Office Especialist

Membro da Comunidade
Experts-Exchange


Administ. da Comunidade
Portugal-a-Programar



Twitter

Artigos no CodeProject

Artigos no CodeProject

Subscrever Novidades

Endereço de Email:

Delivered by FeedBurner

Seguidores

Histórico