星期三, 10月 08, 2025

[C#] 根據條件設定 DataGridViewCell 唯讀

在 DataGridView 內根據條件來決定 DataGridViewCell 唯讀、可編輯。

該範例會在 CellBeginEdit 事件內,根據 [結案] 欄位資料,來決定 [價格] 欄位是否唯讀,並在CellFormatting 事件內,把唯讀的 Column、Cell 設定為淺灰色方便識別。

UI 設計

C# Code

在 CellBeginEdit 事件內,把 把 DataGridViewCellCancelEventArgs.Cancel 設定為 true 即取消編輯該 cell,就可以達到唯讀效果。
namespace CellEditableCore
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            dataGridView1.AutoGenerateColumns = false;

            // 把 ColNO 設為唯讀
            ColNO.ReadOnly = true;
            ColNO.DefaultCellStyle.BackColor = Color.LightGray;
        }

        private void Form1_Load(object sender, EventArgs e)
        {

            List<Data> source = new List<Data>();
            source.Add(new Data() { NO = "001", Price = 100, Done = true });
            source.Add(new Data() { NO = "002", Price = 789, Done = false });
            source.Add(new Data() { NO = "003", Price = 500, Done = true });
            source.Add(new Data() { NO = "004", Price = 1000, Done = false });
            source.Add(new Data() { NO = "005", Price = 2000, Done = true });

            dataGridView1.DataSource = source;
        }

        private void dataGridView1_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
        {
            if (e.ColumnIndex != ColPrice.Index)
                return;

            bool done = (bool)dataGridView1.Rows[e.RowIndex].Cells[ColDone.Index].Value;
            
            // 把 e.Cancel = true 即取消編輯該 cell
            e.Cancel = done;
        }

        private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if (e.ColumnIndex != ColPrice.Index)
                return;

            bool done = (bool)dataGridView1.Rows[e.RowIndex].Cells[ColDone.Index].Value;
            e.CellStyle.BackColor = done ? Color.LightGray : dataGridView1.DefaultCellStyle.BackColor;
        }
    }

    public class Data
    {
        [Description("編號")]
        public string NO { get; set; }

        [Description("價格")]
        public decimal Price { get; set; }

        [Description("結案")]
        public bool Done { get; set; }
    }
}
執行結果
自動生成欄位

預設拉一個 DataGridView 來使用,AutoGenerateColumns 預設為 true,忘記把它設定為 false,導致在 CellBeginEdit 和 CellFormatting 事件內鬼打牆,在 CellFomatting 內寫個簡單範例來說明
bool trigger = false;
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
    if (trigger == false)
    {
        foreach (DataGridViewColumn col in dataGridView1.Columns)
            textBox1.Text += $"ColumnName:{col.Name}-ColumnIndex:{col.Index}" + Environment.NewLine;

        textBox2.Text += $"ColNO:{ColNO.Index}" + Environment.NewLine;
        textBox2.Text += $"ColPrice:{ColPrice.Index}" + Environment.NewLine;
        textBox2.Text += $"ColDone:{ColDone.Index}" + Environment.NewLine;
    }

    trigger = true;
}
從下圖可以看見,AutoGenerateColumns = true 情況下,[直接顯示 ColumnIndex] 會全部都是 0,造成欄位判斷異常,永遠都是第一欄位的背景顏色變化

沒有留言:

張貼留言