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:
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:
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:
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:
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:
<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:
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:
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:
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.
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:
Pegue o projeto completo aqui: Wpf_GerenciaImagens.zip