0

我有一个 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 属性设置器中引发 NullReferenceException。这是调用堆栈:

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;
        }
    }
}

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

有没有什么办法可以在没有副本的情况下做到这一点?

4

1 回答 1

0

将 datagridview 重新绑定到数据表

 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);
   }
于 2013-01-05T05:50:07.600 回答