星期二, 7月 30, 2024

[C#] DataGridView - CurrentCellDirtyStateChanged 事件

使用 DataGridViewCheckBoxColumn 時,都習慣性使用 CellValueChanged Event 來處理判斷,發現同事判斷是使用 CurrentCellDirtyStateChanged Event,在官方文章 DataGridViewCheckBoxColumn 備註內有相關事件說明,分別為
  • CellContentClick
  • CellValueChanged
  • CurrentCellDirtyStateChanged

CellContentClick VS CellValueChanged

以 CellContentClick 和 CellValueChanged 來比較的話,假如 DataGridViewCheckBoxColumn (ThreeState 為預設 false) 值目前為 false 來舉例的話
  • CellContentClick:更新前,抓到 false
  • CellValueChanged:更新後,抓到 true

CurrentCellDirtyStateChanged

而本篇筆記重點 CurrentCellDirtyStateChanged 事件,則是可以在該事件內判斷 DataGridViewCheckBoxColumn 是否更新
namespace CurrentCellDirtyStateChangedEvent
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            List<Source> sources = new List<Source>();
            sources.Add(new Source() { Selected = false });
            sources.Add(new Source() { Selected = false });
            dataGridView1.DataSource = sources;

            dataGridView1.CurrentCellDirtyStateChanged += DataGridView1_CurrentCellDirtyStateChanged;
            dataGridView1.CellValueChanged += DataGridView1_CellValueChanged;
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void DataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
        {
            // CommitEdit() 後,會立即觸發 CellValueChanged
            string value = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString();
            txtEventTrigger.Text += $"CellValueChanged 觸發 => RowIndex:{e.RowIndex},值:{value}" + Environment.NewLine;
        }

        private void DataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
        {
            var dgv = sender as DataGridView;
            if (dgv == null)
                return;

            // 透過 IsCurrentCellDirty 判斷資料是否變更
            if (dgv.IsCurrentCellDirty == false)
                return;
ˇ
            if (dgv.CurrentCell.ColumnIndex != ColSelected.Index)
                return;

            // 第一筆資料會進行 commit,可以進行 true、false 切換
            // 第二筆資料則是會取消使用者點擊,只會維持在 false
            if (dgv.CurrentRow.Index % 2 == 0)
                dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
            else
                dataGridView1.CancelEdit();
        }
    }

    public class Source
    {
        public bool Selected { get; set; }
    }
}

點擊第一筆會進行 CommitEdit 並觸發 CellValueChanged 事件,可以從右側資訊觀察,點擊第二筆資料則是 CancelEdit(),會一直維持在 false 狀態

CommitEdit() VS EndEdit()

看到 Code 最大疑惑是為什麼不用 EndEdit() 而是 CommmitEdit(),確認官方文件後發現,原來 CommitEdit() 會維持在編輯狀態,而 EndEdit() 則是會結束編輯狀態
Commits changes in the current cell to the data cache without ending edit mode.

Commits and ends the edit operation on the current cell.
編輯狀態可以透過 DataGridViewCell.IsInEditMode Property 來判斷,把上述語法修正來觀察
private void DataGridView1_CurrentCellDirtyStateChanged(object? sender, EventArgs e)
{
    if (dgv.CurrentRow.Index % 2 == 0)
    {
        dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
        txtEventTrigger.Text += $"CommitEdit IsInEditMode:{dataGridView1.CurrentCell.IsInEditMode}" + Environment.NewLine;
    }
    else
    {
        dataGridView1.EndEdit();
        txtEventTrigger.Text += $"EndEdit IsInEditMode:{dataGridView1.CurrentCell.IsInEditMode}" + Environment.NewLine;
    }
}

沒有留言:

張貼留言