DataGridView的绑定表在双击时仅生成一个RowChanged事件。我该如何做两个?

时间:2020-03-06 14:53:40  来源:igfitidea点击:

我有一个DataGridView,其数据源是一个数据表。
此DataTable有一个布尔列,该列被解释为DataGridView中的一个复选框。

employeeSelectionTable.Columns.Add("IsSelected", typeof(bool));
...
employeeSelectionTable.RowChanged += selectionTableRowChanged;
dataGridViewSelectedEmployees.DataSource = employeeSelectionTable;

...

private void selectionTableRowChanged(object sender, DataRowChangeEventArgs e)
{
    if ((bool)e.Row["IsSelected"])
    {
        Console.Writeline("Is Selected");
    }
    else
    {
        Console.Writeline("Is Not Selected");
    }
    break;
}

当用户单击复选框时,它会被选中,并且selectionTableRowChanged将输出"已选中"。

同样,当用户再次对其进行检查时,该框将被清除,并且selectionTableRowChanged输出"未选中"。

这是我遇到的问题:

当用户双击该复选框时,该复选框被选中,RowChanged事件被调用("已选择"),然后该复选框被清除,并且没有相应的RowChanged事件被调用。现在,RowChanged事件的订阅者已不同步。

现在,我的解决方案是子类化DataGridView并重写WndProc来吃WM_LBUTTONDBLCLICK,因此,双击该控件都将被忽略。
有更好的解决方案吗?

解决方案

有什么理由需要做这么低的水平? DoubleClick方法可以只是吃掉它的空方法吗?

我已经尝试重写DataGridView子类中的OnDoubleClick方法,但是什么也没做,但是仍然允许再次更改复选框。

理想情况下,我希望让DataTable的RowChanged事件被调用两次。
有没有一种方法可以通过重写的OnDoubleClick方法来影响基础DataTable?

为什么不仅仅让IsSelected列不受限制?使用CellContentClick事件将数据推送到基础数据表,而将CellDoubleClick或者RowChange事件保留为空。

private void dgv_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
  if(e.ColumnIndex == <columnIndex of IsSelected>)
  {
      string value = dgv[e.ColumnIndex, e.RowIndex].EditedFormattedValue;
       if( value == null || Convert.ToBoolean(value) == false)
          {
              //push false to employeeSelectionTable
          }
      else
          {
            //push true to employeeSelectionTable
          }

  }
}

制作空DoubleClick事件方法无济于事的原因是,除了双击时发生的其他操作外,还执行了该方法。

如果查看Windows生成的代码或者以编程方式添加事件处理程序的示例,请使用+ =分配事件处理程序。这意味着,除了已经存在的事件处理程序之外,还要添加该事件处理程序,我们可能会在save事件上触发多个事件处理程序。

我的本能是重写DataGridView类,然后重写OnDoubleClick方法,而不调用基本的OnDoubleClick方法。

但是,我已经对此进行了快速测试,并看到了一些有趣的结果。

我整理了以下测试类:

using System;
using System.Windows.Forms;

namespace TestApp
{
    class DGV : DataGridView
    {
        private string test = "";

        protected override void OnDoubleClick(EventArgs e)
        {
            MessageBox.Show(test + "OnDoubleClick");
        }

        protected override void OnCellMouseDoubleClick(System.Windows.Forms.DataGridViewCellMouseEventArgs e)
        {
            MessageBox.Show(test + "OnCellMouseDoubleClick");
        }

        protected override void OnCellMouseClick(System.Windows.Forms.DataGridViewCellMouseEventArgs e)
        {
            if (e.Clicks == 1)
            {
                // Had to do this with a variable as using a MessageBox
                // here would block us from pulling off a double click
                test = "1 click ";
                base.OnCellMouseClick(e);
            }
            else
            {
                MessageBox.Show("OnCellMouseClick");
            }
        }
    }
}

然后将其插入Windows窗体,添加一个复选框列并运行该程序。

在全新运行中,双击复选框会使消息框显示为" 1单击OnDoubleClick"。

这意味着OnCellMouseClick在双击的第一部分执行,然后OnDoubleClick在第二次单击执行。

同样,不幸的是,删除对基本方法的调用似乎并没有阻止复选框将点击传递给它。

我怀疑要使此方法起作用,可能必须进一步采取措施,并忽略忽略双击的DataGridViewCheckBoxColumn和DataGridViewCheckBoxCell。假设此方法有效,我们将能够停止双击该复选框,但仍将其保留在其他列控件上。

我在这里发布了另一个问题的答案,该问题讨论有关创建自定义DataGridView列和单元格的问题。

不知道为什么要这样做,但是我能够在datagridview刷新中添加一个计时器滴答事件,该事件在第二次单击后便刷新了dgv。

单元格内点击事件

**          _RefreshTimer = new Timer();
                _RefreshTimer.Tick += new EventHandler(RefreshTimer_Tick);
                _RefreshTimer.Interval = 100;
                _RefreshTimer.Start();

            }
        }

    }

    void RefreshTimer_Tick(object sender, EventArgs e)
    {
        dgv.Refresh();
        _RefreshTimer.Stop();
        _RefreshTimer = null;
    }**

如果我们想在DataGridView内创建一个复选框列,请创建如下所示的内容:

DataGridViewCheckBoxCell checkBoxCell = new MyDataGridViewCheckBoxCell();
...
DataGridViewColumn col = new DataGridViewColumn(checkBoxCell);
...
col.Name = "colCheckBox";
...
this.dgItems.Columns.Add(col);

其中dgItems是DataGridView实例。

如我们所见,我有一个MyDataGridViewCheckBoxCell类,它是DataGridViewCheckBoxCell类的子类。在此子类中,我定义:

protected override void OnContentDoubleClick(DataGridViewCellEventArgs e)
{
    //This the trick to keep the checkbox in sync with other actions.
    //base.OnContentDoubleClick(e);
}

当用户现在双击复选框列中的复选框时,该复选框的行为就像单击一样。这应该可以解决同步问题。

这不是一个完美的解决方案,但是为什么不简单地执行以下操作呢?

private void dgv_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
    dgv_CellClick(sender, e);
}

这将显式强制第二个CellClick事件,并避免不同步。