这里有两个例子来测试你自己关于所选单元格的性能和填充样式。由于您的代码 sn-p 没有显示在什么上下文中调用代码,特别是创建图像列部分,并且为了避免重复不必要的例程,请使用网格设计器添加 4 列类型 DataGridViewImageColumn 并设置自动大小和那里的布局属性。
正常模式
在 Form 的 ctor 中,使用 Reflection 启用网格的 DoubleBuffered 属性以减少闪烁。 emptyImage 位图是空单元格的空值。
public partial class SomeForm : Form
{
private Bitmap emptyImage;
public SomeForm()
{
dgv.GetType()
.GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic)
.SetValue(dgv, true);
emptyImage = new Bitmap(1, 1);
foreach (var col in dgv.Columns.OfType<DataGridViewImageColumn>())
col.DefaultCellStyle.NullValue = emptyImage;
}
覆盖 OnLoad 方法以填充网格或为此调用方法。
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
var imgFolder = @"Your-Image-Folder-Path";
LoadImages(imgFolder);
}
protected override void OnFormClosed(FormClosedEventArgs e)
{
base.OnFormClosed(e);
emptyImage.Dispose();
}
private void LoadImages(string path)
{
string[] allFiles = Directory.GetFiles(path);
for (int i = 0; i < allFiles.Length; i += 4)
{
var files = allFiles.Skip(i).Take(4);
dgv.Rows.Add(
files.Select(f =>
{
using (var img = Image.FromFile(f, true))
return Thumb.GetThumbnail(img, ThumbSize.LowRes);
}).ToArray());
}
}
请注意,您的 Thumb.GetThumbnail 方法返回一个新图像,因此您需要处理原始图像。
实施 CellPainting 事件以绘制除 DataGridViewPaintParts.SelectionBackground 之外的所有内容,并用半透明颜色填充选定的单元格。
private void dgv_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
e.Paint(e.ClipBounds, e.PaintParts & ~DataGridViewPaintParts.SelectionBackground);
if (e.RowIndex >= 0 &&
e.Value != null && e.Value != emptyImage &&
(e.State & DataGridViewElementStates.Selected) > 0)
{
using (var br = new SolidBrush(Color.FromArgb(100, SystemColors.Highlight)))
e.Graphics.FillRectangle(br, e.CellBounds);
}
e.Handled = true;
}
}
虚拟模式
你需要在这里有数据存储来缓存你需要显示的图像。可见行的每个单元格的图像。为此,Cache 类是
创建用于管理相关功能,包括:
- 正在计算每个可见行显示 4 个图像所需的总行数。因此,
SetMaxRows 方法应该在网格首次创建和调整大小时重新计算可见行时调用。
- 在
Dictionary<int, Image> 中加载、创建和缓存当前可见行图像,其中键是单元格编号。
- 在引发
CellValueNeeded 事件时传递请求的图像。
public partial class SomeForm : Form
{
private readonly Cache cache;
public SomeForm()
{
dgv.GetType()
.GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic)
.SetValue(dgv, true);
dgv.VirtualMode = true;
var imgFolder = @"Your-Image-Folder-Path";
cache = new Cache(imgFolder, dgv.ColumnCount);
dgv.RowCount = cache.GetRowCount();
SetMaxRows();
}
protected override void OnFormClosed(FormClosedEventArgs e)
{
base.OnFormClosed(e);
cache.Dispose();
}
private void dgv_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e) =>
e.Value = cache.GetImage(e.RowIndex, e.ColumnIndex);
private void dgv_Resize(object sender, EventArgs e) => SetMaxRows();
// Change dgv.RowTemplate.Height as needed...
private void SetMaxRows() =>
cache.MaxRows = (int)Math
.Ceiling((double)dgv.ClientRectangle.Height / dgv.RowTemplate.Height);
private class Cache : IDisposable
{
private readonly Dictionary<int, Image> dict;
private readonly Bitmap nullImage;
private int currentRowIndex = -1;
private Cache()
{
dict = new Dictionary<int, Image>();
nullImage = new Bitmap(1, 1);
}
public Cache(string path, int columnCount) : this()
{
ImageFolder = path;
ColumnCount = columnCount;
}
public string ImageFolder { get; set; }
public int ColumnCount { get; set; }
public int MaxRows { get; set; }
public Bitmap NullImage => nullImage;
public Image GetImage(int rowIndex, int columnIndex)
{
var ri = rowIndex - (rowIndex % MaxRows);
if (ri != currentRowIndex)
{
foreach (var img in dict.Values) img?.Dispose();
currentRowIndex = ri;
dict.Clear();
}
var i = (rowIndex * ColumnCount) + columnIndex;
Image res = nullImage;
if (!dict.ContainsKey(i))
{
var file = Directory.EnumerateFiles(ImageFolder)
.Skip(i).FirstOrDefault();
if (file != null)
{
using (var img = Image.FromFile(file, true))
dict[i] = res = Thumb.GetThumbnail(img, ThumbSize.LowRes);
}
}
else
{
res = dict[i];
}
return res;
}
public int GetRowCount()
{
var count = Directory.EnumerateFiles(ImageFolder).Count();
return (int)Math.Ceiling((double)count / ColumnCount);
}
public void Dispose()
{
foreach (var img in dict.Values) img?.Dispose();
nullImage.Dispose();
}
}
最后,CellPainting 事件几乎保持不变,只是您从 cache 实例获取空图像。
private void dgv_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
e.Paint(e.ClipBounds, e.PaintParts & ~DataGridViewPaintParts.SelectionBackground);
if (e.RowIndex >= 0 &&
e.Value != null && e.Value != cache.NullImage &&
(e.State & DataGridViewElementStates.Selected) > 0)
{
using (var br = new SolidBrush(Color.FromArgb(100, SystemColors.Highlight)))
e.Graphics.FillRectangle(br, e.CellBounds);
}
e.Handled = true;
}
}