ListView为每个项目显示不正确的图像

时间:2016-04-12 17:12:07

标签: vb.net image listview

我有一个列表视图,列出目录中的所有项目,如下所示:

card gallery

但正如您在此图片中所见:

file system

它们不按顺序排列,因为已完全跳过一个图像文本,但图像本身仍处于有序状态。

但是,当它从列表中进一步下降时,从大约一半开始,它们开始变得完全混淆,如下例所示:

Image 3

单击图像时,它会在右侧显示正确图像的预览。

image 4

这是我用来加载所有图片的代码:

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

在我添加到后台工作程序之前,它有大量图像的加载时间,因此我认为我实现了后台工作程序以允许完成异步工作。但是,在任务开始时有些事情是完全错误的,并且在列表中多次出现错误,如图3所示,它完全混乱。

是否有人知道出了什么问题,或者我想要做的任何其他解决方案?

1 个答案:

答案 0 :(得分:1)

由于ReportProgress()没有阻塞(据我所知),文件的迭代速度可能比UI更新的速度快。

要保持同步,您应该创建一个包含要更新的所有内容的自定义类,并将其传递给ReportProgress()方法(甚至自动执行一些步骤)。

例如:

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

(另外,如果您想要文件名而不是扩展程序,则可以使用Path.GetFileNameWithoutExtension()

现在你的代码。首先,counter变量并不是必需的,因为它可以被ListView1.Items.CountimgList.Images.Count替换。

其次,您不应该经常设置imgSize变量或ListView的Small- / LargeImageList属性。这样做是完全没必要的,会减慢速度。对于ListView,只需设置一次图像列表,对于imgSize变量,您可以这样做:

Dim ReadOnly imgSize As New Size(120, 174)

使变量ReadOnly完成它听起来的样子;你可以从中读取,但不能修改它。

现在要解决其他问题,我们将从BackgroundWorker的For Each循环开始:

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

如您所见,我们现在已经将代码缩小了很多。

现在我们将处理ReportProgess()事件:

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

最后,填充的初始化和初始设置应该在例如Form Load事件中完成:

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

由此我认为我应该已经涵盖了所有内容。

希望这有帮助!