当使用 space 栏更改 CheckBox 时,AcceptChanges() 在 DataGridView 中抛出 System.NullReferenceException

AcceptChanges() throws System.NullReferenceException in DataGridView when using space bar for changing CheckBox

在我的 DataGridView 中,我使用 DataView 来过滤 DataTable。 CheckBox 值用于过滤器。

取消选中 CheckBox 时,该行应该会消失。为了立即 运行,我在 CurrentCellDirtyStateChanged 事件中使用 AcceptChanges()。 (否则该行会一直显示,直到选择了另一行)。

This works when I unselect the checkbox with the mouse. Using the space bar a NullReferenceException exception is thrown.

下面是一些示例代码:

(完整工作。只需要带有空白 DataGridView1 的 Form1。使用 space 栏更改 CheckBox 会引发异常)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        DataTable table;
        DataView view; 

        public Form1()
        {
            InitializeComponent();

            Init();
        }

        // Building the table and view
        private void Init()
        {
            table = new DataTable();
            table.Columns.Add("check", typeof(bool));

            table.Rows.Add(true);
            table.Rows.Add(true);
            table.Rows.Add(true);

            view = new DataView(table);
            view.RowFilter = "check = true";

            dataGridView1.DataSource = view;
        }

        // CurrentCellDirtyStateChanged Event
        private void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
        {
            if (dataGridView1.IsCurrentCellDirty == true && dataGridView1.CurrentCell is DataGridViewCheckBoxCell)
            {
                dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);

                // AcceptChanges to update the view
                // works with mouse click, throws NullReferenceException when spacebar is used
                table.AcceptChanges();
            }
        }
    }
}

有什么方法可以让它也与 space 栏一起使用吗?

编辑
在 .net 运行 时间的任何地方抛出异常,而不是直接由 AcceptChanges()

抛出
System.NullReferenceException: Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.
     bei System.Windows.Forms.DataGridViewCheckBoxCell.NotifyMASSClient(Point position)
     bei System.Windows.Forms.DataGridViewCheckBoxCell.OnKeyUp(KeyEventArgs e, Int32 rowIndex)
     bei System.Windows.Forms.DataGridView.OnKeyUp(KeyEventArgs e)
     bei System.Windows.Forms.Control.ProcessKeyEventArgs(Message& m)
     bei System.Windows.Forms.DataGridView.ProcessKeyEventArgs(Message& m)
     bei System.Windows.Forms.Control.WmKeyChar(Message& m)
     bei System.Windows.Forms.Control.WndProc(Message& m)
     bei System.Windows.Forms.DataGridView.WndProc(Message& m)
     bei System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
     bei System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
     bei System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
     bei System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
     bei System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
     bei Sample.Program.Main() in C:\Projects\TFS\Sample\Sample\Program.cs:Zeile 21.

Microsoft Connect 报道,一个潜在的解决方法是延迟 CommitEdit 直到 CellDirtyStateChanged 事件处理程序完成。

public delegate void InvokeDelegate();

public void MyDelegate()
{
    dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
    table.AcceptChanges();
}

//CurrentCellDirtyStateChanged Event
private void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
    if (dataGridView1.IsCurrentCellDirty == true && dataGridView1.CurrentCell is DataGridViewCheckBoxCell)
    {
        BeginInvoke(new InvokeDelegate(MyDelegate));
    }
}

以这种方式使用 Invoke 使代码更易于阅读,因为不需要显式委托声明。

private void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
    if (dataGridView1.IsCurrentCellDirty == true && dataGridView1.CurrentCell is DataGridViewCheckBoxCell)
    {
        // use BeginInvoke with (MethodInvoker) to run the code after the event is finished
        BeginInvoke((MethodInvoker)delegate
        {
            dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
            table.AcceptChanges();
        });
    }
}

与 tezzos 答案一样工作。