Laden...

Bilder aus ImageList wieder freigeben.

Erstellt von Splitframe vor 12 Jahren Letzter Beitrag vor 12 Jahren 2.371 Views
S
Splitframe Themenstarter:in
22 Beiträge seit 2009
vor 12 Jahren
Bilder aus ImageList wieder freigeben.

Hi,

ich komme mir schon richtig doof vor, dass das nicht klappt.

Folgende Infos habe ich hier auf dem Board dazu gefunden:
Images in ImageList muss man beim für jedes Image Dispose aufrufen

Das Problem:

Ich lade Bilder ( png ) in eine ImageList und übergebe diese ImageList and ein
ListView Objekt.

Jetzt möchte ich die Bilder aber, zur Laufzeit, wieder Freigeben zum verschieben, löschen, etc.

Zuerst versuchte ich es damit das ganze ImageList Objekt "null" zu setzen,
das ListView Objekt zu clear() -en und dessen Referenz LargeImageList "null" zu setzen.

Das hat nicht geklappt.

Aber auch jeden ImageList Eintrag einzeln "null" setzen bringt nicht das gewünschte ergebnis : /


foreach (Image img in ilImgList.Images)
                    img.Dispose();

Irgendwie steh ich auf dem Schlauch auch das ImageList Objekt dispose() -en hat nichts gebracht...

Hier mal ein auszug aus der Methode mit den relevanten Code abschnmitten:

[spoiler]


private void btnScan_Click(object sender, EventArgs e)
        {
            if ( ilImgList != null )
                foreach (Image img in ilImgList.Images)
                    img.Dispose();

            ilImgList = new ImageList();                 // Das ImageList Objekt

            if (!Directory.Exists(strStartDir + "\\Temp"))
                Directory.CreateDirectory(strStartDir + "\\Temp");
            else
            {
                Directory.Delete(strStartDir + "\\Temp",true);  // Hier kommt die IOException, duh
                Directory.CreateDirectory(strStartDir + "\\Temp");
            }

            for ( int i = 0; i < arFiPackages.Length; i++ )
            {  
                try
                {
                    using (ZipFile zip = ZipFile.Read(arFiPackages[i].FullName))
                    {
                        
                        ilImgList.Images.Add(Image.FromFile(strStartDir + "\\Temp\\" + strName + "\\icon.png")); // Laden des Bildes über Image.FromFile

                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Extraction:\n" + ex);
                }

            }

            lvPackages.Items.AddRange(arLvItems);
            lvPackages.LargeImageList = ilImgList;
}

Nicht wundern, habe unnötige Zeilen weggelassen.
[/spoiler]

49.485 Beiträge seit 2005
vor 12 Jahren

Hallo Splitframe,

woran siehst du denn, dass es nicht geklappt hat? Mit dem Taskmanager kann man keine verlässliche Aussage über den Speicherverbrauch im allgemeinen und den (nicht) freigegebenen Speicher im besonderen treffen.

Korrekt ist, dass man für jedes Bild Dispose aufrufen sollte. Das gibt den verwalteten Speicher des Bildes, also vor allem den Speicher für den eigentlichen Bildinhalt (also den Speicher für die ganzen Pixel) frei.

Der Rest, also der verwaltete Teil, also das Bitmap-Objekt, verbraucht für sich gesehen eh kaum Speicher. Außerdem werden verwaltete Objekte vom GC üblicherweise erst (viel) später weggeräumt, oft erst dann, wenn der Speicher anderweitig benötigt wird. Das brauche einen aber nicht zu stören.

Lange Rede, kurzer Sinn: Eine Schleife mit Dispose über alle Bilder und anschließendes Nullsetzen aller Variablen, die die ImageList noch referenzieren, sollte es tun.

herbivore

S
248 Beiträge seit 2008
vor 12 Jahren

Hallo,

ich verstehe dein Problem so, dass du die Dateien nicht löschen kannst, weil sie durch dein Programm geöffnet sind?!

Wenn ja, dann versuche anstatt Image.FromFile die Methode Image.FromStream zu verwenden, in Kombination mit einem FileStream den du innerhalb eines using-Blockes verwendest. So sollten alle Dateien sofort wieder frei sein.

Grüße

49.485 Beiträge seit 2005
vor 12 Jahren

Hallo Spook,

versuche [...] die Methode Image.FromStream zu verwenden, in Kombination mit einem FileStream den du innerhalb eines using-Blockes verwendest.

Kreisch! Nein! Es ist nicht erlaubt und kann zu merkwürdigen Fehlern führen, wenn man einem Image-Objekt den Strom unter dem Hintern wegzieht. Immerhin wird die Datei - und der Strom - ja absichtlich offen gehalten, eben weil er in bestimmten Fällen später noch benötigt wird. Man sollte das also auf keinen Fall so machen, wie du geschrieben hat. Wenn man verhindern will, dass die Datei offenbleibt, dann kann man deren Inhalt z.B. in einen MemoryStream packen und denn dann nötigenfalls zurückspulen und ihn dann an Image.FromStream übergeben - natürlich ohne ihn zu schließen!

Aber selbst wenn man Bitmap-Objekte Image.FromFile erstellt und dies irgendwann nicht mehr benötigt, reicht Dispose, um die noch geöffnete Datei freizugeben.

herbivore

S
Splitframe Themenstarter:in
22 Beiträge seit 2009
vor 12 Jahren

Hallo,

vielen Dank für die Antworten.

woran siehst du denn, dass es nicht geklappt hat?

In dem Code ausschnitt in meinem ersten Post gibt es eine Zeile wo ich den Ordner Lösche.
( ist auch Kommentiert ) an der Stelle kommt dann eine IOException mit der Meldung, dass das
Bild noch von meinem Prozess benutzt wird und daher nicht gelöscht werden kann.

Ist ja auch logisch ich hab ja das Bild in eine ImageList geladen mit ImageList.FromFile().

Nun wird die Methode aber erneut benutzt und mein angelegter temporärer Ordner soll
gelöscht und neu erstellt werden ( zurück gesetzt ).
Damit beim neuen befüllen des Ordners keine bösen überraschungen auftauchen.

Das funktioniert auch nicht:


            if ( ilImgList != null )
                foreach (Image img in ilImgList.Images)
                    img.Dispose();

            ilImgList.Dispose();

            if (lvPackages.LargeImageList != null)
                foreach (Image img in lvPackages.LargeImageList.Images)
                    img.Dispose();


            lvPackages.LargeImageList.Dispose();
            lvPackages.Clear();

            GC.Collect();

49.485 Beiträge seit 2005
vor 12 Jahren

Hallo Splitframe,

wenn alle Bilder aus dem Ordner, die per Image.FromFile (oder auf andere Weise, so dass die zugehörige Datei geöffnet bleibt) geladen wurden, in der ImageList enthalten ist, sollte das Aufrufen von Dispose für jedes Element der ImageList alle Dateien freigeben. Und zwar, da Dispose synchron erfolgt, sofort. Wenn das bei dir nicht der Fall ist, gibt es noch Bilder aus dem Ordner, zu denen es ein Bitmap-Objekt gibt, das nicht in der ImageList enthalten ist oder gibt es noch Dateien, die auf andere Weise geöffnet sind oder gibt es noch etwas anderes, was das das Löschen des Ordners verhindert. Es sollte dann jedenfalls nicht mehr an der ImageList liegen.

herbivore