Supponiamo di avere un file di Report in formato .rdlc, e di voler stampare una lista di prodotti visualizzando un'immagine prodotta a run-time e memorizzata in un MemoryStream, piuttosto che utilizzare file d'immagine. Ad esempio, supponiamo di avere nel nostro Database, una tabella denominata Prodotti, contenente 4 colonne:
Aggiungiamo al nostro progetto (ad esempio di tipo Web Application) un DataSet tipizzato (dsProdotti) contenente un DataTable Prodotti, a cui andiamo ad aggiungere una colonna denominata Immagine, con proprietà DataType impostata su System.Byte[]:
Aggiungiamo un nuovo file di Report (Report1.rdlc), nel designer del report, dalla toolbox degli strumenti, trasciniamo nella sezione Body, un item Table che configuriamo opportunamente:
Come si evince dalla figura, nell'ultima colonna della Table, è stato aggiunto un controllo Image. Affinchè il tutto funzioni correttamente, è necessario impostare correttamente le proprietà di questo controllo, ovvero:
- La proprietà Source deve essere impostata su Database
- La proprietà MIMEType deve essere impostata sul tipo di immagine che si vuole visualizzare (images/gif, image/jpeg etc...)
- La proprietà Value deve essere impostata sul valore campo contenente lo Stream di byte, nello specifico: =Fields!Immagine.Value
Agganciato il report ad un opportuno controllo ReportViewer non resta che scrivere il codice per recuperare i dati dal Database e popolare un opportuno DataTable, da utilizzare come sorgente dati per il Report:
1 DsProdotti dsProdotti = new DsProdotti();
2
3 dsProdotti.Prodotti.RowChanged += new DataRowChangeEventHandler(Prodotti_RowChanged);
4
5 using (DsProdottiTableAdapters.ProdottiTableAdapter prodottiAdapter = new ReportConImmaginiStream.DsProdottiTableAdapters.ProdottiTableAdapter())
6 {
7 prodottiAdapter.Fill(dsProdotti.Prodotti);
8 }
9
10 ReportViewer1.LocalReport.DataSources.Clear();
11 ReportViewer1.LocalReport.DataSources.Add(new Microsoft.Reporting.WebForms.ReportDataSource("DsProdotti_Prodotti", dsProdotti.Prodotti));
Gestendo l'evento RowChanged del DataTable Prodotti, possiamo popolare il valore del campo Immagine della riga aggiunta alla collezione del DataTable, con lo stream di byte rappresentante l'immagine che vogliamo visualizzare:
1 void Prodotti_RowChanged(object sender, DataRowChangeEventArgs e)
2 {
3 if (e.Action == DataRowAction.Add)
4 {
5 //Immagine da Stream
6 e.Row["Immagine"] = ImageDataRow.ImageDataRowIstance.GetImageArray();
7 }
8 }
Dove il codice della classe ImageDataRow è il seguente:
1 public class ImageDataRow
2 {
3 private static byte[] _imageArray = null;
4 private static ImageDataRow _imageDataRowIstance;
5
6 private ImageDataRow() { }
7
8 public static ImageDataRow ImageDataRowIstance
9 {
10 get
11 {
12 if (_imageDataRowIstance == null)
13 _imageDataRowIstance = new ImageDataRow();
14 return _imageDataRowIstance;
15 }
16 }
17
18 public System.Byte[] GetImageArray()
19 {
20 if (_imageArray == null)
21 {
22 using (MemoryStream imgStream = new MemoryStream())
23 {
24 System.Drawing.Image img = new Bitmap(32, 32);
25 Graphics gr = Graphics.FromImage(img);
26 gr.FillRectangle(new SolidBrush(Color.White), 0, 0, 32, 32);
27 gr.DrawEllipse(new Pen(Color.Red, 2), 1, 1, 30, 30);
28 img.Save(imgStream, System.Drawing.Imaging.ImageFormat.Gif);
29 _imageArray = imgStream.ToArray();
30 }
31 }
32 return _imageArray;
33 }
34 }
Dato che nell'esempio viene visualizzata sempre la stessa immagine, per non instanziare ad ogni riga un oggetto MemoryStream ed eseguire il codice di disegno, si è scelto di utilizzare un Singleton. Ovviamente, nel caso in cui l'immagine debba cambiare a seconda dei valori contenuti nella riga, il codice dovrà essere ottimizzato opportunamente.
Il risultato che si otterrà eseguendo il codice, sarà qualcosa del tipo:
Sorgenti completi del progetto