从DGV删除 - 索引[x]没有值

时间:2011-05-18 13:01:20

标签: c# datagridview bindinglist

设置: 我有两个DataGridViews,每个都绑定到BindingList<>自定义业务对象。这些网格有一个特殊的行,其中包含该网格中所有行的数学总和 - 这个特殊行反映了BindingList中对应的特殊对象<> (我指定这一点,以便您知道这不是添加到DGV的行,而是添加到BindingList<>)的对象。

错误: 有一段时间,我必须定期找到并从BindingList中删除Totals Row对象<> (因此来自DGV)。这是我用来执行此操作的原始代码:

private void RemoveTotalRow()
  {
     for (int i = UnderlyingGridList.Count - 1; i >= 0; i--)
     {
        if (UnderlyingGridList[i].IsTotalRow) UnderlyingGridList.RemoveAt(i);  
     }
  }

(这不是非常重要,但我在所有记录中循环的原因是为了防止错误地存在多个Totals行的可能性)。在所有情况下,此代码可以完美地运行两个网格中的一个。但是,在第二个网格上,当调用RemoveAt方法时,我得到以下错误:

The following exception occurred in the DataGridView:  System.IndexOutOfRangeException: Index 5 does not have a value.    at System.Windows.Forms.CurrencyManager.get_Item(Int32 index)    at System.Windows.Forms.DataGridView.DataGridViewDataConnection.GetError(Int32 rowIndex)  To replace this default dialog please handle the DataError event.

...其中'5'是总计行的索引。 I found this question,基本上是相同的,除了接受的答案是:1)不使用我必须做的基础列表,或2)从网格而不是从列表中删除。我已经尝试过#2,用上面的代码示例替换最里面的方法调用:

if (UnderlyingGridList[i].IsTotalRow) brokenDataGrid.Rows.RemoveAt(i);

这会引发同样的错误。 I also found this question,它建议在更改后重新绑定 - 但是,这是不可行的,因为此代码可能每秒调用一次,如果列表填充太多,则会使网格无法使用(我知道这个来自糟糕的经历)。

我可以处理网格的DataError事件,但我宁愿不让每分钟出现一百万个错误,即使它们是静默的。任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:2)

所以这是一个奇怪的情况......但是这里有:

1)有问题的网格定义了一个SelectionChanged事件,其中调用了两行代码:

Grid.ClearSelection(); 
Grid.Refresh(); 

这些是因为我将网格伪装成就像有一个选定的行,而实际上没有一个。通过这样做,我可以自定义网格的外观。

2)触发代码来自我的问题的事件是网格的 Sorted 事件。

第3步和第4步是我的推测,但我的测试似乎支持这一理论

3)Grid.Sorted事件显然也会触发此Grid.SelectionChanged事件。

4)网格现在正在尝试刷新网格并同时删除总计行。因此,断点使它看起来好像应该有效,而实际上它不会。

从上面的事件中删除Grid.Refresh()方法调用可以完全解决问题。在检查工作网格的Grid.SelectionChanged事件时,我发现只调用了ClearSelection()方法,而不是Refresh()。

感谢那些在线程和c#聊天帮助的人!

答案 1 :(得分:1)

只是溢出你的问题。可能就是这样:

for (int i = UnderlyingGridList.Count - 1; i >= 0; i--)

需要成为这个:

for (int i = UnderlyingGridList.Count - 1; i >= 0; i--)
i+=1

这是一个简短的例子。只需添加一个DataGridView(有2列)和两个按钮就可以了。这是VB.Net。

Public Class Form1

    Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
        Me.Button1.Text = "Create"
        Me.Button2.Text = "Remove"

        Me.DataGridView1.AllowUserToAddRows = False
    End Sub

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        For i As Integer = 0 To 99
            Me.DataGridView1.Rows.Add("Hello", DateTime.Now)
        Next
    End Sub

    Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
        Dim i As Integer = Me.DataGridView1.Rows.Count - 1
        Do
            If Me.DataGridView1.AllowUserToAddRows = False Then
                If i < 0 Then Exit Do
                Me.DataGridView1.Rows.RemoveAt(i - 0)
            Else
                If i < 1 Then Exit Do
                Me.DataGridView1.Rows.RemoveAt(i - 1)
            End If
            i -= 1
        Loop
    End Sub
End Class

注意Me.DataGridView1.AllowUserToAddRows = False