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: Usando Controlos WPF em WinForms

Windows Presentation Foundation (WPF) permite criar aplicações muito ricas, muito versáteis e com muitos recursos visuais. Uma aplicação que usa WPF é normalmente composta por duas partes: um arquivo XML com características especiais chamado XAML (eXtended Aplication Markup Language, pronuncia-se “zémel”), e um código .NET (que pode ser escrito numa linguagem compatível como o VB.net ou C#).

Mas nem todos gostam de WPF para criar aplicações, até porque é necessário um processo de aprendizagem significativo, quer pelo XAML quer pela arquitectura geral de funcionamento.

Mas porquê não utilizar as potencialidades do WPF em Windows Forms?

É bastante simples utilizar WPF em Windows Forms e com isso usar todas as suas potencialidades. Muitos utilizadores queixam-se dos controlos disponíveis no Visual Studio e esta é uma oportunidade de criar os seus próprios controlos quase sem limites. Estes dois exemplos iram mostrar como incorporar um controlo WPF em Windows Forms e como fazer algumas alterações com o objectivo de melhorar visualmente os mesmos.

Para criar um controlo WPF é apenas necessário adicionar um novo item ao projecto (desde que esteja seleccionado a plataforma . NET Framework 3.0 ou superior) e seleccionar User Control (WPF)


 

Depois, para cada controlo, indicar o nome pretendido de acordo com os exemplos.

wpfPictureBox




Este controlo tem algumas personalizações com é o caso de:

  • Sombra na PictureBox
  • Possibilidade de alterar a opacidade da imagem


No editor de XAML utilizar o seguinte código:

<UserControl x:Class="wpfPictureBox"
    xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="300" Height="300">

    <!-- Definição da imagem e da sombra –>
    <Image Margin="10" x:Name="Image" Stretch="Uniform" Opacity="1">
      <Image.BitmapEffect>
            <DropShadowBitmapEffect Opacity="1" />
        </Image.BitmapEffect>
     </Image>

</UserControl>

Após compilar a aplicação ficará disponível na Toolbox o controlo wpfPictureBox. Arrastar para o Form, adicionar também uma TrackBar e utilizar o seguinte código para definir a imagem e alterar a opacidade da imagem:

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        ' Definições da TrackBar
        Me.TrackBar1.Maximum = 100
        Me.TrackBar1.Minimum = 0
        Me.TrackBar1.Value = 100 

        ' Carrega uma imagem no nosso controlo
        WpfPictureBox1.Image.Source = New Windows.Media.Imaging.BitmapImage(New Uri("c:\imagem.jpg"))

    End Sub

    ' Quando se mexe na TrackBar diminui/aumenta a opacidade da imagem
    Private Sub TrackBar1_Scroll(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TrackBar1.Scroll

        WpfPictureBox1.Image.Opacity = Me.TrackBar1.Value / 100

    End Sub

wpfComboBox




Este controlo tem algumas personalizações (algumas apenas para ilustração das potencialidades do WPF) com é o caso de:

  • Sombra na ComboBox
  • Botão dentro da lista para adicionar novos itens
  • Efeito de fundo na caixa e lista

No editor de XAML utilizar o seguinte código: 

<UserControl  x:Class="wpfComboBox" 
    xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
    xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml 
    Width="200" Height="30">

    <ComboBox x:Name="wpfCombo" Margin="5" Foreground="White" BorderBrush="White" MaxDropDownHeight="150">

        <!-- Define o efeito da sombra –>
        <ComboBox.BitmapEffect>
            <DropShadowBitmapEffect ShadowDepth="1" Opacity="1" Color="DarkSeaGreen" />
        </ComboBox.BitmapEffect>

        <!-- Define o efeito do fundo –>
        <ComboBox.Background>
            <LinearGradientBrush>

                <LinearGradientBrush.GradientStops>
                    <GradientStopCollection>
                        <GradientStop Color="DarkSeaGreen" Offset="0" />
                        <GradientStop Color="White" Offset="1" />
                    </GradientStopCollection>
                </LinearGradientBrush.GradientStops>

           </LinearGradientBrush>
        </ComboBox.Background>

        <ComboBox.Resources>
            <Style TargetType="{x:Type ComboBoxItem}">               

                <!-- Define o efeito do fundo para os itens –>
                <Setter Property="Background">
                    <Setter.Value>
                        <LinearGradientBrush>
                            <GradientStop Color="DarkSeaGreen" Offset="0"/>
                            <GradientStop Color="White" Offset="1"/>
                        </LinearGradientBrush>
                    </Setter.Value>
                </Setter>

                <!-- Define a cor do texto dos items –>
                <Setter Property="Foreground" Value="White" />

            </Style>
        </ComboBox.Resources>

         <!-- Insere um botão para criar um novo item –>
        <Button x:Name="btnCombo" Width="150" Background="White" Height="22" Foreground="DarkSeaGreen">
            <TextBlock>Inserir novo item ... </TextBlock>
        </Button>

    </ComboBox>

</UserControl>

Após compilar a aplicação ficará disponível na Toolbox o controlo wpfComboBox. Arrastar para o Form e utilizar o seguinte código para o preencher e detectar que o botão foi pressionado:

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        ' Insere alguns itens na wpfCombobox
        For x As Byte = 0 To 20
            WpfComboBox1.wpfCombo.Items.Add("Combobox Item " & x.ToString.PadLeft(2, "0"c))
        Next

        ' Define uma acção para quando for pressionado o botão da wpfComboBox
        AddHandler WpfComboBox1.btnCombo.Click, AddressOf btnComboBoxClick 

    End Sub

    Sub btnComboBoxClick()
        MessageBox.Show("Adicionar um novo item à wpfComboBox")
    End Sub

São pequenos exemplos que mostram como utilizar controlos WPF numa aplicação WinForms. Com estes controlos consegue-se personalizar bastante a aplicação e melhorar o aspecto visual.

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

 


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

ComboBox editável em uma DataGridViewComboBoxColumn

A DataGridViewComboBoxColumn é uma coluna onde estão diversas DataGridViewComboBoxCell, ou seja, caixas de selecção que permitem seleccionar um item de uma lista de itens. Esses itens podem ser definidos de diversas formas e podem mesmo estar ligados a uma fonte de dados. No entanto, e através de uma inserção normal, não é possível editar a ComboBox.

Uma das formas de o fazer é utilizando o evento EditingControlShowing para alterar o tipo de ComboBox, de modo a permitir a edição. Esta opção não está disponível no IDE como propriedade e é possível apenas consegui-lo através de código.

Este pequeno exemplo mostra como o fazer, sendo diferente se a ComboBox estiver vinculada a uma fonte de dados. No entanto este exemplo mostra o processo a seguir.

    Private dgvComboColumn As DataGridViewComboBoxColumn

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        ' Definições da ComboBoxColumn e insere alguns itens
        dgvComboColumn = New DataGridViewComboBoxColumn
        With dgvComboColumn
            .Name = "ComboBoxColumn"
            .HeaderText = "Seleccionar"
            .Items.AddRange(New Object() {"Banana", "Morango", "Laranja"})
        End With 

        ' Adiciona a ComboBoxColumn à DataGridView
        Me.DataGridView1.Columns.Add(dgvComboColumn)

    End Sub

    ' No evento EditingControlShowing vai alterar o tipo de ComboBox
    Private Sub DataGridView1_EditingControlShowing(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewEditingControlShowingEventArgs) Handles DataGridView1.EditingControlShowing

        ' Verifica se a coluna é a pretendida e define o novo tipo (DropDown)
        If Me.DataGridView1.CurrentCell.ColumnIndex = dgvComboColumn.Index Then

            Dim cb As ComboBox = DirectCast(e.Control, ComboBox)
            cb.DropDownStyle = ComboBoxStyle.DropDown

            ' Adiciona um evento para verificar se é um novo item
            AddHandler cb.Leave, AddressOf comboBoxLeave

        End If

    End Sub


   
' Quando o focus sai da ComboBox
    Sub comboBoxLeave(ByVal sender As Object, ByVal e As System.EventArgs) 

        Dim cb As ComboBox = DirectCast(sender, ComboBox)

        ' Caso o item não esteja na lista
        If Not dgvComboColumn.Items.Contains(cb.Text) Then 

            Dim msg As String = "Deseja inserir este novo item na lista ?"
            Dim result As DialogResult
            result = MessageBox.Show(msg, My.Application.Info.Title, MessageBoxButtons.YesNo, MessageBoxIcon.Question) 

            ' Caso pretenda inserir o novo item, adiciona-o
            If result = Windows.Forms.DialogResult.Yes Then
                dgvComboColumn.Items.Add(cb.Text) 

                ' Selecciona o novo item
                Me.DataGridView1("ComboBoxColumn", DataGridView1.CurrentRow.Index).Value = cb.Text

            End If

          End If

    End Sub





Comparar se duas imagens são iguais

Uma das formas de comparar se duas imagens são iguais é convertendo as imagens, utilizando o método Convert.ToBase64String(), para uma string. Este método converte um array de 8-bit inteiros para a sua representação com base em 64 dígitos.

É um método muito simples para algumas aplicações onde é necessário comparar imagens.

Atenção: não confundir com tamanho, dimensão, etc,

    ''' <summary>
    ''' Converte a imagem para base 64
    ''' </summary>
    ''' <param name="image">Imagem a converter</param>
    ''' <param name="format">Formato da imagem</param>
    Public Function ImageToBase64String(ByVal image As Image, ByVal format As Imaging.ImageFormat) As String 

        Dim base64String As String = String.Empty
        Using memory As New IO.MemoryStream()
            image.Save(memory, format)
            base64String = Convert.ToBase64String(memory.ToArray())
        End Using 

        Return base64String

    End Function

    ' Verifica se as imagens são iguais ou não
    Private Sub btnTest_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnTest.Click 

        ' Guarda as imagens em memória
        Dim img1 As Image = Image.FromFile("c:\image1.jpg")
        Dim img2 As Image = Image.FromFile("c:\image2.jpg") 

        ' Converte as imagens para base 64
        Dim base64String1 As String = ImageToBase64String(img1, Imaging.ImageFormat.Jpeg)
        Dim base64String2 As String = ImageToBase64String(img2, Imaging.ImageFormat.Jpeg) 

        ' Compara se as strings geração são iguais
        If base64String1 = base64String2 Then
            MessageBox.Show("As imagens são iguais")
        Else
            MessageBox.Show("As imagens são diferentes")
        End If 

    End Sub


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


VB.NET: Pesquisas flexíveis usando Stored Procedures

Nas pesquisas a base de dados, é frequente existirem diferentes critérios para a escolha. Se a base de dados for algo complexa e se as opções de pesquisa forem muitas, torna-se complicado definir o comando Transact SQL.

Uma das opções muito práticas e disponíveis em algumas aplicações é dar a possibilidade ao utilizador de escolha os itens que ele quer ver. Por exemplo, ver as categorias a,b,c ou ver os registos com o código x, y, z. Esta opção complica ainda mais o comando SQL, pois não se sabe o número de entradas que o utilizador pode escolher.

Para dar a ideia um pouco mais real do problema e mostrar como o resolver, será criado um exemplo muito simples onde existe uma lista de equipamentos informáticos e um histórico de movimentos. Existe uma tabela(Inventario) com todos os equipamentos, onde o campo ID é a chave primária. Este campo é utilizado na tabela InventarioHistorico como identificação do equipamento.

Neste momento já temos o exemplo descrito, e agora se quisermos mostrar apenas alguns dos equipamentos no histórico de movimentos?

Seria necessário fazer algo do género:   

CREATE PROCEDURE dbo.StoredProcedure1
           
            @num1 INT,
            @num2 INT,
            @num3 INT,
            @num4 INT
            )
AS
           SET NOCOUNT ON

            BEGIN
                        SELECT
                        FROM InventarioHistorico 
                        WHERE ID_Equipamento = @num1 OR ID_Equipamento = @num2 OR ID_Equipamento = @num3 OR ID_Equipamento = @num4

            END

No entanto isto limita a escolha de equipamentos e nunca se sabe a quantidade de itens que o utilizador escolhe. Num comando directo proderiamos fazer:

SELECT * FROM InventarioHistorico WHERE ID_Equipamento IN(2,7,8,9)

No entanto não é possível fazer o mesmo num stored procedure através de um parâmetro de uma forma directa!   

Para resolver este problema/limitação, é possível passar um parâmetro como string e criar uma função que nos converta essa string de modo a poder-mos utilizar num stored procedure.

Para iniciar, cria-se a seguinte função no SQL:
   

CREATE FUNCTION dbo.CsvToInt (@strArray VARCHAR(8000))

-- Define uma tabela temporária que irá ser usado no stored procedure
RETURNS @TemporaryTable TABLE
            (IntValue NVARCHAR(100))
AS   

            BEGIN

                        -- Define o separador que vai ser usado
                        DECLARE @separator Char(1)
                        SET @separator = ','   

                        -- Define a posição do separador
                        DECLARE @pos INT               

                        DECLARE @value VARCHAR(100) 
                        SET @strArray = @strArray + ','   

                        -- Ciclo no array enquanto existirem separadores (virgulas)
                        WHILE PATINDEX('%,%' , @strArray) <> 0 

                                  
BEGIN

                                     -- Verifica a posição do separador no array e 
                                     -- guarda o valor na variável 'value'
                                     SELECT @pos =  PATINDEX('%,%' , @strArray)
                                     SELECT @value = LEFT(@strArray, @pos - 1)

                                   
-- Insere o novo valor na tabela temporária
                                      INSERT @temporaryTable VALUES (CAST(@value AS NVARCHAR))

                                     -- Apaga do array o registo inserido na tabela
                                     SELECT @strArray = STUFF(@strArray, 1, @pos, '')

                                   END   

                        RETURN

            END

Depois, e com a função já criada, pode-se criar o seguinte stored procedure:

CREATE PROCEDURE dbo.StoredProcedure1
            (
                        -- Define um parâmetro que irá ser ser passado ao stored procedure
                        @equipamentos VARCHAR(1000) = NULL
            )
AS

            SET NOCOUNT ON           

            BEGIN

                        SELECT * FROM InventarioHistorico                       

                        /* Preenche o operador IN() com os resultado da função CsvToInt,
                           que irá separar todos os valores na variável @equipamentos */
                        WHERE ID_Equipamento IN(SELECT * FROM CsvToInt(@equipamentos))                       

            END

   

Finalmente, é apenas necessário criar um pequeno código que permita recolher a escolha do utilizador (com base em uma treeview, datagridview, checklistbox, etc), colocando esses valores separados por vírgulas, e utilizar um código semelhante ao seguinte:
   

        Dim connString As String = "Data Source=.\SQLEXPRESS;AttachDbFilename='C:\myDatabase.mdf';Integrated Security=True;User Instance=True"

        ' Define o SqlDataAdapter indicando o stored procedure e a ligação
        Using da As New SqlDataAdapter("StoredProcedure1", connString)
            da.SelectCommand.CommandType = CommandType.StoredProcedure   

            ' Define o parâmetro, indicando os valores a listar. Neste exemplo são indicados 
            ' directamente (“2,7,8,9”) mas deveriam ser o resultado de uma selecção do utilizador
            da.SelectCommand.Parameters.Add("@equipamentos", SqlDbType.VarChar).Value = "2,7,8,9"   

            ' Preenche o DataSet e a DataGridView
            Using ds As New DataSet
                da.Fill(ds)
                Me.DataGridView1.DataSource = ds.Tables(0).DefaultView
            End Using   

        End Using

   

Este pequeno exemplo mostra essencialmente como passar um parâmetro a um stored procedure e como através de uma função separar de modo a poder tornar as pesquisas muito mais flexíveis.

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