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

Mostrar mensagens com a etiqueta Visual Studio 2005. Mostrar todas as mensagens
Mostrar mensagens com a etiqueta Visual Studio 2005. Mostrar todas as mensagens

VB.NET: Microsoft Reports – Formatações

Os Microsoft Reports permitem formatar diversas propriedades através da criação de expressões. Estas propriedades têm de ser alteradas desta forma, caso os resultados sejam dinâmicos, uma vez que não é possíveis de o fazer através do código. São diversas propriedades como BackgroundColor, ForeColor, BorderColor, FontFamily, FontStyle, TextAlign, etc, etc.

Tudo junto, e com algum bom gosto, podem-se criar relatórios bastante profissionais e de uma forma relativamente simples.

Quando seleccionamos algumas dessas propriedades, está disponível uma opção para construir uma expressão. Isso indica que é possível alterar essa propriedade de acordo com o resultado de um campo, com o número da linha, ou com outra condição qualquer. O resultado da expressão é uma String.

Depois, no Expression Editor, existem algumas constantes especificas para a propriedade, que escolhemos definir através de uma expressão. Neste caso a propriedade Color.

Finalmente, na expressão, podemos utilizar condições simples ou complexas. Este é um exemplo que verifica se o campo “ID1” tem o valor “AAA” e coloca a cor Gainsboro caso esta expressão seja verdadeira, e White caso seja falsa.

=IIF(Fields!ID1.Value="AAA","Gainsboro", “White")


Com algumas condições e manipulando diferentes propriedades, podemos obter resultados com este, onde um plano anual, tem diferentes cores para diferentes códigos.

Outro exemplo, e também para um plano anual, usando um objecto Table, pode-se seleccionar a TableRow e definir a seguinte expressão:

=IIF(RowNumber(Nothing) MOD 2 = 0,"White","LightBlue")

Isto fará com que as linhas tenham cores alternadas para uma mais fácil distinção.

São alguns exemplos de formatação em Microsoft Reports, que espero que ajudem a melhorar o resultado final dos relatórios.


VB.NET: Criar botão para exportar os Microsoft Reports

Como explicado e demonstrado em artigos anteriores, os Microsoft Reports podem exportar directamente para 3 formatos: Microsoft Excel, Adobe Acrobat e Imagem.

Para simplificar o processo de escolha ao utilizador, resolvi criar um botão personalizado, utilizando um ContextMenuStrip, que permita ao utilizador, seleccionar uma opção de exportação. Para diferenciar dos outros botões, resolvi desenhar um triângulo, indicando que irá expandir-se.

Simples, mas prático e simples de utilizar, e como poderá ter interesse para outros programadores, resolvi partilhar o código. Além disso, mostra como desenhar um objecto, através do método FillPolygon().

Para começar é necessário criar uma classe que irá herdar as propriedades de um Windows.Forms.Button

Imports System.Configuration

Public Class PopupButton
    Inherits Windows.Forms.Button

    Public WithEvents PopupButtonMenuStrip As ContextMenuStrip
    Private exportOptions As List(Of String)

#Region "Propriedades"

  
Private m_ArrowWidth As Integer
  
'''<summary>
  
''' Define o tamanho(horizontal)
    '''
</summary>
  
Public Property ArrowWidth() As Integer
         Get 
             Return
m_ArrowWidth
        End Get
        Set
(ByVal value As Integer)
            m_ArrowWidth = value
        End Set
    End Property

    Private
m_ArrowHeight As Integer
  
'''<summary>
  
''' Define o tamanho(vertical)
    '''
</summary>
  
Public Property ArrowHeight() As Integer
        Get
            Return
m_ArrowHeight
        End Get
        Set
(ByVal value As Integer)
            m_ArrowHeight = value
        End Set
    End Property


    Private
m_ArrowBrushColor As Brush
    '''<summary>
  
''' Define a cor da seta
    '''
</summary>
  
Public Property ArrowBrushColor() As Brush
        Get
            Return
m_ArrowBrushColor
        End Get
        Set
(ByVal value As Brush)
            m_ArrowBrushColor = value
        End Set
    End Property

#End Region


#Region
"Construtor"

  
Sub New()

        ' Algumas pré-definições da seta 
       
Me.ArrowWidth = 14
        Me.ArrowHeight = 14
        Me.ArrowBrushColor = Brushes.DarkGray

        ' Opções de exportação
       
exportOptions = New List(Of String)
        exportOptions.Add("Microsoft Excel (*.xls)")
        exportOptions.Add("Adobe Acrobat (*.pdf)")
        exportOptions.Add("Imagem (*.jpg)")


        Me.PopupButtonMenuStrip = New ContextMenuStrip

        ' Adiciona os itens ao menu
      
With Me.PopupButtonMenuStrip
         .Items.Add(New ToolStripMenuItem() With {.Text = exportOptions(0).ToString})
         .Items.Add(New ToolStripMenuItem() With {.Text = exportOptions(1).ToString})
         .Items.Add(New ToolStripMenuItem() With {.Text = exportOptions(2).ToString})
        End With

    End Sub

#End Region


    Enum
output
        Excel
        PDF
        Image
    End Enum


  
' Definição de um evento para quando for seleccionada uma opção
  
Public Event PopupButtonMenuClick(ByVal sender As Object, _
          ByVal e As System.Windows.Forms.ToolStripItemClickedEventArgs, _
          ByVal output As output)


    '''<summary>
  
''' Mostra o ContextMenuStrip
    '''
</summary>
  
Private Sub popupButton_Click(ByVal sender As Object, _
                ByVal e As System.EventArgs) Handles Me.Click

        Me.PopupButtonMenuStrip.Show(Me, New Point(0, Me.Height))

    End Sub


   
''' <summary>
   
''' Desenha a seta no botão alinhada à direita
    '''
</summary>
   
Private Sub popupButton_Paint(ByVal sender As Object, _ 
           ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint 

     Dim h As Integer = (Me.Height / 2) + 3 
     Dim w As Integer = Me.Width - 15 ' offset 

    
Dim points As New List(Of Point) 
     points.Add(New Point(w - (Me.ArrowWidth / 2), h - (Me.ArrowHeight / 2))) 
     points.Add(New Point(w, h)) 
     points.Add(New Point(w + (Me.ArrowWidth / 2), h - (Me.ArrowHeight / 2))) 

    e.Graphics.FillPolygon(Me.ArrowBrushColor, points.ToArray)

    End Sub


  
'''<summary>
  
''' Chama o evento PopupButtonMenuClick
    '''
</summary>
  
Private Sub PopupButtonMenuStrip_ItemClicked(ByVal sender As Object, _
            ByVal e As System.Windows.Forms.ToolStripItemClickedEventArgs) _ 
            Handles PopupButtonMenuStrip.ItemClicked

        Select Case e.ClickedItem.Text

            Case exportOptions(0).ToString
                RaiseEvent PopupButtonMenuClick(sender, e, output.Excel)

            Case exportOptions(1).ToString
                RaiseEvent PopupButtonMenuClick(sender, e, output.PDF)

            Case exportOptions(2).ToString
                RaiseEvent PopupButtonMenuClick(sender, e, output.Image)

        End Select

    End Sub


End Class

Após compilado o projecto, este botão (PopupButton), irá estar disponível na Toolbox.

Finalmente, após arrastar o botão para o Form, utiliza-se o evento PopupButtonMenuClick para verificar e definir que tipo de exportação fazer:

Private Sub btnExportar_PopupButtonMenuClick(ByVal sender As Object, _
         ByVal e As System.Windows.Forms.ToolStripItemClickedEventArgs, _
         ByVal output As PopupButton.output) _
         Handles btnExportar.PopupButtonMenuClick

    Select Case output

        Case PopupButton.output.Excel
            Debug.WriteLine("Exportar para Excel")

        Case PopupButton.output.Image
            Debug.WriteLine("Exportar para Imagem")

        Case PopupButton.output.PDF
            Debug.WriteLine("Exportar para PDF")

    End Select

End Sub


Muito simples de utilizar, mas poderá simplificar o processo de selecção do tipo de exportação sem recorrer a um Form especifico ou sem utilizar múltiplos botões.

Espero que seja útil!


VB.NET: Microsoft Reports – Custom Assemblies

Num artigo anterior, mostrei como utilizar Custom Code num relatório. Isto é muito útil se for necessário personalizar alguma coisa, mas se precisarmos de fazer esta operação em diversos relatórios ? Bem, podemos usar as Custom Assemblies.

Para usar Custom Assemblies num relatório, é apenas necessário criar um projecto do tipo Class Library, que irá originar um *.dll, e usar esta biblioteca em todos os relatórios.

Depois de criado o ficheiro/biblioteca, é necessário copiar o *.dll para as pastas Release/Debug da aplicação, e para a pasta PrivateAssemblies (no Visual Studio 2008 está normalmente em C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\)

Para este exemplo criei uma pequena classe, que irá cortar algum texto caso o tamanho do texto seja igual ou superior a 30:

Public Class rptClass

    Public Function CutText(ByVal txt As String) As String
        If
txt.Length >= 30 Then
            Return
txt.Substring(0, 26) & " ..."
      
Else
            Return
txt
        End If
    End Function


    Public Shared Function
SharedCutText(ByVal txt As String) As String
        If
txt.Length >= 30 Then
            Return
txt.Substring(0, 26) & " ..."
      
Else
            Return
txt
        End If
    End Function

End Class

Depois, é necessário adicionar uma referência no relatório para a biblioteca. Abrir o relatório, e no menu Reports, seleccionar a opção Report Properties. No separador References, seleccionar o *.dll criado.

NOTA: O nome da biblioteca (Assembly Name) irá ser usado mais tarde no código

Nesta janela existem 2 grelhas:

References: Se forem usados métodos definidos como Shared, é possível invocá-los directamente
Classes: Se não forem usados métodos Shared, é necessário criar uma nova instância da classe (tem de ser escrito directamente na grelha)

Depois, no relatório, podemos usar da seguinte forma:

Como podem ver, se for criada uma nova instância da classe, é necessário definir como =Code.<instância criada>.<nome do método>

Finalmente, e no código, é necessário definir que a classe criada (biblioteca) é Trusted Code, usando o Assembly Name usado nas referências:

Me.ReportViewer1.LocalReport.AddTrustedCodeModuleInCurrentAppDomain( _ 
    "ClassLibrary1, Version=1.0.0.1, Culture=neutral, PublicKeyToken=null")

 
PS: Como sempre, qualquer dúvida, comentário ou correcção ao artigo é sempre bem vinda!


VB.NET: Microsoft Reports – Código Personalizado

Os Microsoft Reports têm um conjunto de funções que permitem personalizar a informação que é colocada nos relatórios. Através do Expression Editor, podemos visualizar diversas funções já incorporadas, disponíveis na categoria Common Functions, e com isto, conseguir formatar, modificar, personalizar a visualização dos dados.

No entanto, é possível também a utilização de código personalizado, de modo a não nos limitamos às funções disponíveis, não obrigando à manipulação dos dados na aplicação/base de dados.

Para utilizar código personalizado no relatório, é necessário ir ás propriedades do relatório (menu ReportReport Properties) e escolher o separador Code.

Na caixa de texto disponível, colocar o código a usar.
 
Neste exemplo ilustrativo, irá ser utilizada uma função que através de um código de País, irá formatar o valor para o formato correcto (Euros ou Dólares).

Este é o código que está na imagem anterior:


Function currencyFormat(ByVal value As Double, ByVal countryCode As String) As String
    Select Case
countryCode
        Case "PT"
           
Return String.Format("{0:n} €", value)
        Case "US"
           
Return String.Format("$ {0:n}", value)
        Case Else
            Return String
.Format("{0:n}", value)
    End Select
End Function

Se editarmos o relatório com um editor XML ou mesmo com um editor de texto (por exemplo o Notepad), o código personalizado que definimos encontra-se entre as tags <Code> ... </Code> 



Para utilizar o código criado, na indicação dos campos a listar, utilizar o Expression Editor, clicando com o botão direito do rato e seleccionando “Expression …”.

Aqui, indica-se =Code.<nome da função> de modo a indicar que estamos a utilizar código personalizado. Neste caso será a seguinte expressão, onde o primeiro campo indicará o valor, e o segundo indicará o código do País.

=Code.currencyFormat(Fields!price.Value,Fields!countryCode.Value) 

Pode-se verificar também que o Intellissense não irá reconhecer a nova função, uma vez que não é compilado e não é possível interpretar o código criado. De qualquer maneira, é apenas necessário garantir que a função se encontra correctamente indicada, e os parâmetros bem definidos. 

O resultado final é um relatório com diferentes formatos para diferentes códigos de Países
 

Este foi um exemplo de como utilizar código personalizado nos relatórios e mostrar que, com este método, é possível ter relatórios muito mais flexíveis.

PS: Como sempre, qualquer dúvida, comentário ou correcção ao artigo é sempre bem vinda!


VB.NET: Microsoft Reports – Mostrando Imagens

O armazenamento de imagens em bases de dados, designado por BLOB's(binary large object), é um processo muito comum quando se trabalha com dados. Existem vantagens e desvantagens em guardar as imagens na base de dados, ou apenas o seu caminho ou URL, e se no SQL Server o processo é simples, como podem ver no artigo Inserir Imagens no SQL Server, em outras bases de dados, como o Access, o processo é mais complicado.

O objectivo deste artigo não é enumerar as vantagens e desvantagens de ambos os métodos, mas sim mostrar com se pode mostrar as imagens num relatório em ambos os métodos. Neste caso será mostrado apenas para SQL Server, e deverá ser semelhante para outras bases de dados, excepto Access, uma vez que a imagem é guardada como objecto.

Imagem na base de dados

Caso a imagem esteja guardada na base de dados, é apenas necessário inserir um controlo Image, da Toolbox, no controlo Table.



Depois, e nas propriedades do controlo, definir como Value o campo respectivo da base de dados, a Source como Database e o MIMEType adequado. Neste exemplo será seleccionado image/png.



Caminho na base de dados

Caso na base de dados apenas esteja gravado o caminho para o ficheiro ou URL, pode-se inserir um controlo Image, da Toolbox, no controlo Table, como no exemplo anterior, mas na propriedade Value indica-se: ="File://" & Nome do Campo.

Define-se também a propriedade Source como External.



Finalmente, através de código ou nas propriedade do ReportViewer, é necessário indicar que este permite a utilização de imagens externas, definindo EnableExternalImages como True.


Me.ReportViewer1.LocalReport.EnableExternalImages = True


Como podem nestes dois exemplos, para os dois métodos possível, os relatórios são muito flexíveis e permitem de uma forma bastante simples mostrar as imagens guardadas ou através dos caminhos guardados 

PS: Como sempre, qualquer dúvida, comentário ou correcção ao artigo é sempre bem vinda!


VB.NET: Microsoft Reports – Relatórios Embebidos

Os Microsoft Reports são ficheiros XML, com uma extensão diferente (*.rdlc), que guardam o esquema do relatório, imagens embebidas, código personalizado, etc. No entanto, e por serem ficheiros fáceis de editar (usando um simples editor XML ou mesmo através do Notepad), podem ser modificados, alterando com isso, e sem ser necessário compilar a aplicação, o resultado pretendido.

Isto trás algumas vantagens e, obviamente, algumas desvantagens.

Se por um lado conseguimos ver o conteúdo do ficheiro e analisar um eventual problema, não colocamos toda a aplicação num só ficheiro e não aumentamos o tamanho do executável, por outro lado, não garantimos a protecção do relatório. Estes são alguns pontos que devem ser considerados na escolha da opção a usar.

Para se utilizar um relatório embebido no executável, é necessário apenas seleccionar o relatório, na janela Soluction Explorer, e definir na propriedade Build Action como Embedded Resource.

Depois, utilizar uma função semelhante à seguinte, para extrair o relatório embebido para uma Stream.

''' <summary>
''' Extrai dos Resources da aplicação, o relatório para uma Stream
'''
</summary>
''' <param name="reportName">Nome do relatório</param>
Private Function GetReport(ByVal reportName As String) As IO.Stream

    ' Recolhe a informação da Assembly
   
Dim currentAssembly As Reflection.Assembly = _
                Reflection.Assembly.GetExecutingAssembly()

    ' Irá guarda o caminho + nome do ficheiro
   
Dim resource As String = String.Empty

    ' Verifica nos Resources se encontra o relatório pretendido
   
Dim arrResources As String() = _
                currentAssembly.GetManifestResourceNames()

    For Each resource In arrResources
        If resource.Contains(reportName) Then Exit For
    Next

   
' Coloca o relatório embebido na Stream
   
Dim resourceStream As IO.Stream = _
        currentAssembly.GetManifestResourceStream(resource)

    Return resourceStream

End Function

Finalmente, definir como nome do relatório, a Stream retornada pela função, através do método LoadReportDefinition().

Dim rptStream As IO.Stream = GetReport("rptProducts.rdlc")
Me.ReportViewer1.LocalReport.LoadReportDefinition(rptStream)


E já está … um método simples, prático, e que poderá proteger os relatório, caso seja pretendido.

PS: Como sempre, qualquer dúvida, comentário ou correcção ao artigo é sempre bem vinda!


VB.NET: Microsoft Reporting Services

Os Microsoft Reports são baseados na definição do relatório, que é na realidade um ficheiro XML, que descreve a informação e o layout do relatório, com uma extensão diferente. Pode-se criar um relatório no cliente – Client-Side Report Definition Language (*.rldc) – usando o Visual Studio, e construir excelentes relatórios para a aplicação.

O objectivo deste artigo é mostrar os passos básicos para a criação de um relatório, definir a Data Source em modo runtime, trabalhar com Parameters, incluir imagens, usar o Expression Editor, e como alimentar um SubReport e um gráfico. Finalmente irá também mostrar algumas personalizações simples ao controlo ReportViewer.

Introdução

Para começar, foi criada uma tabela em SQL com alguma informação para este exemplo. É uma lista de equipamento electrónico como PDA, computadores, etc. Da tabela criada é necessário criar um DataSet, com duas DataTables. Chamar a este DataSet “dsReport.xsd”.

A primeira DataTable, “products”, contém a lista de todos os produtos na tabela SQL. A segunda DataTable, “groupTotal”, é uma vista agrupada (Group By) com os grupos e os somatórios das quantidades. que serão usados para o SubReport e para o gráfico.

Depois disto é necessário adicionar o relatório à aplicação. Seleccionar o relatório e indicar um nome apropriado. Para o exemplo podem utilizar “rptProducts”.

Com o novo relatório criado e aberto, existe uma nova opção na barra de ferramentas Report. Seleccionar o “Page Header” e “Page footer” para mostrar estas duas secções no relatório. Depois disto vamos arrastar da Toolbox para a secção “Body” (corpo) do relatório.

DataSource

Agora é altura para definir a Data Source. No menu Report, seleccionar Data Source. Irá aparecer uma nova janela onde se pode escolher as Data Sources (DataSets) disponíveis na nossa aplicação. Seleccionar a DataSet criada.

NOTA: O nome do “Report Data Sources” pode ser renomeado, e será usado no código mais tarde.

Depois de definir a Data Source para o relatório, as DataTables estarão disponíveis no Data Source Explorer (normalmente disponível na janela da Soluction Explorer). Da tabela Produtos arrastar as colunas para o objecto Table que foi inserido na secção “Body”


O objecto Table funciona como uma folha de Excel. Pode-se unir células, alterar a cor de fundo, fontes, etc. Este exemplo utiliza um campo do tipo Moeda. Para mostrar como é simples formatar as células, clicar com o botão direito do rato sobre o campo e seleccionar Propriedades. Na janela das propriedade ir à Tab Format e definir a célula com o formato Currency.

 

Alterar o formato dos restantes campos, como negrito, títulos, etc., para obter um aspecto profissional.

Imagens

Para incluir imagens na nossa aplicação, pode-se embeber e depois usar como um logótipo (por exemplo). Pode-se também ir buscar directamente as imagens à base de dados, se estiverem armazenados como binário (Binary).

Para embeber as imagens no relatório é apenas necessário ir ao menu Report e seleccionar Embedded Images. Na nova janela seleccionar o botão New Image e escolher a imagem pretendida.


Fechar a janela e depois, na Toolbox, adicionar um controlo Image ao relatório. Nas propriedades do controlo, seleccionar a imagem adicionada da Combobox disponível na propriedade Value.

Expression Editor

Uma das novidades do Visual Studio 2008 para o Microsoft Reporting Services Expression Editor é o intellissense disponível quando se precisa de criar alguma fórmula ou expressão.

Na secção Footer, pode-se adicionar duas TextBoxes. Numa delas, iremos colocar o número da pagina e o total de páginas. Para isso, já existem fórmulas criadas na categoria Global.


Como se pode ver na imagem seguinte, pode-se usar fórmulas de VB (a maioria delas) no Expression Editor. O intellissence ajuda bastante para prevenir erros e para lembrar o sintaxe das fórmulas . Na segunda Textbox vamos colocar simplesmente a data de impressão.

 

Parâmetros (Parameters)

Pode-se utilizar Parameters para diversas coisas. Neste exemplo será apenas usado para passar informação da aplicação para o relatório.

No menu Report, seleccionar Report Parameters. Definir dois parâmetros: “ApplicationUser” e “ApplicationLevel” do tipo String.

Depois, no relatório, pode-se usar o Expression Editor para definir os parâmetros (eles serão definidos no código) para as TextBoxes. Eles estarão disponíveis na categoria Parameters.

Gráficos (Chart)

Pode-se usar vários gráficos no relatório e eles são muito fáceis de usar e alimentar com informação.

Adicionar um controlo Chart da Toolbox para a secção Body do relatório. Efectuar um duplo-clique no gráfico e irá mostrar as áreas “Data Field” e “Category Field”.

Arrastar os campos “Group” e Totals” da janela DataSource Explorer.


Pode-se também fazer isto nas propriedades do gráfico. Nesta janela pode-se também personalizar as cores das séries, legendas, efeitos 3D, filtros, eixos, etc.

Usando o código

Nos passos anteriores, foram usadas diversas Data Sources no relatório. Agora, iram ser adicionadas novas Data Sources, filtradas ou não, e essa será a informação que será visível no relatório.

Imports System.Data.SqlClient
Imports Microsoft.Reporting.WinForms

Public Class Form1

    ' Connection string
  
Private connString As String = _ 
"DataSource=.\SQLEXPRESS;AttachDbFilename='|DataDirectory|\myDatabase.mdf'”_
";
Integrated Security=True;User Instance=True"

  
''' <summary>
  
''' Evento Form load
    '''
</summary>
  
Private Sub Form1_Load(ByVal sender As Object, _
                                   ByVal e As System.EventArgs) Handles Me.Load

        Try

          
' Chama a personalização
          
Call customizeReportViewer(Me.ReportViewer1)

            ' Adiciona um novo botão
          
Call AddReportViewerButton()

            With Me.ReportViewer1.LocalReport

                ' Caminho para o relatório
              
.ReportPath = Application.StartupPath & "\..\..\rptProducts.rdlc"
              
.DataSources.Clear()

                ' Define os parameters
              
Dim parameters(1) AsReportParameter
                parameters(0) = _
                         New ReportParameter("ApplicationUser", "jpaulino")
                parameters(1) = _
                         New ReportParameter("ApplicationLevel", "Administrator")

                .SetParameters(parameters) 
            End With

          
' ----------------------------------------------------
            ' Datasource para o relatório principal (where price > 200)
            ' ----------------------------------------------------
          
Dim SQL As String = "SELECT * FROM products WHERE price > @price"
          
Using da As New SqlDataAdapter(SQL, connString)
                da.SelectCommand.Parameters.Add("@price", SqlDbType.Int).Value = 200

                Using ds As New DataSet
                    da.Fill(ds, "products")

                    ' É preciso usar o mesmo nome como foi de definido 
                    ' no Data Source Definition
                  
Dim rptDataSource As New ReportDataSource _
                                          ("dsReport_products", ds.Tables("products"))
                    Me.ReportViewer1.LocalReport.DataSources.Add(rptDataSource)

                End Using

            End Using

          
' ----------------------------------------------------
            ' Datasource para o gráfico
            ' ----------------------------------------------------
          
Dim SQL_Chart As String = "SELECT [group], SUM(quantity) AS " _ 
                   “
Total FROM products GROUP BY [group]"
          
Using da As New SqlDataAdapter(SQL_Chart, connString)
                Using ds As New DataSet
                    da.Fill(ds, "groupTotal")

                    Dim rptDataSource As New ReportDataSource("dsReport_groupTotal", _
    ds.Tables("groupTotal"))
                    Me.ReportViewer1.LocalReport.DataSources.Add(rptDataSource)

                End Using
            End Using


          
' Refresh do relatório
          
ReportViewer1.RefreshReport()


        Catch ex As Exception
            MessageBox.Show(ex.Message, My.Application.Info.Title, _
                                              MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try

    End Sub

End Class

SubReports

Pode-se usar um ou vários subreports no relatório. Para fazer isso, é necessário preencher a Data Source para cada um deles. Uma vez que não se pode aceder directamente à Data Source do relatório, é preciso definir um evento (handler) ao SubreportProcessing, e depois quando o relatório está a ser carregado, recolhe-se a informação da base de dados e preenche-se a Data Source.

Pode parecer difícil de fazer, mas na verdade é bastante simples!

Definir a Data Source para o subreport e usar um objecto Table, como no relatório principal. Adicionar os campos ao objecto Table. No relatório principal, adicionar um objecto SubReport da Toolbox e escolher o subreport criado.

Depois, no evento Form Load onde está o relatório principal, adicionar o evento para o SubreportProcessing.


AddHandler
ReportViewer1.LocalReport.SubreportProcessing, _
                  AddressOf SubreportProcessingEvent

Finalmente, no evento SubreportProcessing, define-se a nova Data Source, da mesma maneira dos anteriores.


 ''' <summary>
''' Quando o subreport está a ser carregado/processado, preenche a DataSource
''' 
</summary>
Sub SubreportProcessingEvent(ByVal sender As Object, _
                                         ByVal e As SubreportProcessingEventArgs)

     Try

         Dim
SQL As String = "SELECT [group], SUM(quantity) AS " _
             “
Total FROM products GROUP BY [group]"
        
Using da As New SqlDataAdapter(SQL, connString)
             Using ds As New DataSet
                 da.Fill(ds, "groupTotal")
                 Dim rptDataSource As New ReportDataSource _
                                           ("dsReport_groupTotal", ds.Tables("groupTotal"))
                 e.DataSources.Add(rptDataSource)
             End Using
         End Using

     Catch
ex As Exception
         MessageBox.Show(ex.Message, My.Application.Info.Title, _ 
                                      MessageBoxButtons.OK, MessageBoxIcon.Error)
     End Try

End Sub

Personalização do ReportViewer

O ReportViewer é o controlo que mostra os Microsoft Reports num Form ou numa Webpage. Pode-se personalizar a maioria dos controlos deste, para melhorar ou personalizar como pretendido.

Neste artigo, será mostrado duas personalizações simples.

Primeiro, pode-se alterar os títulos dos controlos. Pode-se também fazer outras coisas, como desabilitar itens, renomear tooltips, etc. Isto é especialmente interessante para alterar a linguagem do controlo, uma vez que está disponível apenas em Inglês.

Para isto, será criado um método recursivo que irá fazer um ciclo em todos os controlo do ReportViewer e fazer algumas alterações.

'''  <summary>
''' Ciclo em todos os controlos do ReportViewer
'''
</summary>
''' <remarks></remarks>
Sub customizeReportViewer(ByVal ctrl AsControl)

    For Each c As Control In ctrl.Controls

        ' ----------------------------------------------------
        ' Verifica o texto das labels disponíveis 
        ' ----------------------------------------------------
      
If TypeOf c Is Label Then
            Dim
lbl As Label = DirectCast(c, Label)
            Select Case lbl.Name
                Case "LblGeneratingReport"
                  
lbl.Text = "My report is loading now ... "
              
Case Else
                  
' Podem ser adicionadas mais personalizações
          
End Select
        End If

      
' ----------------------------------------------------
        ' Altera os textos da ToolStrip para Português
        ' ----------------------------------------------------
      
If TypeOf c Is ToolStrip Then
            Dim
ts AsToolStrip = DirectCast(c, ToolStrip)
            For Each item AsToolStripItem In ts.Items

                Select Case item.Text
                    Case "Find"
                      
item.Text = "Pesquisar"
                  
Case "Next"
                      
item.Text = "Próximo"
                  
Case "of"
                       
item.Text = "de"
                    
Case Else
                       
' Podem ser adicionadas mais personalizações
              
End Select
            Next
        End If

      
' Se o controlo tiver child controls
       
If c.HasChildren Then
          
customizeReportViewer(c)
        End If

    Next

End Sub

Finalmente é apenas necessário chamar o método criado no evento Form Load, onde se encontra o ReportViewer.

   ' Chama o método criado
Call customizeReportViewer(Me.ReportViewer1)

A segunda personalização mostra como incluir um novo botão na Toolstrip. Irá encontrar a ToolStrip principal do relatório e adicionar um botão alinhado à direita.

'''  <summary>
'''  Encontra a ToolStrip principal e adiciona um novo botão alinhado à direita
'''
</summary>
Sub AddReportViewerButton()

    Dim ts() As Control = Me.ReportViewer1.Controls.Find("toolStrip1", True)
    If ts IsNot Nothing Then
        Dim
tsItem As ToolStrip = DirectCast(ts(0), ToolStrip)
        Dim item As New ToolStripButton
        item.Name = "newButton"
       
item.Text = "New Button"
       
item.BackColor = Color.Green
        item.ForeColor = Color.White
        item.Alignment = ToolStripItemAlignment.Right

        tsItem.Items.Add(item)

        AddHandler item.Click, AddressOf newButtonClick
   End If

End Sub

Quando o botão for pressionado:

'''  <summary>
''' Mostra uma mensagem quando o botão no ReportViewer for pressionado
''' 
</summary>
Sub newButtonClick()
    MessageBox.Show("This is my new button!")
End Sub


Este artigo mostra os primeiros passo, e os mais importantes, para usar os Microsoft Reports, e como utilizar o código. Espero que isto ajude a utiliza-los e mostrar como é simples trabalhar com eles.


Download do Exemplo

VB.NET: AndAlso, OrElse e Using

A utilização de operadores lógicos é tão comum que um pouco por todo o código se usam operadores como o And ou o Or . No entanto o VB.NET tem novos operadores, já disponíveis nas primeiras versões .NET, que muitos não usam por desconhecimento da sua real funcionalidade.

Os operadores AndAlso e OrElse, são designados short-circuiting operators, ou seja, são operadores de rápida validação ou de circuito reduzido.

Vejamos o funcionamento de uma validação:

CONDIÇÃO 1 CONDIÇÃO 2 RESULTADO
True True True
False True False
True False False
False False False

Ou seja, qualquer condição a False irá produzir um resultado False.

O que o AndAlso faz é quando encontrar uma condição a False, decide logo e não executa a condição seguinte. Isto pode reduzir bastante, dependendo das condições, o tempo de execução da aplicação.

A seguinte função leva algum tempo a executar e retorna o resultado (True ou False) indicado no parâmetro. Serve apenas para mostrar os diferentes resultados, na utilização de diferentes operadores, nos exemplos seguintes.

''' <summary>
''' Efectua um ciclo retornando o resultado indicado no parâmetro
'''
</summary>
Private Function doTestLoop(ByVal result As Boolean) As Boolean
    For
x As Byte = 0 To 200
        Threading.Thread.Sleep(5)
        Application.DoEvents()
    Next

   
Debug.WriteLine("Executado às " & Now.ToString)
    Return result
End Function

Este exemplo executa duas vezes a função doTestLoop() e irá depois parar na condição falsa


If
doTestLoop(False) And doTestLoop(False) Then
    Stop
' Condição verdadeira
Else
    Stop
' Condição falsa
End If

Usando o operador AndAlso, e no mesmo exemplo, irá ser executado apenas a primeira condição e salta para a condição falsa, reduzindo o tempo de ciclo.

If doTestLoop(False) AndAlso doTestLoop(False) Then
    Stop
' Condição verdadeira
Else
    Stop
' Condição falsa
End If

Isto permite que se criem validações, apenas em uma linha, sem erros indesejados.

Por exemplo, o seguinte código tenta encontrar um Form na aplicação que não existe, ficando a variável frm a Nothing. Neste caso é verificada a primeira condição, que é falsa, e sai da validação, mas se utilizássemos o operador And, iria ser feita a primeira condição e depois a segunda, originando um erro "Object reference not set to an instance of an object".


Dim
frm As Form = My.Application.OpenForms("Nome não Existente")
If frm IsNot Nothing AndAlso frm.Text = "Nome Pretendido" Then
    Stop
' Condição verdadeira
End If

O mesmo acontece com o operador OrElse. Se encontrar uma condição verdadeira ele decide, sem ter de executar a próxima.

A validação de uma condição Or funciona desta forma, ou seja, qualquer condição verdadeira irá ter um resultado verdadeiro:

CONDIÇÃO 1 CONDIÇÃO 2 RESULTADO
True True True
False True True
True False True
False False False

Neste exemplo simples será executado apenas a primeira condição, saltando logo para a condição verdadeira:


If doTestLoop(True) OrElse doTestLoop(True) Then
    Stop
' Condição verdadeira
End If


Resumindo: são dois operadores que podem e devem ser utilizados, especialmente se as condições/validações podem levar algum tempo a executar. Podem ainda simplificar o código, evitando-se utilizar If’s dentro de If’s para se conseguir o mesmo resultado.


O bloco Using é uma novidade da Visual Studio 2005/.NET Framework 2.0 e permite criar um bloco, onde no final, os recursos utilizados são libertados. Isto é muito útil e prático, especialmente quando se utilizam unmanaged resources, como ligações a base de dados, ligações a ficheiros de texto, objectos COM, etc.

Os unmanaged resources, são recursos que o CLR (Common Language Runtime) não liberta e que ficam a consumir desnecessariamente recursos do sistema. Os managed resources, por sua vez, são geridos pelo CLR através do .NET Framework Garbage Collector (GC).

No seguinte exemplo, mesmo que aconteça um erro, a ligação à base de dados é fechada e limpa, porque o Using faz o .Disposal() automaticamente sem código adicional.

Dim myConnectionString As String = String.Empty

Using conn As New SqlConnection(myConnectionString)
    conn.Open()

    Using command As New SqlCommand("SELEC * FROM myTable", conn)
        command.ExecuteNonQuery()
    End Using

End Using

Como se pode ver neste exemplo simples, é declarada a variável, usada dentro do bloco e finalmente faz o Disposal da variável.


PS: Como sempre, qualquer dúvida, comentário ou correcção ao artigo é sempre bem vinda!


VB.NET: Extraindo executáveis dos Resources

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!


VB.NET: Dicas de Programação #13

ReadOnly NumericUpDown

O controlo NumericUpDown, na propriedade ReadOnly, não tem um comportamento perfeito no seu funcionamento, pois embora esteja definido como ReadOnly, é possível alterar os números através das setas (Up e Down).

Uma das formas de resolver este problema é criar um novo controlo, que herda o controlo base, e que faz o Override ao UpButton e DownButton de modo a ignorar as setas, caso a propriedade ReadOnly esteja definida.

Como a definição desta propriedade altera também a cor de fundo (BackColor), foi criada uma Shadow Property para não fazer esta alteração e podes personalizar o controlo a gosto.

O resultado é esta classe que após compilada ficará disponível na Toolbox

Class ReadOnlyNumericUpDown
    Inherits NumericUpDown

    Private m_ReadOnly As Boolean

  
'''<summary>
  
''' Cria uma propriedade para definir o NumericUpDown como ReadOnly
    ''' e como já existe uma propriedade com este nome é necessário criar
    ''' uma Shadows Property. Além disso como é uma palavra reservada tem
    ''' de ser colocada entre chavetas rectas []
    '''
</summary>
  
Public Shadows Property [ReadOnly]() As Boolean
        Get
            Return
m_ReadOnly
        End Get
        Set
(ByVal value As Boolean)
            m_ReadOnly = value
        End Set
    End Property


  
'''<summary>
  
''' Ao ser carregado no botão para cima e se for ReadOnly ignora a acção
    '''
</summary>
  
'''<remarks></remarks>
  
Public Overrides Sub UpButton()
        If Not Me.ReadOnly Then
            MyBase
.UpButton()
        End If
    End Sub


  
'''<summary>
  
''' Ao ser carregado no botão para baixo e se for ReadOnly ignora a acção
    '''
</summary>
  
'''<remarks></remarks>
  
Public Overrides Sub DownButton()
        If Not Me.ReadOnly Then
            MyBase
.DownButton()
        End If
    End Sub


  
'''<summary>
  
''' Ao ser pressionada uma tecla e se for ReadOnly ignora a acção
    '''
</summary>
   
''' <remarks></remarks>
   
Protected Overrides Sub OnKeyDown(ByVal e As System.Windows.Forms.KeyEventArgs)
        If Not Me.ReadOnly Then
            MyBase
.OnKeyDown(e)
        Else
           
e.SuppressKeyPress = True
        End If
    End Sub

End Class


Alterar o Wallpaper do Sistema Operativo

A alteração do wallpaper (ambiente de trabalho) do sistema operativo é sempre uma acção muito utilizada e que muitos aproveitam para criar pequenos aplicativos para o fazer (embora já existam várias ferramentas disponíveis).

A alteração do wallpaper pode-se fazer muito simplesmente através da API SystemParametersInfo. Um dos problemas que normalmente se vê em alguns códigos para alterar o wallpaper do computador, é a utilização de ficheiros *.jpg, *.png, etc, sem a conversão para um formato bmp (que o sistema aceita).

Fica um exemplo de como fazer esta alteração:

' Declaração da API que irá alterar o wallpaper
Private Declare Function SystemParametersInfo Lib "user32"Alias"SystemParametersInfoA"(ByVal uAction As Integer, ByVal uParam As Integer, ByVal lpvParam As String, ByVal fuWinIni As Integer) As Integer

' Definição das constantes
Private Const SPI_SETDESKWALLPAPER = 20
Private Const SPIF_UPDATEINIFILE = &H1


'''<summary>
''' Muda o wallpaper do computador
'''
</summary>
'''<param name="imagePath">Endereço completo da imagem</param>
'''<remarks></remarks>
Private Sub SetWallpaper(ByVal imagePath As String)

    ' Verifica se o ficheiro existe
  
If Not IO.File.Exists(imagePath) Then
        Throw New
Exception("O ficheiro indicado não existe!")
    End If

    Try

        Dim
imgName As String

      
' Caso o ficheiro indicado não seja um *.bmp é necessário
        ' converter para tal, de modo a que este funcione
      
If IO.Path.GetExtension(imagePath) <> ".bmp"Then

          
' Cria o ficheiro *.bmp
          
imgName = IO.Path.ChangeExtension(imagePath, "bmp")

            ' Cria uma nova image e grava como *.bmp
          
Using bm AsBitmap = Image.FromFile(imagePath)
                bm.Save(imgName, Imaging.ImageFormat.Bmp)
            End Using

        Else
          
imgName = imagePath
        End If

      
' Define o novo wallpaper
      
SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, imgName, _
                                SPIF_UPDATEINIFILE)

    Catch ex AsException
        Throw New Exception(ex.Message)
    End Try

End Sub


Para alterar o wallpaper é apenas necessário fazer:

SetWallpaper("c:\imagem.jpg")

 

PS: Como sempre, qualquer dúvida, comentário ou correcção ao artigo é sempre bem vinda!




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