检测 DataGridViewCell 的 BackColor 变化

Detecting BackColor change of the DataGridViewCell

我正在开发一个 class,我们称它为 MyDataGridView,派生自必须与 Excel 文件同步的 DataGridView(即,当 DataGridView 中发生某些变化时,我需要对 Excel 文件进行相同的更改。

为了检测 DataGridView 中的变化,我使用事件(例如,RowsAdded、ColumnRemoved、CellValueChanged 等)。但是我在检测背景颜色已更改的单元格时遇到问题。

颜色被使用我的 class 的其他程序员更改。为此,他可以使用以下代码:

MyDataGridView myDataGridView;
// create and fill MyDataGridView...
myDataGridView.Rows[0].Cells[0].Style.BackColor = Color.AliceBlue;

我的目标是检测 BackColor 属性 的变化以更改 Excel 文件。

为了实现这个目标,我(未成功)尝试了几种方法:

  1. CellStyleContentChanged 事件(问题:无法从事件处理程序中获取 Cell 本身)。

  2. CellFormatting事件(问题:事件上升了很多次,我搞不懂它发生的原因)

  3. CellStyleChanged 事件(问题:事件只发生在Style 属性改变时,而不是Style.BackColor)。

  4. 覆盖 DataGridViewCellStyle class(问题:我不知道如何正确覆盖这个 class 以及它是否可能)。

有助于重现我的尝试的代码片段:

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        dataGridView1.CellStyleContentChanged += dataGridView1_CellStyleContentChanged;
        dataGridView1.CellFormatting += dataGridView1_CellFormatting;
    }

    // Goal
    private void Form1_Load(object sender, EventArgs e)
    {
        dataGridView1.Columns.Add("column1", "column1");
        dataGridView1.Columns.Add("column2", "column2");
        dataGridView1.Rows.Add("cell1", "cell2");

        // how to detect this?
        dataGridView1.Rows[0].Cells[0].Style.BackColor = Color.AliceBlue;
    }

    // Attempt #1
    void dataGridView1_CellStyleContentChanged(
        object sender, DataGridViewCellStyleContentChangedEventArgs e)
    {
        // how to get cell itself (rowIndex & columnIndex)?
    }

    // Attempt #2
    void dataGridView1_CellStyleChanged(object sender, DataGridViewCellEventArgs e)
    {
        // event only occurs when the Style property changes, but not Style.BackColor
    }

    // Attempt #3
    void dataGridView1_CellFormatting(
        object sender, DataGridViewCellFormattingEventArgs e)
    {
        // event rises so many times!
        // and how to get reason of formatting (i need to detect only color change)?
    }

    // Attempt #4
    // do i need something like this?
    public class MyDataGridView : DataGridView
    {
        public class MyDataGridViewRowCollection : DataGridViewRowCollection
        {
            public MyDataGridViewRowCollection(DataGridView _dgv) : base(_dgv) { }

            public class MyDataGridViewRow : DataGridViewRow
            {
                public class MyDataGridViewCellCollection : DataGridViewCellCollection
                {
                    public MyDataGridViewCellCollection(DataGridViewRow _dgvRow) :
                        base(_dgvRow) { }

                    public class MyDataGridViewCell : DataGridViewCell
                    {
                        private new MyDataGridViewCellStyle Style { get; set; }

                        public class MyDataGridViewCellStyle : DataGridViewCellStyle
                        {
                            public new Color BackColor
                            {
                                get
                                {
                                    return base.BackColor;
                                }
                                set
                                {
                                    base.BackColor = value;

                                    // TODO: changes in Excel
                                    // ...
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

我很乐意接受任何建议和解答!

与@TaW 的讨论促使我同时使用多个事件。

我们使用 CellStyleContentChanged 事件来检测 Style.BackColor 变化,并使用 CellFormatting 事件来获取 Cell,其 BackColor 已被更改。

我们还需要一些 Collection 来存储更改的颜色,因为这些事件不会按顺序发生(请参阅下面的日志)。

备注!!此方法仅适用于用户可见的单元格(DataGridView 不应有滚动条)。

public partial class Form1 : Form
{
    string log = "";
    List<Color> changedBackColors = new List<Color>();

    public Form1()
    {
        InitializeComponent();
        this.dataGridView1.CellStyleContentChanged +=
            dataGridView1_CellStyleContentChanged;
        this.dataGridView1.CellFormatting +=
            dataGridView1_CellFormatting;
        this.Shown += Form1_Shown;
    }

    void Form1_Shown(object sender, EventArgs e)
    {
        log += "Change Cell[0,0] (color = blue)\r\n";
        this.dataGridView1.Rows[0].Cells[0].Style.BackColor = Color.Blue;

        log += "Change Cell[0,1] (color = red)\r\n";
        this.dataGridView1.Rows[0].Cells[1].Style.BackColor = Color.Red;
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        this.dataGridView1.Columns.Add("column1", "column1");
        this.dataGridView1.Columns.Add("column1", "column1");
        this.dataGridView1.Rows.Add("cell1", "cell2");
    }

    private void dataGridView1_CellStyleContentChanged(
        object sender, DataGridViewCellStyleContentChangedEventArgs e)
    {
        log += string.Format(
            "CellStyleContentChanged occurs for Cell[?,?] (color = {0})\r\n",
            e.CellStyle.BackColor.Name);
        this.changedBackColors.Add(e.CellStyle.BackColor);
    }

    private void dataGridView1_CellFormatting(
        object sender, DataGridViewCellFormattingEventArgs e)
    {
        if (this.changedBackColors.Count > 0)
        {
            if (this.changedBackColors.Contains(e.CellStyle.BackColor))
            {
                log += string.Format(
                    "CellFormatting occurs for Cell[{0},{1}] (color = {2})\r\n",
                     e.RowIndex, e.ColumnIndex, e.CellStyle.BackColor.Name);

                this.changedBackColors.Remove(e.CellStyle.BackColor);

                // TODO: change excel file
                // ...
            }
        }
    }
}

日志:

  • 更改单元格[0,0](颜色=蓝色)
  • 单元格发生 CellStyleContentChanged[?,?](颜色 = 蓝色)
  • 更改单元格[0,1](颜色=红色)
  • 单元格发生 CellStyleContentChanged[?,?](颜色 = 红色)
  • Cell[0,0] 出现 CellFormatting(颜色 = 蓝色)
  • 单元格 [0,1](颜色 = 红色)发生单元格格式化