winforms 单元格选择隐藏在图像后面DataGridViewImageCell

yhqotfr8  于 2022-12-14  发布在  其他
关注(0)|答案(1)|浏览(134)

我正在使用Winform DataGridView来显示图像。但是当图像填充单元格时,我没有看到蓝色选择或数量非常少。请参见:

当一个单元格被选中时,我期望使单元格整个透明蓝色,而不仅仅是边或没有被图像占据的边。

目前,我尝试着色蓝色自己在油漆事件,但它更新太频繁,挂起软件。
我也修改图像看起来蓝色在选择改变事件,但它再次放慢软件。
有没有解决这个问题的方法?有没有什么变通办法?而不影响性能?

**EDIT:**这是关于如何在datagridview上显示图像的源代码:

int colms = 4; // total no. of columns in our datagridview

//this create 4 image columns in datagridview
for (int c = 0; c < colms; c++)
{
    var imgColm = new DataGridViewImageColumn();
    imgColm.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
    imgColm.ImageLayout = DataGridViewImageCellLayout.Zoom;
    grid.Columns.Add(imgColm);
}

int colm = 0;
int row = 0;

//this get all images and display on datagridview 
foreach (var img in Directory.GetFiles(@"C:\Users\Administrator\Desktop\images"))
{
    if (colm >= colms)
    {
        row++;
        colm = 0;
        grid.Rows.Add();
    }
    ((DataGridViewImageCell)grid.Rows[row].Cells[colm]).Value = Thumb.GetThumbnail(img, ThumbSize.LowRes);
    colm++;
}

目前,我使用的单元格绘制只是一个解决方案,that draws border on selected cell。但它的速度慢,当数据很大,其次画在未选定的单元格以及。

flseospp

flseospp1#

以下是两个示例,用于测试所选单元格的性能和填充样式。由于您的代码段没有显示在什么上下文中调用代码,特别是创建图像列部分,为了避免重复不必要的例程,请使用网格设计器添加4个DataGridViewImageColumn类型的列,并从那里设置自动调整大小和布局属性。

正常模式

在窗体的ctor中,使用Reflection启用网格的DoubleBuffered属性以减少 Flink 。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;
    }
}

相关问题