当使用空格键更改CheckBox时,AcceptChanges()会抛出异常

时间:2015-02-18 17:46:58

标签: c# exception datagridview datatable .net-4.0

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

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

  

当我用鼠标取消选中该复选框时,此功能正常。 使用空格键会抛出 NullReferenceException 异常。

以下是一些示例代码:

(完全正常工作。只需要Form1,空格DataGridView1。用空格键更改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();
            }
        }
    }
}

有没有办法让它与空格键一起工作?

修改
异常在.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.

2 个答案:

答案 0 :(得分:2)

使用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答案相同。

答案 1 :(得分:0)

正如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));
    }
}