Banco de Dados

24 mar, 2015

WPF – salvando e recuperando imagens em um banco de dados

Publicidade

Esse não é o primeiro artigo sobre como salvar e recuperar imagens em um banco de dados SQL Server, mas ele tem algumas diferenças dos artigos anteriores. Neste artigo, vou criar uma aplicação WPF com um menu de opções onde o usuário poderá carregar um formulário Wpf para salvar e outro para recuperar imagens.

Então, neste projeto iremos usar 3 Windows (arquivos .xaml). Você não deve confundir Page com Windows em uma aplicação WPF.

As páginas WPF podem ser usadas para aplicativos de navegador XAML, você também pode carregá-las em seu próprio aplicativo usando o controle Frame, ou você pode usar um NavigationWindow e criar o equivalente a um navegador como aplicativo. Assim, uma Page não é independente e geralmente é visualizada em um container.

As janelas WPF são janelas normais WPF, que podem hospedar páginas usando um frame. As janelas podem ser exibidas de forma independente.

Recursos usados:

Definindo o modelo dados

Para armazenar as imagens vamos definir o banco de dados Cadastro.mdf e a tabela Imagens com a estrutura mostrada a seguir:

wpf_imgbd4

Criando o projeto no Visual Studio 2013 Express Windows desktop

Abra o VS 2013 Express for Windows desktop e clique em New Project. Selecione a linguagem Visual Basic ou e o template WPF Application e informe o nome Wpf_GerenciaImagens, clicando em seguida no botão OK:

wpf_imgbd1

Será criado o projeto WPF contendo uma janela MainWindow.xaml, que será a nossa janela principal.

Vamos incluir mais duas janelas no projeto: uma para salvar imagens e outra para recuperar imagens.

No menu PROJECT, clique em Add New Item e a seguir selecione o template WPF -> Window(WPF). Depois informe o nome SalvarImagem.xaml e clique no botão Add:

wpf_imgbd2

Repita o procedimento anterior e crie outra janela com o nome RecuperarImagem.xaml no projeto. Neste momento, nosso projeto será visualizado na janela Solution Explorer, exibindo a seguinte estrutura:

wpf_imgbd3

Vamos, agora, criar o menu da aplicação na janela MainWindow.xaml.

Criando o menu da aplicação

Vamos abrir o arquivo MainWindow.xaml e definir o código para criar um menu de opções. A criação é feita usando as classe Menu e MenuItem, que representam um menu e um item de menu, respectivamente.

Um Menu é uma coleção de itens de menu com um comando associado a cada um dos itens do menu. Um item de menu pode ter itens de menu filhos, chamado ‘submenus’.

Antes de definir o código, vamos criar uma pasta no projeto chamada Imagens, que irá armazenar as imagens que iremos usar.

No menu PROJECT, clique em New Folder e informe o nome Imagens. A seguir, clique com o botão direito do mouse sobre esta pasta e, a seguir, clique em Add ExistingItem e selecione as imagens.

Abaixo temos o código XAML, que define um menu Arquivos com 3 itens: Salvar Imagem, Recuperar Imagem e Sair:

wpf_imgbd5

<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Salvar e Recuperar Imagens - MENU" Height="600" Width="750" WindowStartupLocation="CenterScreen">
    <Grid>
        <DockPanel>
            <Menu DockPanel.Dock="Top" Background="Aquamarine">
                <MenuItem Header="_Arquivos" FontSize="16">
                    <MenuItem Header="_Salvar Imagem"  Click="Salvar_Click">
                        <MenuItem.Icon>
                            <Image Source="Imagens/salvar.png" />
                        </MenuItem.Icon>
                    </MenuItem>
                    <MenuItem Header="_Recuperar Imagem"  Click="Recuperar_Click">
                        <MenuItem.Icon>
                            <Image Source="Imagens/recuperar.png" />
                        </MenuItem.Icon>
                    </MenuItem>
                    <MenuItem Header="_Encerrar Programa"  Click="Sair_Click">
                        <MenuItem.Icon>
                            <Image Source="Imagens/sair.png" />
                        </MenuItem.Icon>
                    </MenuItem>
                </MenuItem>
            </Menu>
        </DockPanel>
    </Grid>
</Window>

Note que estamos definindo na propriedade Image Source o caminho da imagem que estamos usando no menu. Observe também que a janela MainWindow será exibida centralizada: WindowStartupLocation=”CenterScreen”. O código também definir os eventos Click para cada item do menu.

A seguir, abra o arquivo MainWindow.xaml.vb e defina o código que irá abrir as janelas para Salvar e Recuperar as imagens:

Class MainWindow 
    Private Sub Salvar_Click(sender As Object, e As RoutedEventArgs)
        Dim salvaImg As New SalvarImagem
        salvaImg.Show()
    End Sub
    Private Sub Recuperar_Click(sender As Object, e As RoutedEventArgs)
        Dim recupImg As New RecuperarImagem
        recupImg.Show()
    End Sub
    Private Sub Sair_Click(sender As Object, e As RoutedEventArgs)
        If MessageBox.Show("Deseja realmente encerrar o programa ?", "Confirma", MessageBoxButton.YesNo) = MessageBoxResult.Yes Then
            Application.Current.Shutdown()
        End If
    End Sub
End Class

Assim, quando o usuário clicar em um item do menu, o evento Click irá acionar o respectivo código definido acima.

Implementando as funcionalidades para salvar imagens

Abra o projeto criado e, a seguir, abra o arquivo SalvarImagem.xaml e inclua os seguintes controles a partir da ToolBox:

  • TextBox = Name=txtArquivo
  • Button = btnProcurar
  • Button = btnSalvar
  • Button = btnSair
  • Image = imgArquivo
  • Label = lblmsg

Defina os controles conforme o leiaute da figura abaixo:

wpf_imgbd6

O código XAML gerado é visto abaixo:

<Window x:Class="SalvarImagem"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Salvar Imagens" Height="500" Width="600" WindowStartupLocation="CenterScreen">
    <Grid Background="Aqua">
        <TextBox x:Name="txtArquivo" HorizontalAlignment="Left" Height="23" Margin="51,374,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="432"/>
        <Button x:Name="btnProcurar" Content="Procurar" HorizontalAlignment="Left" Margin="488,374,0,0" VerticalAlignment="Top" Width="75" Background="#FF9A9AC1" Click="btnProcurar_Click"/>
        <Button x:Name="btnSalvar" Content="Salvar a imagem no Banco de dados" HorizontalAlignment="Left" Margin="51,402,0,0" VerticalAlignment="Top" Width="432" Background="#FF9898CF"  Click="btnSalvar_Click"/>
        <Button x:Name="btnSair" Content="Sair" HorizontalAlignment="Left" Margin="488,402,0,0" VerticalAlignment="Top" Width="75" Background="#FFAEAED6" Click="btnSair_Click"/>
        <Image x:Name="imgArquivo" HorizontalAlignment="Left" Height="309" Margin="51,29,0,0" VerticalAlignment="Top" Width="432" ToolTip="Selecione a imagem para Salvar" />
        <Label x:Name="lblmsg" Content="" HorizontalAlignment="Left" Margin="51,429,0,0" VerticalAlignment="Top" Width="432" Height="30"/>
    </Grid>
</Window>

Observe que a janela SalvarImagem será exibida centralizada: WindowStartupLocation=”CenterScreen” e que definimos os eventos Click para cada controle Button.

Vamos declarar os seguintes namespaces que iremos usar nesta janela:

  • Imports Microsoft.Win32
  • Imports System.IO
  • Imports System.Data.SqlClient
  • Imports System.Data

Agora vamos definir o código em cada um dos eventos Click.

1. Código do evento Click do botão Procurar:

Private Sub btnProcurar_Click(sender As Object, e As RoutedEventArgs)
        lblmsg.Content = ""
        imgArquivo.Source = Nothing
        Dim FileDialog As New OpenFileDialog
        Try
            FileDialog.Title = "Selecione um Arquivo"
            FileDialog.InitialDirectory = ""
            FileDialog.Filter = "Image Files (*.gif,*.jpg,*.jpeg,*.bmp,*.png)|*.gif;*.jpg;*.jpeg;*.bmp;*.png"
            FileDialog.FilterIndex = 1
            FileDialog.ShowDialog()

            txtArquivo.Text = FileDialog.FileName()
            lblmsg.Content = NomeArquivo(txtArquivo.Text.Trim)

            Dim bmp As New BitmapImage(New Uri(txtArquivo.Text.Trim))
            If bmp.Width < 484 And bmp.Height < 268 Then
                imgArquivo.Stretch = Stretch.None
                imgArquivo.VerticalAlignment = Windows.VerticalAlignment.Center
                imgArquivo.HorizontalAlignment = Windows.HorizontalAlignment.Center
                imgArquivo.Source = bmp
            Else
                imgArquivo.Stretch = Stretch.Uniform
                imgArquivo.VerticalAlignment = Windows.VerticalAlignment.Center
                imgArquivo.HorizontalAlignment = Windows.HorizontalAlignment.Center
                imgArquivo.Source = bmp
            End If
        Catch ex As Exception
            lblmsg.Content = "Você não selecionou nenhum arquivo Imagem..."
        End Try
    End Sub

Este código abre uma caixa de diálogo que permite selecionar uma imagem, exibindo-a a seguir no controle PictureBox –  imgArquivo – do formulário:

wpf_imgbd7

O código utiliza o método NomeArquivo(), cujo objetivo é apenas extrair o home do arquivo do caminho completo de sua localização:

Private Function NomeArquivo(ByVal Pth As String) As String
        Dim posicaoBarra As Integer = Pth.LastIndexOf("\")
        Dim _nomeArquivo As String = Pth.Substring(posicaoBarra + 1)
        Return _nomeArquivo
  End Function

Após selecionar a imagem, o usuário clica no botão ‘Salvar a imagem no banco de dados” para armazenar a imagem na tabela Imagens:

Private Sub btnSalvar_Click(sender As Object, e As RoutedEventArgs)
        Try
            lblmsg.Content = ""
            Dim Stream As FileStream
            Dim Reader As StreamReader
            Stream = New FileStream(txtArquivo.Text, FileMode.Open, FileAccess.Read)
            Reader = New StreamReader(Stream)
            Dim ImgData(Stream.Length - 1) As Byte
            Stream.Read(ImgData, 0, Stream.Length - 1)
            Dim str As String = "Data Source=.\SQLEXPRESS;Initial Catalog=Cadastro;Integrated Security=True"
            Dim con As New SqlConnection(str)
            Dim sql As String = "INSERT INTO Imagens (imagemNome, Imagem) VALUES(@ImagemNome, @Imagem)"
            Dim cmd As New SqlCommand(sql, con)
            cmd.Parameters.Add("@ImagemNome", SqlDbType.Text).Value = NomeArquivo(txtArquivo.Text.Trim)
            cmd.Parameters.Add("@Imagem", SqlDbType.Binary, Stream.Length).Value = ImgData
            con.Open()
            cmd.ExecuteNonQuery()
            lblmsg.Content = " O arquivo   " & NomeArquivo(txtArquivo.Text.Trim) & "  foi armazenado com sucesso...."
            con.Close()
        Catch ex As Exception
            lblmsg.Content = ex.Message
        End Try
    End Sub

O código acima abre o arquivo criando um stream e, a seguir, um array de bytes.

A seguir , usando ADO .NET, definimos a string de conexão com o banco de dados e a instrução SQL INSERT INTO para incluir os dados na tabela.

Atribuímos os parâmetros para o objeto parameters, e usamos o método ExecuteNonQuery() para executar a instrução SQL.

Implementando as funcionalidades para recuperar e exibir as imagens salvas

Abra o projeto e, a seguir, abra o arquivo RecuperarImagem.xaml e inclua os seguintes controles a partir da ToolBox:

  • ListBox = Name=lstbImagens
  • Imagem = imgDados
  • Button = btnSair

Defina os controles conforme o leiaute da figura abaixo:

wpf_imgbd8

O código XAML gerado é visto abaixo:

<Window x:Class="RecuperarImagem"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Recuperar Imagens" Height="500" Width="680"  WindowStartupLocation="CenterScreen">
    <Grid Background="LightGreen">
        <ListBox x:Name="lstbImagens" HorizontalAlignment="Left" Height="385" Margin="10,44,0,0" VerticalAlignment="Top" Width="215"/>
        <Image x:Name="imgDados" HorizontalAlignment="Left" Height="386" Margin="247,43,0,0" VerticalAlignment="Top" Width="415"/>
        <Button x:Name="btnSair" Content="Sair" HorizontalAlignment="Left" Margin="150,434,0,0" VerticalAlignment="Top" Width="75" RenderTransformOrigin="0.32,1.3" Click="btnSair_Click"/>
    </Grid>
</Window>

Observe que a janela RecuperarImagem será exibida centralizada: WindowStartupLocation=”CenterScreen” e que definimos o evento Click para o controle Button – btnSair.

Vamos declarar os seguintes namespaces que iremos usar nesta janela:

  • Imports Microsoft.Win32
  • Imports System.IO
  • Imports System.Data.SqlClient
  • Imports System.Data

Logo após a declaração da janela, vamos definir uma variável con, do tipo SqlConnection, que será usada no projeto:

Dim con As SqlConnection = Nothing

Agora vamos definir o código no evento Window_Loaded da janela RecuperarImagem que ocorre quando a janela é carregada:

Private Sub Window_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
        Try
            con = New SqlConnection("Data Source=.\SQLEXPRESS;Initial Catalog=Cadastro;Integrated Security=True")
            con.Open()
            Dim dad As SqlDataAdapter = New SqlDataAdapter("Select imagemId, imagemNome from Imagens", con)
            Dim dst As New DataSet
            dad.Fill(dst, "ImgContainer")
            Dim datarow As DataRow
            For Each datarow In dst.Tables(0).Rows
                Dim lbitem As New ListBoxItem
                lbitem.Content = datarow(1).ToString
                lbitem.DataContext = datarow(0).ToString
                lstbImagens.Items.Add(lbitem)
            Next
        Catch ex As Exception
            MessageBox.Show(" Erro : " & ex.Message)
        Finally
            con.Close()
        End Try
    End Sub

Este código acessa o banco de dados Cadastro e executa uma instrução SQL – Select imagemId, imagemNome from Imagens – para recuperar as imagens armazenadas na tabela Imagens.

A seguir, criamos um dataset e exibimos o nome da imagem recuperada no controle ListBox – lstbImagens.

wpf_imgbd9

Nosso objetivo é permitir que o usuário selecione uma imagem no controle ListBox e a mesma seja exibida no controle Image.

Para isso, vamos definir o código abaixo no evento SelectionChanged do controle ListBox:

Private Sub lstbImagens_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles lstbImagens.SelectionChanged
        ExibirImagem()
End Sub

Neste código, cada item selecionado no controle ListBox irá chamar a rotina ExibirImagem() cujo código mostramos a seguir:

 Private Sub ExibirImagem()
        Try
            con = New SqlConnection("Data Source=.\SQLEXPRESS;Initial Catalog=Cadastro;Integrated Security=True")
            Dim lbitem As ListBoxItem = TryCast(lstbImagens.SelectedItem, ListBoxItem)
            Dim dst As New DataSet
            con.Open()
            Dim dad As New SqlDataAdapter("Select Imagem from Imagens where imagemId='" + lbitem.DataContext.ToString + "'", con)
            dad.Fill(dst, "ImgContainer")
            Dim ImgSource() As Byte = DirectCast(dst.Tables(0).Rows(0)(0), Byte())
            Dim stream As MemoryStream = New MemoryStream()
            stream.Write(ImgSource, 0, ImgSource.Length - 1)
            stream.Seek(0, SeekOrigin.Begin)
            Dim bitmap As New BitmapImage
            bitmap.BeginInit()
            bitmap.StreamSource = stream
            bitmap.EndInit()
            If bitmap.Width < 390 Or bitmap.Height < 340 Then
                imgDados.Stretch = Stretch.None
                imgDados.VerticalAlignment = Windows.VerticalAlignment.Center
                imgDados.HorizontalAlignment = Windows.HorizontalAlignment.Center
                imgDados.Source = bitmap
            Else
                imgDados.Stretch = Stretch.Uniform
                imgDados.VerticalAlignment = Windows.VerticalAlignment.Center
                imgDados.HorizontalAlignment = Windows.HorizontalAlignment.Center
                imgDados.Source = bitmap
            End If
        Catch ex As Exception
            MessageBox.Show(" Erro : " & ex.Message)
        Finally
            con.Close()
        End Try
    End Sub

O código obtém o id da imagem selecionada e localiza a imagem na tabela imagem.

A seguir, cria um stream com os dados da imagem e o atribui a um objeto do tipo BitmapImage para, em seguida, atribuir os dados ao controle Image e exibir a imagem selecionada:

wpf_imgbda

Pegue o projeto completo aqui: Wpf_GerenciaImagens.zip