簡體   English   中英

單元格選擇隱藏在圖像 DataGridViewImageCell 后面

[英]Cell selection hides behind image DataGridViewImageCell

我正在使用 Winform DataGridView 來顯示圖像。 但是當圖像填滿單元格時,我看不到藍色選擇或數量非常少。 請參見: 實際行為

When an cell is selected, I expect make cell whole transparent blue, not just sides or sides which isn't occupied by image. 像:

預期行為

目前我嘗試在繪畫事件中自己塗上藍色,但更新太頻繁導致軟件掛起。

我還修改了圖像,使其在選擇更改事件中看起來偏藍,但它再次減慢了軟件速度。

有解決辦法嗎? 任何解決方法或什么? 在不影響性能的情況下?

編輯:這是關於我如何在 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++;
}

目前單元格繪畫我只使用一種解決方法,即在選定的單元格上繪制邊框 但是當數據很大並且其次也利用未選擇的單元格時它很慢。

在此處輸入圖像描述

這里有兩個例子來測試你自己關於所選單元格的性能和填充樣式。 由於您的代碼片段沒有顯示在什么上下文中調用代碼,尤其是創建圖像列部分,並且為了避免重復不必要的例程,請使用網格設計器添加 4 列DataGridViewImageColumn類型並從那里設置自動大小和布局屬性.

正常模式
在 Form 的 ctor 中,使用Reflection啟用網格的DoubleBuffered屬性以減少閃爍。 emptyImage bitmap 是空單元格的 null 值。

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 class 來管理相關功能,包括:

  • 計算每個可見行顯示 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實例中獲取了 null 圖像。

    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;
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM