4

我有一个 DataGridView,它的 DataSource 是一个 DataTable。此 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 将输出“Is Selected”。

同样,当用户再次检查时,该框被清除,并且 selectionTableRowChanged 输出“未选中”。

这是我遇到问题的地方:

当用户双击复选框时,复选框被选中,RowChanged 事件被调用(“Is Selected”),然后复选框被清除,不会调用相应的 RowChanged 事件。现在 RowChanged 事件的订阅者不同步。

我现在的解决方案是继承 DataGridView 并覆盖 WndProc 以吃掉 WM_LBUTTONDBLCLICK,因此任何双击控件都会被忽略。有更好的解决方案吗?

4

7 回答 7

2

制作一个空的 DoubleClick 事件方法无济于事的原因是,它是在发生双击时发生的其他操作之外执行的。

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

我的直觉是重写 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 在双击的第一部分执行,然后 OnD​​oubleClick 在第二次单击时执行。

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

我怀疑要使这种方法起作用,可能必须采取进一步措施并覆盖忽略双击的 DataGridViewCheckBoxColumn 和 DataGridViewCheckBoxCell 。假设这可行,您将能够停止双击该复选框,但仍允许它在您的其他列控件上。

我已经发布了关于在此处创建自定义 DataGridView 列和单元格的另一个问题的答案。

于 2008-09-29T21:52:51.920 回答
2

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

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

这将明确强制第二个 CellClick 事件并避免不同步。

于 2009-09-01T17:19:36.463 回答
2

如果您想要 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);
}

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

于 2008-12-18T11:15:28.730 回答
1

我已经尝试覆盖 DataGridView 子类中的 OnDoubleClick 方法以不执行任何操作,但它仍然允许第二次更改复选框。

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

于 2008-09-29T20:37:01.277 回答
1

为什么不让 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
          }

  }
}
于 2008-09-29T20:43:04.180 回答
1

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

于 2008-09-29T20:24:26.737 回答
1

不知道为什么我必须这样做,但我能够将一个计时器滴答事件附加到一个 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;
    }**
于 2008-11-04T19:33:33.380 回答