Problem beim Entfernen eines Datensatzes aus einem gebundenen Data

27/06/2008 - 10:03 von Christoph Michalski | Report spam
Hallo,
die Daten aus einer Access2000-Datenbank werden zunàchst in eine DataTable
"TestDT" eingelesen, die dann im 2.Schritt mit einen DataGridView über
DataSource gebunden wird.
Nun muß ich immer wieder eine oder mehrere Zeilen entfernen. Wenn ich den
Datensatz über Remove-Funktion entferne, dann làuft alles gut, wenn ich das
aber über Delete-Funktion mache dann bekomme ich Probleme mit dem Row-Index:
1. Remove-Beispiel:
Private SubTestDT_CellClick(ByVal sender As Object, ByVal e As
System.Windows.Forms.DataGridViewCellEventArgs) Handles TestDT.CellClick

If e.ColumnIndex = 0 Then TestDT.Rows.Remove(TestDT.Rows(e.RowIndex))

End Sub

2. Delete-Beispiel:
...
Dim Row As DataRow = TestDT.Rows(e.RowIndex)
Row.Delete()
...

Im 2. Beispiel wird beim ersten Mal der richtige Datensatz entfernt, bei
nàchsten aber ein Falscher. Wieso stimmt dann der RowIndex des DataGridView
mit dem des DataTable nicht mehr überein? Wie muß ich den Code schreiben,
damit es richtig funktioniert?
Bemerkung: ich brauche die "Delete"-alternative, weil ich den Abgleich mit
der Datenbank erst beim Verlassen des Fensters und nicht nach jeder Änderung
vornehmen möchte!
Gruß
Christoph
 

Lesen sie die antworten

#1 Peter Götz
27/06/2008 - 12:03 | Warnen spam
Hallo Christoph,

die Daten aus einer Access2000-Datenbank werden
zunàchst in eine DataTable "TestDT" eingelesen, die
dann im 2.Schritt mit einen DataGridView über
DataSource gebunden wird.



Besser wàre eine Bindung über eine konkrete
DataView zu Deiner DataTable

Private mDV as DataView
Private WithEvents mCM as CurrencyManager

Private Sub AnySub()
mDV = new DataView(TestDT)
DGV.DataSource = mDV

' und zum Navigieren und erkennen von
' Datensatzwechseln in mcm_PositionChanged-
' Ereignis gleich noch den passenden
' CurrencyManager dazu

mCM = _
directCast _
(me.BindingContext(mDV), _
CurrencyManager)

End Sub


Nun muß ich immer wieder eine oder mehrere Zeilen
entfernen.



Dazu brauchst Du doch nur im DataGridView die
entsprechende Zeile auswàhlen (z.B. Mausklik auf
den RowHeader) und dann die Entf-Taste auf
der Tastatur zu drücken.

Wenn ich den Datensatz über Remove-Funktion
entferne, dann làuft alles gut, wenn ich das
aber über Delete-Funktion mache dann bekomme
ich Probleme mit dem Row-Index:
1. Remove-Beispiel:
Private SubTestDT_CellClick(ByVal sender As Object, ByVal e As
System.Windows.Forms.DataGridViewCellEventArgs) Handles TestDT.CellClick



Wieso löschst Du einen Datensatz im
DataGridView_CellClick-Ereignis?
Ich denke, eine solche Bedienungsweise
dürfte den jeweiligen Benutzer eher verwirren.

If e.ColumnIndex = 0 Then TestDT.Rows.Remove(TestDT.Rows(e.RowIndex))

End Sub

2. Delete-Beispiel:
...
Dim Row As DataRow = TestDT.Rows(e.RowIndex)



e.RowIndex kann mit dem RowIndex der DataTable
übereinstimmen, muss es aber nicht.
Spàtestens dann, wenn der Benutzer z.B. via Mausklick
auf einen Spaltenkopf im Grid die Sortierung der
Datensàtze geàndert hat, sind e.RowIndex und der
Zeilenindex der zugehörigen Row in der DataTable
nicht mehr synchron.

Auch wenn Du eine DataTable via

DGV.DataSource = DeineDataTable

an das Grid bindest, ist die tatsàchliche DataSource
für das Grid immer eine DataView. In Deinem Fall
eben eine vom DGV implizit erzeugte DataView.

Row.Delete()
...

Im 2. Beispiel wird beim ersten Mal der richtige
Datensatz entfernt, bei nàchsten aber ein Falscher.
Wieso stimmt dann der RowIndex des DataGridView
mit dem des DataTable nicht mehr überein?
Wie muß ich den Code schreiben,
damit es richtig funktioniert?



Private Sub DGV_CellClick _
(ByVal sender as Object, _
ByVal e as DataGridViewCellEventArgs _
) Handles DGV_CellClick

if e.ColumnIndex = 0 then
Dim DV as DataView = _
DirectCast(DGV.DataSource, DataView)

Dim DRV As DataRowView = _
DV.Item(e.RowIndex)

Dim DR as DataRow = DRV.Row

DR.Delete
end if
End Sub

Bemerkung: ich brauche die "Delete"-alternative,
weil ich den Abgleich mit der Datenbank erst
beim Verlassen des Fensters und nicht nach
jeder Änderung vornehmen möchte!



Was hat das Eine mit dem Anderen zu tun?
Ob und wann ein Datensatz gelöscht wird, kannst
Du doch im Code selbst bestimmen.
Wenn Du einen DS durch Drücken der Entf-Taste
im DGV oder durch DataTable.Rows(x).Delete löschst,
ist das vom Ergebnis her das selbe.
Der DS hat den RowState Deleted, ist also lediglich
als gelöscht markiert. Erst ein DataAdapter.Update
würde nun erkennen, dass der DS als gelöscht markiert
ist und der DataAdapter.DeletetCommand würde den
betr. Datensatz aus der DB löschen.

Schau Dir mal das nachfolgende Beispiel an.
Damit kann ein Datensatz durch Anklicken des Buttons
"Delete Record" und/oder durch Markieren einer Zeile
im DGV mit anschl. Drücken der Entf-Taste auf der
Tastatur gelöscht werden.

Public Class Form1
Private WithEvents DGV As DataGridView
Private WithEvents btnDelete As Button
Private mDT As DataTable
Private mDV As DataView
Private mCM As CurrencyManager

Private Sub Form1_Load _
(ByVal sender As System.Object, _
ByVal e As System.EventArgs _
) Handles MyBase.Load

Me.Size = New Size(320, 420)
CreateControls()

CreateData()

With DGV
.DataSource = mDV
.AutoResizeColumns()
.AutoResizeRows()
End With
End Sub

Private Sub CreateControls()
DGV = New DataGridView
With DGV
.SetBounds _
(10, 10, _
Me.ClientSize.Width - 20, _
Me.ClientSize.Height - 70)

.Anchor = AnchorStyles.Left Or _
AnchorStyles.Top Or _
AnchorStyles.Right Or _
AnchorStyles.Bottom

.DefaultCellStyle.Font = _
New Font("Arial", 12)

.ColumnHeadersDefaultCellStyle.Font = _
New Font("Arial", 8, FontStyle.Bold)
End With
Me.Controls.Add(DGV)

btnDelete = New Button
With btnDelete
.SetBounds(Me.ClientSize.Width - 110, _
DGV.Bottom + 10, _
100, 40)
.Anchor = AnchorStyles.Right Or _
AnchorStyles.Bottom
.Text = "Delete Record"
End With
Me.Controls.Add(btnDelete)
End Sub

Private Sub CreateData()
Dim i As Integer
Dim DR As DataRow

mDT = New DataTable
With mDT
.Columns.Add("ID", GetType(Integer))
.Columns.Add("SText", GetType(String))
.Columns.Add("LText", GetType(String))
.Columns.Add("Bool", GetType(Boolean))

For i = 1 To 12
DR = .NewRow
DR.Item(0) = i
DR.Item(1) = MonthName(i, True)
DR.Item(2) = MonthName(i, False)
DR.Item(3) = (i Mod 2 = 0)
.Rows.Add(DR)
Next
.AcceptChanges()
End With

mDV = New DataView(mDT)

mCM = _
DirectCast(Me.BindingContext(mDV), _
CurrencyManager)
End Sub

Private Sub DGV_KeyDown _
(ByVal sender As Object, _
ByVal e As System.Windows.Forms.KeyEventArgs _
) Handles DGV.KeyDown

If e.KeyData = Keys.Space Then
DGV.CurrentCell = DGV.CurrentRow.Cells(3)
End If
End Sub

Private Sub btnDelete_Click _
(ByVal sender As Object, _
ByVal e As System.EventArgs _
) Handles btnDelete.Click

If mCM.Position > -1 Then
Dim DRV As DataRowView = _
mDV.Item(mCM.Position)

Dim DR As DataRow = DRV.Row
DR.Delete()
End If
End Sub
End Class
' \\\ E N T E

Ob und wann solche DS-Löschungen letztlich
in der DB auch ausgeführt werden, hàngt davon
ab, wann Du z.B. ein entsprechendes
DataAdapter.Update für Deine zugrundeliegende
DataTable (mDT) ausführst.

Gruß aus St.Georgen
Peter Götz
www.gssg.de (mit VB-Tipps u. Beispielprogrammen)

Ähnliche fragen