通过DataGridView重新排序DataTable中的列

时间:2013-01-02 23:05:11

标签: c# .net data-binding datagridview

我有一个DataGridView并启用了AllowUserToOrderColumns属性,以便用户可以使用拖放操作对列进行重新排序。我已经为ColumnDisplayIndexChanged事件创建了一个处理程序。 DataGridView绑定到DataTable。当用户重新排序DataGridView中的列时,我想重新排序DataTable中的列。

这是我到目前为止所得到的:

private void dataGridView_Main_ColumnDisplayIndexChanged(object sender, DataGridViewColumnEventArgs e)
{
    if(!_isDatabinding)
    {
        if(_data.Columns[columnName].Ordinal != e.Column.DisplayIndex)
        {
            _data.Columns[e.Column.DataPropertyName].SetOrdinal(e.Column.DisplayIndex);
        }
    }
}

问题是这会导致以下异常:

“集合已被修改;枚举操作可能无法执行。”

我意识到发生这种情况是因为调用SetOrdinal方法导致再次调用事件处理程序,因为DataTable绑定到DataGridView。所以我把它改成了以下内容:

private void dataGridView_Main_ColumnDisplayIndexChanged(object sender, DataGridViewColumnEventArgs e)
{
    if(!_isDatabinding && !_isChangingColumnOrder)
    {
        if(_data.Columns[columnName].Ordinal != e.Column.DisplayIndex)
        {
            _isChangingColumnOrder = true;
            _data.Columns[e.Column.DataPropertyName].SetOrdinal(e.Column.DisplayIndex);
            _isChangingColumnOrder = false;
        }
    }
}

现在在DataGridViewColumn :: DisplayIndex属性setter中抛出NullReferenceException。这是callstack:

System.Windows.Forms.dll!System.Windows.Forms.DataGridViewColumn.DisplayIndex.set(int value) + 0xc5 bytes   
System.Windows.Forms.dll!System.Windows.Forms.DataGridView.EndColumnRelocation(System.Windows.Forms.MouseEventArgs e, System.Windows.Forms.DataGridView.HitTestInfo hti) + 0x27f bytes  
System.Windows.Forms.dll!System.Windows.Forms.DataGridView.OnMouseUp(System.Windows.Forms.MouseEventArgs e) + 0x3a6 bytes   
System.Windows.Forms.dll!System.Windows.Forms.Control.WmMouseUp(ref System.Windows.Forms.Message m, System.Windows.Forms.MouseButtons button, int clicks) + 0x48b bytes 
System.Windows.Forms.dll!System.Windows.Forms.Control.WndProc(ref System.Windows.Forms.Message m) + 0xe14 bytes 
System.Windows.Forms.dll!System.Windows.Forms.DataGridView.WndProc(ref System.Windows.Forms.Message m) + 0x134 bytes    
System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.DebuggableCallback(System.IntPtr hWnd, int msg = 514, System.IntPtr wparam, System.IntPtr lparam) + 0x14c bytes  

我不确定导致此例外的原因。

我还尝试在调用SetOrdinal之前在事件处理程序中将DataGridView的DataSource属性设置为null,然后在方法结束时重新绑定它。尝试避免在重新排序时将DataTable绑定到DataGridView的问题。但是仍然会抛出相同的NullReferenceException。这可能不太理想,因为为每个受影响的列调用一次处理程序(即总是不止一次),并且在列重新排序开始时我似乎没有任何事件可以告诉我并完成了。

我完全可以使用它的唯一方法是执行以下操作(请注意副本):

private void dataGridView_Main_ColumnDisplayIndexChanged(object sender, DataGridViewColumnEventArgs e)
{
    if(!_isDatabinding)
    {
        if(_data.Columns[columnName].Ordinal != e.Column.DisplayIndex)
        {
            var newData = _data.Copy();
            newData.Columns[e.Column.DataPropertyName].SetOrdinal(e.Column.DisplayIndex);
            _data = newData;
        }
    }
}

我真的不想做这个副本,因为数据可能非常大。

如果没有副本,我有什么方法可以做到这一点吗?

1 个答案:

答案 0 :(得分:0)

将datagridview重新绑定到datatable

 DataTable dt = new DataTable();
 foreach(DataGridViewColumn col in dgv.Columns)
    {
   dt.Columns.Add(col.HeaderText);    
    }

   foreach(DataGridViewRow row in dgv.Rows)
   {
     DataRow dRow = dt.NewRow();
    foreach(DataGridViewCell cell in row.Cells)
     {
      dRow[cell.ColumnIndex] = cell.Value;
     }
    dt.Rows.Add(dRow);
   }
相关问题