You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VB.NET中从流调整图片大小优化DevExpress Grid图片显示性能

解决方案:DevExpress Grid行切换时图片加载卡顿优化

问题背景

使用DevExpress.XtraGrid的FocusedRowChanged事件时,因存在数千张图片数据,切换行时直接加载原图到PictureEdit导致界面卡顿。需求是:默认显示缩略图,双击图片时再展示原图。

现有代码

If Not String.IsNullOrWhiteSpace(filePath1) Then
    PictureEdit1.Image = Image.FromStream(New MemoryStream(File.ReadAllBytes(filePath1)), True, False)
    If Not String.IsNullOrWhiteSpace(filePath2) Then
        PictureEdit2.Image = Image.FromStream(New MemoryStream(File.ReadAllBytes(filePath2)), True, False)
        If Not String.IsNullOrWhiteSpace(filePath3) Then
            PictureEdit3.Image = Image.FromStream(New MemoryStream(File.ReadAllBytes(filePath3)), True, False)
            If Not String.IsNullOrWhiteSpace(filePath4) Then
                PictureEdit4.Image = Image.FromStream(New MemoryStream(File.ReadAllBytes(filePath4)), True, False)
                If Not String.IsNullOrWhiteSpace(filePath5) Then
                    PictureEdit5.Image = Image.FromStream(New MemoryStream(File.ReadAllBytes(filePath5)), True, False)
                    If Not String.IsNullOrWhiteSpace(filePath6) Then
                        PictureEdit6.Image = Image.FromStream(New MemoryStream(File.ReadAllBytes(filePath6)), True, False)
                    End If
                End If
            End If
        End If
    End If
End If

Private Sub PictureEditAll_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles PictureEdit1.DoubleClick, PictureEdit2.DoubleClick, PictureEdit3.DoubleClick, PictureEdit4.DoubleClick, PictureEdit5.DoubleClick, PictureEdit6.DoubleClick
    Dim picEdit As PictureEdit = DirectCast(sender, PictureEdit)
    Dim f2 As New Preview(picEdit.Image)
    f2.Show(Me)
End Sub

优化方案

1. 实现缩略图生成方法

编写通用方法,根据原图路径生成指定尺寸的缩略图,避免加载完整原图:

Private Function GenerateThumbnail(filePath As String, targetWidth As Integer, targetHeight As Integer) As Image
    Using originalImage As Image = Image.FromFile(filePath)
        ' 计算缩放比例,保持图片宽高比
        Dim scale As Double = Math.Min(targetWidth / originalImage.Width, targetHeight / originalImage.Height)
        Dim newWidth As Integer = CInt(originalImage.Width * scale)
        Dim newHeight As Integer = CInt(originalImage.Height * scale)

        Dim thumbnail As New Bitmap(newWidth, newHeight)
        Using g As Graphics = Graphics.FromImage(thumbnail)
            g.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
            g.DrawImage(originalImage, 0, 0, newWidth, newHeight)
        End Using
        Return thumbnail
    End Using
End Function

2. 异步加载+缓存缩略图

使用异步操作避免阻塞UI线程,同时用字典缓存已生成的缩略图,减少重复计算:

' 缩略图缓存,键为文件路径,值为缩略图
Private thumbnailCache As New Dictionary(Of String, Image)
' 原图路径缓存,用于双击时加载原图
Private picturePaths As New Dictionary(Of PictureEdit, String)

Private Async Sub GridView_FocusedRowChanged(sender As Object, e As DevExpress.XtraGrid.Views.Base.FocusedRowChangedEventArgs) Handles GridView1.FocusedRowChanged
    ' 先清空当前PictureEdit的内容,避免旧图残留
    ClearPictureEdits()

    ' 获取当前行的图片路径(根据你的实际数据结构调整)
    Dim filePath1 As String = GridView1.GetRowCellValue(e.FocusedRowHandle, "FilePath1").ToString()
    Dim filePath2 As String = GridView1.GetRowCellValue(e.FocusedRowHandle, "FilePath2").ToString()
    ' ... 其他路径同理

    ' 异步加载每个PictureEdit的缩略图
    Await LoadThumbnailAsync(PictureEdit1, filePath1)
    Await LoadThumbnailAsync(PictureEdit2, filePath2)
    ' ... 其他PictureEdit同理
End Sub

Private Async Function LoadThumbnailAsync(picEdit As PictureEdit, filePath As String) As Task
    If String.IsNullOrWhiteSpace(filePath) Then
        picEdit.Image = Nothing
        picturePaths.Remove(picEdit)
        Return
    End If

    ' 先检查缓存,存在则直接使用
    If thumbnailCache.ContainsKey(filePath) Then
        picEdit.Image = thumbnailCache(filePath)
        picturePaths(picEdit) = filePath
        Return
    End If

    ' 异步生成缩略图,避免阻塞UI
    Dim thumbnail As Image = Await Task.Run(Function() GenerateThumbnail(filePath, 200, 200))
    ' 回到UI线程赋值
    picEdit.Invoke(Sub()
                       picEdit.Image = thumbnail
                       thumbnailCache(filePath) = thumbnail
                       picturePaths(picEdit) = filePath
                   End Sub)
End Function

Private Sub ClearPictureEdits()
    PictureEdit1.Image = Nothing
    PictureEdit2.Image = Nothing
    ' ... 清空其他PictureEdit
    picturePaths.Clear()
End Sub

3. 双击加载原图优化

双击时直接从文件加载原图,而非依赖PictureEdit中的缩略图,同时注意资源释放:

Private Sub PictureEditAll_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles PictureEdit1.DoubleClick, PictureEdit2.DoubleClick, PictureEdit3.DoubleClick, PictureEdit4.DoubleClick, PictureEdit5.DoubleClick, PictureEdit6.DoubleClick
    Dim picEdit As PictureEdit = DirectCast(sender, PictureEdit)
    If picturePaths.ContainsKey(picEdit) Then
        Dim filePath As String = picturePaths(picEdit)
        ' 加载原图,使用Using确保资源释放
        Using originalImage As Image = Image.FromFile(filePath)
            ' 克隆原图,避免Preview窗体持有文件锁
            Dim clonedImage As Image = originalImage.Clone()
            Dim f2 As New Preview(clonedImage)
            f2.Show(Me)
        End Using
    End If
End Sub

4. 额外优化建议

  • 内存管理:当Grid行数量大时,定期清理缓存中不再使用的缩略图(比如监听GridView的RowCount变化,或者使用LRU缓存策略),避免内存溢出。
  • 图片格式预处理:如果可能,提前批量生成所有图片的缩略图并保存到本地,切换行时直接加载本地缩略图,进一步提升速度。
  • DevExpress控件特性:可以考虑使用DevExpress的PictureEdit的ZoomMode属性设置为ZoomMode.Fit,避免控件额外的缩放计算;同时开启PictureEdit的AsyncLoad属性(如果版本支持),简化异步加载逻辑。

内容的提问来源于stack exchange,提问作者roy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 13:50:30