Alessandro Del Sole's Blog

{ A programming space about Microsoft® .NET® }
posts - 1908, comments - 2047, trackbacks - 352

My Links

News

Your host

This is me! Questo spazio è dedicato a Microsoft® .NET®, di cui sono molto appassionato :-)

Cookie e Privacy

Disabilita cookie ShinyStat

Microsoft MVP

My MVP Profile

Microsoft Certified Professional

Microsoft Specialist

Xamarin Certified Mobile Developer

Il mio libro su VB 2015!

Pre-ordina il mio libro su VB 2015 Pre-ordina il mio libro "Visual Basic 2015 Unleashed". Clicca sulla copertina per informazioni!

Il mio libro su WPF 4.5.1!

Clicca sulla copertina per informazioni! E' uscito il mio libro "Programmare con WPF 4.5.1". Clicca sulla copertina per informazioni!

These postings are provided 'AS IS' for entertainment purposes only with absolutely no warranty expressed or implied and confer no rights.
If you're not an Italian user, please visit my English blog

Le vostre visite

I'm a VB!

Guarda la mia intervista a Seattle

Follow me on Twitter!

Altri spazi

GitHub
I miei progetti open-source su GitHub

Article Categories

Archives

Post Categories

Image Galleries

Privacy Policy

LINQ-to-SQL: Inserire un'immagine nel database e riaprirla da una cella di DataGridView

Una domanda che ho letto molte volte nei forum riguarda la possibilità di inserire immagini in un database di Microsoft SQL Server da codice Visual Basic. In questo post vediamo come raggiungere l’obiettivo utilizzando LINQ-to-SQL e vedremo, inoltre, come fare per ottenere l’immagine contenuta in una cella di una DataGridView per rielaborarla e visualizzarla tramite il viewer di Windows alle sue dimensioni originali. Spesso, infatti, le griglie ci costringono a dover mantenere ridotte le dimensioni delle celle per poterle visualizzare in modo uniforme sullo schermo.

 

Supponiamo di avere un’applicazione Windows Forms, in cui sia stata aggiunta una classe LINQ-to-SQL per il mapping della sola tabella Employees del database Northwind. Per semplicità, sfruttiamo poi gli automatismi di data-binding messi a disposizione da Microsoft Visual Studio 2008 al fine di generare tutti i controlli dell’interfaccia e i controlli dati, con relativa associazione tra loro. Avendo trattato tutti questi passaggi nel mio articolo introduttivo a LINQ-to-SQL, vi rimando alla sua lettura poichè non mi soffermerò in questa sede a ripeterli.

 

Al BindingNavigator, aggiungiamo un pulsantino per l’aggiunta delle immagini. Il designer, in sostanza, si presenterà in modo simile alla figura:

 

 

 

Trasciniamo poi sul designer, dalla toolbox, una OpenFileDialog che ci servirà per selezionare il file di interesse. Passando al codice, iniziamo con due campi privati. Il primo per dichiarare il DataContext, il secondo per memorizzare successivamente il nome di un file temporaneo in cui saranno estratte le foto dalla DataGridView e poi riaperte tramite il Visualizzatore di Windows.

 

 

    Private NorthwindContext As NorthwindDataContext

 

    'Campo per memorizzare un percorso temporaneo

    Private PathForSavingImage As String

 

Ora iniziamo subito a “sporcarci le mani”. Ipotizzando di voler aggiungere agli impiegati della nostra tabella delle fotografie esistenti su disco come file, è necessario che i file stessi siano convertiti in array di byte e poi passati al DataContext. Possiamo prevedere un metodo che si occupi della conversione in questo modo, che sfrutta uno stream in memoria:

 

    Private Function ConvertImageToByteArray(ByVal inputImage As Image) As Byte()

 

        Dim ms As New MemoryStream

        inputImage.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp)

        Return ms.ToArray

 

    End Function

 

Fermiamoci un momento. LINQ to SQL esegue il mapping del tipo SQL Image in un tipo .NET chiamato System.Data.Linq.Binary. Affinchè il nostro codice funzioni, dobbiamo quindi modificare questo tipo in System.Byte(). Per farlo, è sufficiente attivare il designer ORM, selezionare la proprietà Photo dell’entità Employee e modificarne il tipo da Binary a Byte() come evidenziato in figura:

 

 

 

Il metodo di cui sopra verrà richiamato dal gestore di evento Click del pulsantino che abbiamo disegnato all’inizio e che otterrà, inoltre, l’istanza dell’Employee di cui modificare la fotografia attraverso un’espressione lambda e il metodo extension First. Ecco il codice del gestore:

 

    Private Sub ToolStripButton1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ToolStripButton1.Click

        Try

 

            'Leggo il contenuto della cella "LastName" tramite indice

            Dim ID As String = (Me.EmployeeDataGridView.SelectedRows(0).Cells(1).Value).ToString

 

            'Ottengo l'Employee corrispondente tramite espressione lambda e metodo extension First

            Dim currentEmployee As Employee = NorthwindContext.Employees.First(Function(p) p.LastName = ID)

 

            Dim fileName As String = String.Empty

 

            With OpenFileDialog1

 

                .Filter = "Immagini supportate|*.bmp;*.jpg;*.png;*.gif;*.tif"

 

                If .ShowDialog = Windows.Forms.DialogResult.OK And String.IsNullOrEmpty(.FileName) = False Then

 

                    fileName = .FileName

                Else

                    Exit Sub

                End If

            End With

 

            'Carica l'immagine e la assegna, per inferenza, a

            'un tipo System.Drawing.Image

            Dim img = Image.FromFile(fileName)

 

            'In sintesi: Byte()=Byte()   :-)

            currentEmployee.Photo = ConvertImageToByteArray(img)

            'Salva le modifiche

            NorthwindContext.SubmitChanges()

 

            'Se nessuna riga è stata selezionata nella DataGridView, solleva errore

        Catch ex As ArgumentOutOfRangeException

 

            MessageBox.Show("No grid row was selected. Please select one and retry")

        Catch ex As Exception

 

        End Try

    End Sub

 

L’istanza dell’Employee viene determinata in base al cognome specificato nella cella (con indice 1) LastName della riga selezionata. Il metodo extension First ottiene il primo elemento della sequenza di employees il cui cognome sia quello contenuto nella cella stessa, confrontato tramite lambda.

 

Oltre alla selezione e al caricamento del file di immagine, la cosa interessante è l’assegnazione della proprietà Photo (ora di tipo System.Byte()) dell’Employee col risultato della conversione dell’immagine proprio in un array di byte. L’invio delle modifiche alla sorgente dati finalizza il lavoro.

 

Prima di testare il risultato del codice sopra evidenziato, ragioniamo in senso contrario. Inserisco la foto per gli impiegati e voglio vederla alle sue dimensioni originali facendo doppio clic su di essa sulla cella della DataGridView che la contiene. Innanzitutto, predisponiamo un metodo che ottenga un’immagine a partire da un array di byte. Facciamo in questo modo per salvare l’immagine come file bitmap ed aprirla esternamente. Ecco il codice:

 

    'Converte il contenuto di un array di byte (contenuto cella) in Bitmap

    Private Function ConvertByteArrayToBitmap(ByVal Array As Byte()) As Bitmap

 

        Dim ic As New ImageConverter

        Dim img As Image = CType(ic.ConvertFrom(Array), Image)

 

        Dim bmp As New Bitmap(img)

 

        Return bmp

    End Function

 

La classe ImageConverter ci permette di eseguire la conversione desiderata. Intercettiamo ora il doppio clic sulla cella, tenuto conto del fatto che, nella fattispecie in esame, la colonna Photo è indicizzata al numero 14:

 

    Private Sub EmployeeDataGridView_CellContentDoubleClick(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles EmployeeDataGridView.CellContentDoubleClick

 

        If e.ColumnIndex = 14 Then

 

            Try

                'Ottengo l'istanza della griglia

                Dim dgv As DataGridView = DirectCast(sender, DataGridView)

 

                'Eseguiamo il cast tramite CType poichè abbiamo Option Strict su On

                'Il valore della cella (CurrentCell.Value) è di tipo Object

                Dim bmp As Bitmap = ConvertByteArrayToBitmap(CType(dgv.CurrentCell.Value, Byte()))

 

                'Otteniamo un pathname temporaneo

                PathForSavingImage = IO.Path.GetTempPath + "TestImage.bmp"

                'Salviamo l'immagine

                bmp.Save(PathForSavingImage)

 

                'e la apriamo col visualizzatore predefinito nel sistema

                Process.Start(PathForSavingImage)

 

            Catch ex As Exception

 

            End Try

 

        End If

    End Sub

 

Ora le ultime due implementazioni. Il pulsante di salvataggio (che va precedentemente abilitato nel BindingNavigator):

 

    Private Sub EmployeeBindingNavigatorSaveItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles EmployeeBindingNavigatorSaveItem.Click

        Me.Validate()

        Me.EmployeeBindingSource.EndEdit()

 

        Try

 

            NorthwindContext.SubmitChanges()

        Catch ex As Exception

 

        End Try

 

    End Sub

 

Popolamento della griglia:

 

    Public Sub New()

 

        ' This call is required by the Windows Form Designer.

        InitializeComponent()

 

        NorthwindContext = New NorthwindDataContext

        ' Add any initialization after the InitializeComponent() call.

        Me.EmployeeBindingSource.DataSource = Me.NorthwindContext.Employees

    End Sub

 

Ora avviamo l’applicazione e aggiungiamo un nuovo Employee. Nell’esempio, ci sono i miei dati. Prima di aggiungere la fotografia, salviamo il lavoro. Fatto questo, selezioniamo la riga interessata (non la singola cella ma la riga) quindi facciamo clic sul pulsante Add photo. Selezioniamo la foto che ci interessa e dopo pochi secondi otterremo quanto segue:

 

 

 

Per vedere la fotografia a dimensioni originali, facciamo doppio clic sulla cella che la contiene. La foto verrà estratta, come bitmap, nella cartella temporanea di Windows e aperta col visualizzatore di default.

 

LINQ to SQL ci ha permesso di memorizzare l’immagine nel database in modo molto semplice.

 

Il progetto completo utilizzato in questo esempio è disponibile nell’area Download di Visual Basic Tips & Tricks a questo indirizzo.

 

Alessandro

Print | posted on giovedì 27 novembre 2008 19:48 | Filed Under [ Visual Basic Visual Studio 2008 LINQ ]

Powered by:
Powered By Subtext Powered By ASP.NET