DataGridView 排序会导致 NullReferenceException



我想要一个可以通过单击表标题来由用户进行排序的DataGridView。 DataGridViews 数据绑定到 DataView,数据的最后一行应该是总和行(此代码中未实现总和!),该行需要始终是最后一行(换句话说,它需要免于排序)。

基于这个答案,我在类中实现了以下代码:

using System;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
namespace PipelineManagement.Debug
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Shown(object sender, EventArgs e)
{
tlp1.RowStyles.Clear();
for (var i = 0; i < 1; i++)
{
tlp1.RowStyles.Add(new RowStyle(SizeType.Absolute, 200));
var gbNew = new GroupBox();
gbNew.Text = "gb" + i;
gbNew.Size = new Size(tlp1.Size.Width - 2, 185);
gbNew.Anchor = AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom | AnchorStyles.Left;
m_dgv = new DataGridView();
m_dgv.Parent = gbNew;
m_dgv.AutoSize = true;
m_dgv.Location = new Point(5, 25);
m_dgv.Size = new Size(gbNew.Size.Width - 10, gbNew.Size.Height - 70);
m_dgv.Anchor = AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Left;
m_dt = new DataTable();
for (var j = 0; j < 2; j++)
{
var NewColumn = new DataColumn("Column" + j, typeof(Double));
m_dt.Columns.Add(NewColumn);
}
var k = 5;
for (var j = 0; j < 5; j++)
{
var NewRow = m_dt.NewRow();
NewRow[0] = Convert.ToDouble(k--);
m_dt.Rows.Add(NewRow);
}
m_dt.AcceptChanges();
m_dgv.ColumnHeaderMouseClick += dgv_ColumnHeaderMouseClick;
m_dgv.CellValueChanged += CellValueChangedHandler;
m_dgv.DataSource = m_dt.DefaultView;
tlp1.Controls.Add(gbNew);
}
}
private void dgv_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
var col = m_dgv.Columns[e.ColumnIndex].Name;
if (col != "")
{
if (m_Direction == ListSortDirection.Ascending)
{
m_Direction = ListSortDirection.Descending;
}
else
{
m_Direction = ListSortDirection.Ascending;
}                
sort_dgv(col, m_Direction);
}
}
private void CellValueChangedHandler(Object sender, DataGridViewCellEventArgs e)
{
var temp = m_dt.Rows[0].Field<Double>(0);
m_dt.Rows[m_dt.Rows.Count-1].SetField<Double>(0, m_dt.Rows[m_dt.Rows.Count - 1].Field<Double>(0) + 1);
}
private void sort_dgv(String ColumnName, ListSortDirection Direction)
{
if (!m_dt.Columns.Contains("sortMe"))
{
m_dt.Columns.Add("sortMe", typeof(Int32));
}
var dr = m_dt.Rows[m_dt.Rows.Count - 1];
m_dt.DefaultView.Sort = "";
for (int r = 0; r < m_dt.Rows.Count; r++)
{
m_dt.Rows[r]["sortMe"] = 0;
}
dr["sortMe"] = int.MaxValue;
if (Direction == ListSortDirection.Descending)
{
m_dt.DefaultView.Sort = "sortMe," + ColumnName + " DESC";
}
else
{
m_dt.DefaultView.Sort = "sortMe," + ColumnName;
}
m_dt.Columns.Remove("sortMe");
}
private DataGridView m_dgv;
private DataTable m_dt;
private ListSortDirection m_Direction = ListSortDirection.Ascending;
}
}

问题:一旦我单击任何标题对表进行排序 - 按预期工作 - 当我更改任何单元格中的值(并且调用CellValueChangedHandler)时,我得到一个System.NullReferenceException:"对象引用未设置为对象的实例。 在行中

m_dt.Rows[m_dt.Rows.Count-1].SetField<Double>(0, m_dt.Rows[m_dt.Rows.Count - 1].Field<Double>(0) + 1);

上面的一行我能够从完全相同的行(存储在可变温度中)获取值,但是一旦我尝试写入单元格,就会抛出异常。

问题:有人知道为什么我可以从单元格读取值但在写入时出现异常?

尝试以下代码:

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 WindowsFormsApplication44
{
public partial class Form1 : Form
{
DataTable m_dt = new DataTable();
public Form1()
{
InitializeComponent();
m_dgv.CellValueChanged += CellValueChangedHandler;
m_dt.Columns.Add("Col_A", typeof(double));
m_dt.Columns.Add("Col_B", typeof(string));
m_dt.Rows.Add(new object[] { 1 });
m_dgv.DataSource = m_dt;
}
private void CellValueChangedHandler(Object sender, DataGridViewCellEventArgs e)
{
DataGridView dgv = sender as DataGridView;
DataGridViewCellEventArgs arg = e as DataGridViewCellEventArgs;
int row = arg.RowIndex;
int col = arg.ColumnIndex;
if (row >= 0 && row == dgv.Rows.Count - 2) //new row already added to DGV
{
if (row == 0)
{
if (col != 0)
{
dgv.Rows[row].Cells[0].Value = 1;
}
}
else
{
double temp = (double)dgv.Rows[row - 1].Cells[0].Value;
dgv.Rows[row].Cells[0].Value = temp + 1;
}
}
}
private void button1_Click(object sender, EventArgs e)
{
m_dt = m_dt.AsEnumerable().OrderBy(x => x.Field<string>("Col_B")).CopyToDataTable();
m_dgv.DataSource = null;
m_dgv.DataSource = m_dt;
}
}
}