Saiba como trazer novos valores ao seu negócio, ao seu projecto ou à sua Equipa, a partir de ferramentas de desenvolvimento de fácil utilização, rapidez e qualidade. Com estas sessões webcasts poderá dar início a uma carreira, acrescentar uma nova competência ao seu curriculum, rever matérias ou simplesmente estrear-se num hobby divertido - agora, tudo depende de si!
Registe-se em cada uma das sessões webcast para receber o respectivo link de acesso
26 Maio 2009
Desenvolvimento de aplicações em Equipa
Como utilizar o Visual Studio 2008 e quais as ferramentas adicionais necessárias para desenvolver de forma fácil e em qualidade: testes Unitários, testes de Carga, Code Profiling, Gestor de fontes, utilitários, entre outros, para facilitar o seu desenvolvimento.
27 Maio 2009
Desenvolvimento de Aplicações Web utilizando o VS2008
Saiba como utilizar o Visual Studio 2008 na criação de aplicações Web de forma fácil e rápida, utilizando ASPX, AJAX, Dynamic Controls, Data Binding, controlos de navegação e de autenticação. Saiba como em poucos clicks pode criar uma aplicação funcional.
02 Junho 2009
Desenvolvimento de Aplicações Cliente utilizando WPF, C# e Visual Studio 2008
As aplicações instaladas no seu pc perderam interesse? Será que continuam a fazer sentido? Saiba como utilizar o Visual Studio 2008 na criação de aplicações Cliente Rico, de forma fácil e rápida, utilizando: Windows Presentation Foundation, LINQ, ClickOnce Deployment, Enterprise Library, entre outros.
03 Junho 2009
Utilize WCF para construir aplicações com uma camada reutilizável
Múltiplos clientes? Múltiplos Interfaces de trabalho? Como resolver o problema? Saiba como utilizar Windows Comunication Foundation na construção de aplicações orientadas a serviços. Orador: Pedro Rosa Developer Advisor Microsoft Portugal
Orador: Pedro Rosa
Developer Advisor
Microsoft Portugal
Quando falamos em vários registos, falamos muitas vezes em registos duplicados. A forma usual de os eliminarmos é ordenando a lista e escolher, visualmente ou através de algumas fórmulas, os registos a apagar.
Mas existem maneiras mas simples e mais práticas de o fazer, especialmente se a lista for muito grande, usando o VBA
Neste exemplo será usando um Dictionary do Microsoft Scripting Runtime que será inserido como referência. A principal vantagem de usar este objecto, é que permite pesquisar por um valor na sua colecção através de um simples método Exists(). Isto permite que se faça um ciclo em toda a lista, verifique-se se o registo já existe ou não, e caso exista indicar esse registo para apagar. Finalmente, caso o registo não exista na lista, adiciona-se.
É um processo muito mais simples e prático do que o recurso a arrays.
Para este exemplo, foi indicado que a lista a verificar seria a selecção actual, sem limite de linhas ou colunas. Caso seja necessário, pode-se alterar por uma área(range) fixa, substituindo:
For Each rng In Selection
pela área (range) que pretendemos verificar, como por exemplo:
For Each rng In Range("B5:D14")
Para implementar este pequeno exemplo é necessário abrir o editor de VBA (ALT+F11) e colocar este código associado a um botão. No editor é necessário adicionar a referência ao nosso objecto através do menu Tools –> References seleccionando depois o Microsoft Scripting Runtime.
Para testar é só seleccionar a área a verificar/apagar os registos e correr o código usando o botão.
Sub DeleteDuplicates()
Dim msg As String
msg = "Deseja apagar os registos duplicados na selecção ?"
' Confirma a intenção de continuar
If MsgBox(msg, vbYesNo + vbQuestion + vbDefaultButton2) = vbYes Then
Dim rng AsRange, rngDelete AsRange
Dim dic As New Dictionary
Dim tmpString As String
Dim x As Byte
Application.ScreenUpdating = False
For Each rng In Selection
tmpString = ""
' Faz um ciclo em todas as colunas seleccionadas
' da linha actual e guarda na variável "tmpString"
Forx = 1 ToSelection.Columns.Count
tmpString = tmpString & rng.Columns(x).Value & "|"
Next x
' Caso não esteja em branco
If tmpString <> vbNullString Then
' Verifica se está no Dictionary
If dic.Exists(tmpString) Then
' Adiciona a célula ao range a apagar
If Not rngDelete Is Nothing Then
rngDelete = Union(rngDelete, rng)
Else
rngDelete = rng
End If
Else
' Adiciona a string e a linha
dic.Add(tmpString, rng.Row)
End If
End If
Next
' Caso exista alguma coisa a apagar
If Not rngDelete Is Nothing Then
rngDelete.EntireRow.Delete
End If
Application.ScreenUpdating = True
dic = Nothing
End If
End Sub
Este exemplo mostra como eliminar registos duplicados, mas através do código apresentado é simples alterar para apenas indicar (colorir por exemplo) os registos que se encontram iguais.
Para que possam testar e modificar o exemplo aqui apresentado, podem descarregar este exemplo: DOWNLOAD
PS: Como sempre, qualquer dúvida, comentário ou correcção ao artigo é sempre bem vinda!
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
Os resources de uma aplicação permitem guardar diversa informação, como ícones, imagens, etc. Essa informação é usada normalmente dentro da própria aplicação e simplifica no desenvolvimento do código, pois temos acesso a ela através do intellissense.
No entanto, e por diversos motivos, podemos querer guardar dentro do próprio executável outro ficheiro e extrai-lo para, por exemplo, criar um instalador personalizado.
Para se conseguir isto é apenas necessário criar um novo projecto, ir às propriedades do projecto (My Properties ou menu Project – «Nome da Aplicação» Properties) e no separador Resources adicionar o executável pretendido.
Depois, no Solution Explorer, selecciona-se o executável e na janela de propriedades (Properties Window) definir na Build Action como Embedded Resource.
Depois, no código, pode-se usar uma função semelhante a esta, que irá ler o executável dos resources usando Reflection para uma Stream, e que irá depois gravar para o disco usando um FileStream.
''' <summary>
''' Extrai um ficheiro executável dos resources da aplicação
'''</summary>
'''<param name="fileName">Nome completo do ficheiro a extrair</param>
'''<returns>Localização do ficheiro extraido</returns>
'''<remarks></remarks>
Private Function GetResourceFile(ByVal fileName As String) As String
Try
' Cria um nome/localização temporária para o ficheiro. Por defeito é criado um
' ficheiro com o a extensão *.tmp e por isso é necessário alterar o para *.exe
Dim tempPath As String = IO.Path.ChangeExtension(IO.Path.GetTempFileName(), ".exe")
' Verifica o nome da aplicação (Assembly)
Dim currentAssembly As Reflection.Assembly = Reflection.Assembly.GetExecutingAssembly()
' Verifica todos os objectos disponíveis nos resources
Dim arrResources As String() = currentAssembly.GetManifestResourceNames()
For Each resource As String In arrResources
' Verifica se o resource tem o nome do ficheiro a extrair
If resource.Contains(fileName) Then
' Lê o executável dos resources para uma Stream
Using resourceStream As IO.Stream = currentAssembly.GetManifestResourceStream(resource)
' Cria um novo FileStream que irá escrever o ficheiro final
Using writer As New IO.FileStream(tempPath, IO.FileMode.Create, IO.FileAccess.Write)
Const size As Int16 = 4096
Dim bytes(size) As Byte
Dim numBytes As Int32 = 0
' Escreve todos os bytes da Stream criada, usando
' o FileStream e o método Write() num ciclo Do
Do
numBytes = resourceStream.Read(bytes, 0, size)
writer.Write(bytes, 0, numBytes)
Loop While (numBytes > 0)
End Using ' writer
End Using ' resourceStream
' Retorna a localização do ficheiro
Return tempPath
End If
Next
' Caso não tenha encontrado o ficheiro pretendido
Return String.Empty
Catch ex As Exception
Return String.Empty
End Try
End Function
Finalmente, é apenas necessário chamar a função indicando o nome do executável e, neste caso, executá-lo.
If file <> String.Empty Then
' Inicia a aplicação da localização temporária. Se fosse necessário
' podia-se copiar o ficheiro final para outra localização qualquer
Process.Start(file)
Else
MessageBox.Show("Não foi possível extrair o executável")
End If
Este exemplo, bastante simples, utiliza apenas um pequeno ficheiro, mas permite ver o funcionamento geral deste processo. Foi escolhido um executável para o exemplo mas pode ser utilizado outro tipo de ficheiros.
Exemplo do artigo: DOWNLOAD
PS: Como sempre, qualquer dúvida, comentário ou correcção ao artigo é sempre bem vinda!