2016-04-12 22 views
0

Ich habe eine Listenansicht, die alle Elemente aus einem Verzeichnis listet etwa so:Listview zeigt falsche Bilder für jedes Element

card gallery

Aber wie Sie in diesem Bild sehen:

file system

Sie sind nicht in Ordnung, weil ein Bildtext komplett übersprungen wurde, aber das Bild selbst ist noch in Ordnung.

Aber, wenn es weiter unten in der Liste bekommt, etwa auf halbem Weg beginnen starten sie in diesem Beispiel vollständig vermischt wie immer:

Image 3

Wenn ein Bild klicken sie die Vorschau der korrekten zeigen Bild auf der rechten Seite.

image 4

Dies ist der Code, den ich in allen Bildern laden bin mit:

Dim imgList As New ImageList 
    Dim imgSize As New Size 
    Dim count As Integer = 0 
    Dim imgFilename As String 

    Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork 
     'Dim imlTemp As New ImageList 
     Dim dirFiles() As String = IO.Directory.GetFiles(My.Settings.GalleryLocation) 

     'Dim item As New ListViewItem 
     For Each dirFile As String In dirFiles 
      imgFileName = IO.Path.GetFileName(dirFile) 
      Dim img As New System.Drawing.Bitmap(dirFile) 
      Dim imgImage As Image = Image.FromFile(dirFile) 
      'Dim imgHeight As Integer 
      'imgHeight = imgImage.Height 
      imgSize.Width = 120 
      imgSize.Height = 174 
      Threading.Thread.Sleep(10) 
      BackgroundWorker1.ReportProgress(100/((dirFiles.Count + 1) - count), img) 
     Next 
    End Sub 

    Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged 
     ListView1.SmallImageList = imgList 
     ListView1.LargeImageList = imgList 
     imgList.ImageSize = imgSize 
     imgList.ColorDepth = ColorDepth.Depth32Bit 

     ListView1.Items.Add(imgFilename, count) 
     imgList.Images.Add(e.UserState.Clone) 
     count += 1 
     'ListView1.EnsureVisible(ListView1.Items.Count - 1) 
    End Sub 

Bevor ich in der Background hatte enorme Ladezeiten für eine große Menge von Bildern hinzugefügt, so Ich dachte, ich würde den Hintergrundarbeiter implementieren, um asynchrone Arbeit zu ermöglichen. Allerdings läuft etwas völlig falsch am Anfang der Aufgabe und mehrfach durch die Liste, wo es völlig vermasselt, wie in Bild 3 gezeigt.

Hat jemand eine Ahnung, was schief läuft, oder irgendeine Alternative Lösungen für das, was ich erreichen möchte?

Antwort

1

Da ReportProgress() nicht blockiert (soweit ich weiß), besteht die Möglichkeit, dass die Dateien schneller durchlaufen werden, als die UI aktualisieren kann.

Um dies synchronisiert zu halten, sollten Sie eine benutzerdefinierte Klasse erstellen, die alles enthält, was Sie aktualisieren möchten, und dieses an die ReportProgress()-Methode übergeben (sogar einige Schritte automatisieren).

Zum Beispiel:

Public Class GalleryImage 
    Public Property FullPath As String 
    Public Property FileName As String 
    Public Property [Image] As Image 


    Public Sub New(ByVal File As String) 
     Me.Image = Image.FromFile(File) 'Get the image. 
     Me.FullPath = File 'Save the full path of the image. 
     Me.FileName = Path.GetFileName(File) 'Get the file name. 
    End Sub 
End Class 

(Auch, wenn Sie die Dateinamen wollen, aber nicht die Erweiterung, die Sie können Path.GetFileNameWithoutExtension() verwenden)


Nun zu Ihrem Code. Zuallererst ist die Variable counter nicht wirklich notwendig, da sie entweder durch ListView1.Items.Count oder imgList.Images.Count ersetzt werden kann.

Zweitens sollten Sie nicht ständig die imgSize Variable noch die ListView Small-/LargeImageList Eigenschaften setzen. Das ist völlig unnötig und wird die Dinge verlangsamen. Für die Listview setzen nur die Bildliste einmal, und für die imgSize Variable können Sie wie folgt tun:

Dim ReadOnly imgSize As New Size(120, 174) 

machen die Variable ReadOnly tut, was es klingt; Sie können daraus lesen, aber nicht ändern.

jetzt diese Dinge beheben wir in der Background der For Each Schleife starten werde:

For Each dirFile As String In dirFiles 
    Threading.Thread.Sleep(10) 'You don't need this Sleep if you don't want to. 

    'Report the progress, declare an in-line version of our class and send it with. 
    BackgroundWorker1.ReportProgress(100/((dirFiles.Count + 1) - ListView1.Items.Count), New GalleryImage(dirFile)) 'A new GalleryImage is created. The property setting is handled by the class itself. 
Next 

Wie Sie haben wir nun den Code unten ziemlich viel verengt sehen.

Jetzt werden wir die ReportProgess() Ereignis behandeln:

Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged 
    Dim img As GalleryImage = e.UserState 'Retrieve our class, no need to clone it. 

    imgList.Images.Add(img.Image) 'Add the image first (I don't know for sure, but if you add the image after, wouldn't it require to redraw the ListView an extra time?). 
    ListView1.Items.Add(img.FileName, imgList.Images.Count - 1) 'Add the new item with the values from our class. 
End Sub 

Und schließlich sollte die Initialisierung und Ersteinstellung Sachen in der zum Beispiel die Form Load Ereignis erfolgen:

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load 
    'In here we do all the standard settings and initializations. 
    ListView1.SmallImageList = imgList 
    ListView1.LargeImageList = imgList 
    imgList.ImageSize = imgSize 
    imgList.ColorDepth = ColorDepth.Depth32Bit 
End Sub 

Und damit denke ich, ich hätte alles abdecken sollen.

Hoffe, das hilft!

+0

Das funktioniert wie ein Charme! Vielen Dank für diese detaillierte Antwort, und um mir zu helfen, einige dumme Fehler zu klären ... Ich habe eine letzte Frage: Wenn ich die Liste aktualisieren/neu laden wollte, musste ich nur die Liste löschen und dann die wieder Hintergrundarbeiter? –

+0

Auch ich aus Neugier tauschte diese zwei Linien um: 'imgList.Images.Add (img.Image) ListView1.Items.Add (img.FileName, imgList.Images.Count - 1) ' Und es war der gleiche Fehler wie am Anfang, also war das vielleicht das ganze Problem? –

+1

@DominikH: Ja, Sie können nur die 'ListView' und die' imgList' löschen und dann können Sie die BGW erneut ausführen. –

Verwandte Themen