VB.NET - Exibindo imagens armazenadas em um Banco de dados


Neste artigo vamos exibir imagens armazenadas em uma base de dados Access em um formulários Windows .

Para você entender melhor o projeto que vou criar você deve ler o artigo : Desvendando os segredos do Data Binding no VB.NET  - I

Pois vou usar a vinculação de dados no formulário.

Abaixo temos a exibição da tabela Categories do banco de dados Northwind.mdb (um velho conhecido nosso...). Na coluna Picture da tabela temos armazenadas as imagens de cada categoria.

Nosso objetivo será criar um projeto que exiba os dados da tabela em controles de forma que conforme o usuário navegue pelos registros os dados sejam dinamicamente mostrados juntamente com cada imagem da categoria correspondente.

Inicie então um novo projeto no VS.NET do tipo Windows Application usando a linguagem VB.NET e no formulário padrão insira os controles : label , textbox , Button e PictureBox conforme o layout abaixo.

Defina os imports usado pelo sistema conforme abaixo :

Imports System.IO

Imports System.Data

Imports System.Configuration

Imports System.Data.OleDb

 

Defina também as variáveis abaixo no início do formulário , pois serão usadas no projeto:

 

Private MSACCESSIMAGEMOFFSET As Integer = 78

Private ds As DataSet

Private da As OleDbDataAdapter

Private bm As BindingManagerBase


Em seguida vamos criar um arquivo de configuração para aplicação onde iremos armazenar as strings de conexão para o banco de dados SQL Server e para o banco de dados Access.

Abaixo o código do nosso arquivo de configuração:(Nele estou armazenando a string de conexão com o SQL Server e o nome do banco de dados Access usado no projeto.)

Para esta aplicação o arquivo de configuração tem o seguinte conteúdo:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
    <add key="acessoBD" value="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=d:\teste\Northwind.mdb" />
</appSettings>
</configuration>

Nota: Para saber mais sobre como criar o seu arquivo de configuração leia o artigo : NET - Tratando arquivos de configuração

Agora vamos ao código:

No evento Load do formulário inclua o código abaixo. Ele é responsável por :

Private Sub frmFoto_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' cria um DataSet
        ds = New DataSet

        ' cria um DataAdapter e retorna a tabela Categories
        Dim selectCommand As String = "SELECT CategoryID, CategoryName, Description FROM Categories"
        da = New OleDbDataAdapter(selectCommand, ConfigurationSettings.AppSettings("AcessoBD"))
        da.FillSchema(ds, SchemaType.Source, "Categories")
        da.Fill(ds, "Categories")

        ' vincula a tabela aos controles
        txtCodigo.DataBindings.Add("Text", ds, "Categories.CategoryID")
        txtNome.DataBindings.Add("Text", ds, "Categories.CategoryName")
        txtDescricao.DataBindings.Add("Text", ds, "Categories.Description")

        ' obtem o bm para a tabela pai
        bm = BindingContext(ds, "Categories")
        ' atualiza a imagem em resposta a cada posição do registro
        AddHandler bm.PositionChanged, AddressOf bm_PositionChanged
        ' atualiza e exibe para o primeiro registro
        bm_PositionChanged(Nothing, Nothing)

    End Sub

Para que possamos controlar a exibição dos dados conforme a navegação do usuário pelos registros incluir o código abaixo no evento PostionChanged do BindingManager. Ele irá selecionar a imagem referente a posição atual do registro e irá carregar e exibir a imagem no controle PictureBox.

Private Sub bm_PositionChanged(ByVal sender As [Object], ByVal e As EventArgs)
        ' refresca a foto exibida quando o registro atual muda
        ' obtem uma nova CategoryID usando o BindingManager
        Dim categoryId As Integer = CInt(ds.Tables("Categories").Rows(bm.Position)("CategoryID"))
        ' cria a conexao
        Dim conn As New OleDbConnection(ConfigurationSettings.AppSettings("acessoBD"))
        ' cria o commando para retornar a categoria das fotos
        Dim sqlText As [String] = "SELECT Picture FROM Categories WHERE CategoryID=" & categoryId
        Dim cmd As New OleDbCommand(sqlText, conn)

        ' retorna a foto do banco de dados
        conn.Open()
        Dim image As [Byte]() = CType(cmd.ExecuteScalar(), [Byte]())
        ' escreve o stream removendo a imagem do cabecalho
        Dim ms As New MemoryStream
        ms.Write(image, MSACCESSIMAGEMOFFSET, image.Length - MSACCESSIMAGEMOFFSET)
        conn.Close()

        ' carrega a imagem no picturebox
        picFoto.Image = System.Drawing.Image.FromStream(ms)
        ms.Close()
    End Sub

O Microsoft Access armazena as imagens no banco de dados com um objeto OLE que encapsula a imagem atual. Desta forma que a imagem possui um header com um tamanho variável que precisa ser extraído para obter a imagem. O tamanho deste header para imagens do tipo bitmap armazenadas no Northwind.mdb é de 78 bytes.

A imagem armazenada é retornada para um (array de bytes)Byte array. O byte array é copiado no objeto MemoryStream usando uma sobrecarga do método Write() que permite que 78 bytes sejam definidos.

O método estático FromStream da classe Image cria um objeto Image a partir de MemoryStream que é carregado no PictureBox.

Finalmente o código relativo a cada botão de movimentação do formulário para permitir a navegação pelos registros.


    
    Private Sub btnPrimeiro_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPrimeiro.Click
        bm.Position = 0
    End Sub

    Private Sub btnAnterior_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAnterior.Click
        bm.Position = bm.Position - 1
    End Sub

    Private Sub btnProximo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnProximo.Click
        bm.Position = bm.Position + 1
    End Sub

    Private Sub btnUltimo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnUltimo.Click
        bm.Position = bm.Count - 1
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Me.Close()
    End Sub
 

Abaixo o resultado da execução do projeto:

 

Notou como é simples criar um projeto com acesso a dados e fazer o tratamento dos mesmos usando o novo databinding do VB.NET ?

Pegue o código completo do projeto aqui : fotoDB.zip

Eu sei é apenas VB.NET , mas eu gosto...


José Carlos Macoratti