Feedback

C# - Asynchrones nachladen von Bildern in DataGridView

Veröffentlicht von am 12/8/2008
(1 Bewertungen)
Bei einem DataGridView hat man die Möglichkeit eine (oder mehrere) Spalten als Image-Spalte zu definieren.

In dieser Spalte hat man die Möglichkeit Bilder in eine Tabelle zu integrieren. Wenn diese Bilder aber von externer Quelle, sei es ein FileServer oder ein Webservice geladen werden müssen, entstehen unschöne Wartezeiten beim Aufbau des Grids. Vor allem wenn große Datenmengen angezeigt werden sollen ist das Laden der Bilder beim füllen des Grids nicht tragbar.

Das folgende Snippet ist als Anregung gedacht, wie man solche Bilder (am Besten Thumbs der Originalbilder) asynchron, bei Bedarf nachladen kann.



Um die Beispielklasse (ja es ist eine ganze Klasse J) zu kompilieren brauchen wir ein Projekt mit einer Windows-Form (Form1) und einem ungebundenen DataGridView (dataGridView1). Beim DataGridView sollte Hinzufügen, Bearbeiten und Löschen (im ersten Schritt) nicht aktiviert sein.
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Threading;
using System.Windows.Forms;

namespace SnippetASLoader
{
    public partial class Form1 : Form
    {
        delegate void BildEintragenCallback(List<object> parameter);
        private List<String> dateinamen;

        public Form1()
        {
            //Infos zu den Einstellungen der visuellen Komponenten:
            //Das Grid (dataGridView1) is gedockt (Dock=fill);
            //Hinzufügen, Löschen, Bearbeiten .. alles aus!
            //Zwei Spalten:
            //  Column1 -> DataGridViewImageColumn
            //  Column2 -> DataGridViewTextBoxColumn
            InitializeComponent();
            //Sachen die wir für's Beispiel brauchen...
            this.dateinamen = new List<string>();
            dateinamen.Add(@"c:\temp\Bild01.png"); //Ja geht auch anders :-)
            dateinamen.Add(@"c:\temp\Bild02.png");
            dateinamen.Add(@"c:\temp\Bild03.png");
            dateinamen.Add(@"c:\temp\Bild04.png");
            dateinamen.Add(@"c:\temp\Bild05.png");
            dateinamen.Add(@"c:\temp\Bild06.png");
            dateinamen.Add(@"c:\temp\Bild07.png");
            dateinamen.Add(@"c:\temp\Bild08.png");
            dateinamen.Add(@"c:\temp\Bild09.png");
            dateinamen.Add(@"c:\temp\Bild10.png");
        }

        /// <summary>
        /// Standard Load-methode des Fensters ... 
        /// Hier füllen wir das Grid initial...
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_Load(object sender, EventArgs e)
        {
            dataGridView1.SuspendLayout();
            dataGridView1.Rows.Clear(); //Paranoider Sicherheitsabstand ... nicht wirklich nötig
            //Eintragen der nicht Bild-Daten ins Grid
            int z = -1;
            foreach (String zeile in dateinamen)
            {
                z++;
                dataGridView1.Rows.Add(); //Neue Zeile
                dataGridView1.Rows[z].Height = 128; //An Bildergröße anpassen!
                dataGridView1.Rows[z].Tag = zeile; //Hier den Pfad zum Bild ablegen!
                //SnippetASLoader.Properties.Resources.BildWirdGeladenBild -> "Standard-Bild" aus Resource
                dataGridView1.Rows[z].Cells[0].Value = SnippetASLoader.Properties.Resources.BildWirdGeladenBild;
                //Anhand dieser "null" merken wir uns, ob das Bild bereits nachgeladen wurde..
                dataGridView1.Rows[z].Cells[0].Tag = null;
                //Der Rest ... also alle Daten die wir haben!
                dataGridView1.Rows[z].Cells[1].Value = zeile;
            }
            dataGridView1.ResumeLayout();
        }

        /// <summary>
        /// Bevor die Zeile "gemalt" wird!!
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dataGridView1_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
        {
            DataGridViewRow row = dataGridView1.Rows[e.RowIndex];
            if (row.Cells[0].Tag == null) //Wir erinnern uns an den Merker vom Form1_Load? *G*
            {
                row.Cells[0].Tag = true; //Ab jetzt nicht mehr nachladen! (Nachladen läuft....)
                //Vorbereiten zum Starten eines neuen Threads
                List<Object> paramter = new List<object>();
                paramter.Add(row.Index);
                paramter.Add(row.Tag);
                ParameterizedThreadStart pts = new ParameterizedThreadStart(this.bildLaden);
                Thread serverThread = new Thread(pts);
                //Und Thread starten...
                serverThread.Start(paramter);
            }
        }

        /// <summary>
        /// Methode die in einem eigenen Thread läuft...
        /// </summary>
        /// <param name="o"></param>
        private void bildLaden(Object o)
        {
            List<Object> parameter = (List<Object>)o;
            int rowIndex = (int)parameter[0];
            string pfadZumBild = (string)parameter[1];

            //Thumb
            Image i;
            FileInfo fi = new FileInfo(pfadZumBild);
            if (fi.Exists)
            {
                i = Image.FromFile(fi.FullName); //Oder aus Stream oder sonst wie ...
            }
            else
            {
                i = SnippetASLoader.Properties.Resources.BildNichtGefundenBild;
            }
            List<object> result = new List<object>();
            result.Add(rowIndex);
            result.Add(i);

            //Zurückgeben des Ergebnisses
            this.bildEintragen(result);
        }

        /// <summary>
        /// Trägt das Ergebnis des Threads sicher in das Steuerelement ein.
        /// </summary>
        /// <param name="parameter"></param>
        private void bildEintragen(List<object> parameter)
        {
            if (this.dataGridView1.InvokeRequired)
            {
                //Delegaten Aufruf um das Steuerlement Thredsicher anzusprechen
                BildEintragenCallback tec = new BildEintragenCallback(bildEintragen);
                this.Invoke(tec, new object[] { parameter });
            }
            else
            {
                int rowIndex = (int)parameter[0];
                Image bild = (Image)parameter[1];
                dataGridView1.Rows[rowIndex].Cells[0].Value = bild;
            }
        }
    }
}

Kommentare zum Snippet

 

Logge dich ein, um hier zu kommentieren!