Удаление из DGV - у индекса [x] нет значения - PullRequest
3 голосов
/ 18 мая 2011

Настройка: У меня есть два DataGridView, каждый из которых связан с BindingList <> пользовательских бизнес-объектов.Эти сетки имеют специальную строку, содержащую математические суммы всех строк в этой сетке - эта специальная строка отражает соответствующий специальный объект в BindingList <> (я указываю это, чтобы вы знали, что это не добавляемая строкав DGV, но объект добавляется в BindingList <>).

Ошибка: Периодически наступает время, когда я должен найти и удалить объект Totals Row из BindingList <> (и, следовательно, из DGV).Вот оригинальный код, который я использовал для этого:

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

(Это не супер важно, но причина, по которой я перебираю все записи, состоит в том, чтобы защитить от возможности того, что их может быть больше, чемодин итоговый ряд, по ошибке).Этот код работает безупречно для одной из двух сеток при любых обстоятельствах.Тем не менее, во второй сетке я получаю следующую ошибку при вызове метода 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' - индекс строки итогов. Я нашел этот вопрос , который, по сути, тот же, за исключением того, что принятым ответом является либо: 1) не использовать базовый список, что я должен сделать, либо 2) удалить из таблицы вместо изсписок.Я попробовал # 2, заменив самый внутренний вызов метода из моего примера кода следующим:

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

Это выдает ту же ошибку. Я также нашел этот вопрос , который предполагает повторное связывание после изменения - однако это неосуществимо, так как возможно, что этот код вызывается один раз в секунду, и если список слишком заполнен, он сделаетэнергосистема непригодна (я знаю это по плохому опыту).

Я мог бы просто обработать событие DataError сетки, но я бы предпочел, чтобы это не выдавало миллион ошибок в минуту, даже если они молчат.Любая помощь будет принята с благодарностью.

Ответы [ 2 ]

2 голосов
/ 18 мая 2011

Итак, это было странное стечение обстоятельств ... но вот так:

1) В рассматриваемой сетке определено событие SelectionChanged, внутри которого вызываются две строки кода:

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

Это здесь, потому что я подделываю сетку в , выглядя как будто есть выбранная строка, хотя на самом деле ее нет. Благодаря этому я могу настроить внешний вид сетки.

2) Событием, которое вызывает код из моего вопроса , является событие Sorted сетки.

Шаги 3 и 4 являются спекуляцией с моей стороны, но мои тесты, похоже, подтверждают теорию

3) Событие Grid.Sorted, по-видимому, также запускает это событие Grid.SelectionChanged.

4) Сетка теперь пытается обновить сетку, а также одновременно удалить итоговую строку. Следовательно, точка останова создает впечатление, что она должна работать, хотя на самом деле это не сработает.

Удаление вызова метода Grid.Refresh () из указанного выше события полностью устраняет проблему. Изучив событие Grid.SelectionChanged рабочей сетки, я обнаружил, что вызывается только метод ClearSelection (), а не Refresh ().

Спасибо тем, кто помогал здесь в ветке и в чате c #!

1 голос
/ 18 мая 2011

Просто переполните свой вопрос.Может ли быть так:

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

...