Entwickler-Ecke
WinForms - GridView Insert Absturz
Schmido - Do 25.02.10 22:06
Titel: GridView Insert Absturz
Hallo,
ich habe zum Insert die Methode hergenommen:
C#-Quelltext
1: 2: 3: 4: 5:
| private void dataGridView_EingabeKategorie_RowsAdded(object sender, DataGridViewRowsAddedEventArgs e) { int i1 = e.RowIndex; this.kategorieTableAdapter.Insert((string)this.dataGridView_EingabeKategorie.Rows[i1].Cells["kategorie_name"].Value, (bool)this.dataGridView_EingabeKategorie.Rows[i1].Cells["kategorie_typ"].Value); } |
Sobald das Fenster gerufen wird, kommt folgende Meldung im VS2010:
"Object reference not set to an instance of an object."
Wieso??
Edit:
Ich habe gesehen, dass diese Methode bereits beim Erstellen des Fensters pro Datensatz gerufen wird.
Ist das nicht die Methode, zum Hinzufügen, wenn das Fenster offen ist?
Schließlich will ich ja nicht ein zusätzliches Insert machen.
JüTho - Fr 26.02.10 10:05
Hallo und :welcome:
Ich habe nicht verstanden, was du eigentlich machen willst; dafür sind es zu wenig Anweisungen. Dein Hauptproblem dürfte darin liegen, dass du nicht zwischen DataGridView und DataSet/DataTable (die sich im TableAdapter verstecken) unterscheidest.
Das DataGridView ist - wie schon der Name sagt - dazu da, dass Daten in einem Grid zur Anzeige gebracht werden (und bei Bedarf vom Anwender geändert werden können). Wenn sich der Programmierer um die Daten kümmert, sollte er in der Regel nicht das DGV bearbeiten, sondern die DataTable. Das gilt vor allem bei der Zuordnung von Standardwerten u.ä.
Wenn du die SDK-Doku/MSDN/Hilfe nach RowAdded-Ereignis durchliest, wirst du feststellen, dass RowIndex kritisch zu verarbeiten ist. Das kann dazu führen, dass Rows[i] nicht vorhanden ist und zur NullReferenceException führt.
Übrigens: Benutze immer die korrekten Begriffe. GridView ungleich DataGridView ungleich DataGrid (Win) ungleich DataGrid (Web).
Gruß Jürgen
Schmido - Sa 27.02.10 09:55
Hallo und guten Morgen,
ok, ich fang mal an, was ich gemacht habe.
Ich habe in ein Fenster die DataGridView gezogen.
Die Daten stammen aus dem BindingSource.
Dort sollen Daten hinzugefügt, gelöscht und geändert werden können.
Leider funktioniert weder ein Update noch ein hinzufügen.
Welche Events muss ich verwenden?
Du schreibst, dass das mit dem Index kritisch sein kann - wie kann ich es besser lösen?
Vielen Dank!
JüTho - Sa 27.02.10 13:05
Schmido hat folgendes geschrieben : |
Ich habe in ein Fenster die DataGridView gezogen.
Die Daten stammen aus dem BindingSource. |
Und die BindingSource ist an eine DataTable gebunden, nicht wahr? Also ist die
DataTable die Datenmenge, mit der gearbeitet wird.
Schmido hat folgendes geschrieben : |
Dort sollen Daten hinzugefügt, gelöscht und geändert werden können.
Leider funktioniert weder ein Update noch ein hinzufügen. |
"Dort" muss sich also unbedingt auf die DataTable beziehen!
Schmido hat folgendes geschrieben : |
| Welche Events muss ich verwenden? |
Wenn du auf etwas
reagieren willst, dann auf Ereignisse der DataTable. Wenn du etwas
selbst machen (= veranlassen oder auslösen) willst, dann brauchst du (eigene) Methoden, die die DataTable benutzen.
Schmido hat folgendes geschrieben : |
| Du schreibst, dass das mit dem Index kritisch sein kann - |
Das ergibt sich aus der
SDK-Doku/MSDN/Hilfe.
Schmido hat folgendes geschrieben : |
| wie kann ich es besser lösen? |
Dazu weiß ich immer noch nicht, wer wann wie einen neuen Datensatz erzeugen will und wer wann wie das Update ausführen oder auslösen soll.
Gruß Jürgen
Schmido - Sa 27.02.10 14:22
Hallo,
das Hinzufügen soll über das "*" links erfolgen.
Ändern per Doppelklick.
Das Funktioniert ja auch in der Ansicht.
Nur wird es nicht in die Tabelle geschrieben.
Solange das Programm offen ist, ist auch die Änderung da...nur wenn es wieder zugemacht wird, ist es das alte.
Für das Edit zum Beispiel habe ich folgendes Event verwendet:
C#-Quelltext
1: 2: 3: 4: 5:
| private void dataGridView_EingabeKategorie_CellEndEdit(object sender, DataGridViewCellEventArgs e) { int i1 = e.RowIndex; this.kategorieTableAdapter.Update((string)this.dataGridView_EingabeKategorie.Rows[i1].Cells["kategorie_name"].Value, (bool)this.dataGridView_EingabeKategorie.Rows[i1].Cells["kategorie_typ"].Value, (int)this.dataGridView_EingabeKategorie.Rows[i1].Cells["kategorie_id"].Value); } |
Aber wird nicht in die DB geschrieben.
Gibt es nicht ein Standard-Event für das Hinzufügen?
JüTho - Sa 27.02.10 14:58
Schmido hat folgendes geschrieben : |
| das Hinzufügen soll über das "*" links erfolgen. |
Aha. Dann wird durch die Bindung an BindingSource und DataTable automatisch die neue Zeile in der DataTable angelegt. Das bestätigst du auch durch:
Schmido hat folgendes geschrieben : |
| Solange das Programm offen ist, ist auch die Änderung da...nur wenn es wieder zugemacht wird, ist es das alte. |
Schmido hat folgendes geschrieben : |
| Ändern per Doppelklick. |
Das verstehe ich nicht. Wo klickst du doppelt? In der Regel wird eine Zelle im DGV automatisch durch einen einfachen Klick in den Edit-Modus gesetzt; dann kann sofort geändert werden.
Schmido hat folgendes geschrieben : |
Das Funktioniert ja auch in der Ansicht.
Nur wird es nicht in die Tabelle geschrieben. |
Du musst "irgendwo" - z.B. durch einen Button.Click - den Befehl TableAdapter.Update aufrufen, aber eine einfache Version, die sich auf alle Änderungen bezieht, und nicht eine solch komplizierte, die einige einzelne Zellen benutzen soll. Das sieht etwa so aus:
C#-Quelltext
1: 2: 3: 4: 5:
| private void saveButton_Click(object sender, EventArgs e) { myBindingSource.EndEdit(); kategorieTableAdapter.Update(kategorieTable); } |
Du beendest ausdrücklich die aktuelle Eingabe; das ist bei BindingSource bzw. DataGridView notwendig. Dadurch wird die Bearbeitung der aktuellen Zeile abgeschlossen; die aktuellen Werte werden in die
DataTable übertragen. Durch den
Update-Befehl werden alle Änderungen aus der DataTable (hier kategorieTable genannt) in die Datenbank übertragen.
Es müssen
Voraussetzungen erfüllt sein: Der SelectCommand, der zu diesem TableAdapter gehört, darf sich nur auf eine einzige Tabelle beziehen und muss den PrimaryKey enthalten. Nur dann sind InsertCommand, UpdateCommand, DeleteCommand vorhanden. Wenn die Voraussetzungen nicht passen, musst du die Änderungsbefehle vorher manuell erstellen.
Schmido hat folgendes geschrieben : |
| Für das Edit zum Beispiel habe ich folgendes Event verwendet: ... dataGridView_EingabeKategorie_CellEndEdit... |
Das hat mit dem Edit insgesamt wenig zu tun, wie sich aus den Erläuterungen in der
SDK-Doku/MSDN/Hilfe zum CellEndEdit-Ereignis ergibt.
Schmido hat folgendes geschrieben : |
| Aber wird nicht in die DB geschrieben. |
Wie gesagt: automatisch tut sich gar nichts. Du musst den Update-Befehl an einer sinnvollen Stelle in sinnvollem Zusammenhang bewusst aufrufen.
Schmido hat folgendes geschrieben : |
| Gibt es nicht ein Standard-Event für das Hinzufügen? |
Auch hier gilt: Was automatisch möglich ist, hast du durch die Auswahl der neuen Zeile durch '*' schon gesteuert. Alles andere müsste (wenn es gewünscht wird) durch den Aufruf einer passenden Methode an einer sinnvollen Stelle in sinnvollem Zusammenhang bewusst geschehen.
Bist du sicher, dass du den Begriff
Event immer richtig verwendest? Mir kommt es vor, als wenn du es mit
Methode verwechselst. Ein Ereignis (= Event) ist etwas, was "irgendwo" im Programm ausgelöst wird und dann behandelt werden soll; dazu gibt es die EventHandler (= Ereignisbehandlungsmethode). Eine Methode ist dagegen ein Block von Befehlen/Anweisungen, der zusammenhängend ausgeführt wird und vom Programmierer in bestimmten Situationen gezielt aufgerufen wird. (In anderen Programmiersprachen spricht man von Funktionen und Prozeduren o.ä.)
Zur Einarbeitung in die
Arbeit mit Datenbanken unter .NET solltest du dir etwas wie das
Openbook VC# [
http://openbook.galileocomputing.de/visual_csharp/] Kap. 25 ff. durcharbeiten.
Gruß Jürgen
Schmido - Sa 27.02.10 15:39
Also muss ich einen separaten Speicher Button auf das Fenster legen um die Speichern Methode aufzurufen?
Habe gedacht, dass das auch so geht in einer GridView.
Ich spreche von Events, da dies im VS2010 so heißt, wo ich die Methoden hinterlegt habe.
Auch wenn ich per Speichern Button das ganze mache:
C#-Quelltext
1: 2: 3: 4: 5:
| private void btnSpeichern_Click(object sender, EventArgs e) { kategorieBindingSource.EndEdit(); kategorieTableAdapter.Update(this.haushaltDataSet.kategorie); } |
Kommt es nicht richtig in der DB an.
Wenn ich aber Debuge, ist in
this.haushaltDataSet.kategorie der richtige Inhalt vorhanden, so wie er geändert wurde.
JüTho - Sa 27.02.10 16:07
Dann müssen wir uns erst einmal darauf konzentrieren:
Schmido hat folgendes geschrieben : |
| Wenn ich aber Debuge, ist in this.haushaltDataSet.kategorie der richtige Inhalt vorhanden, so wie er geändert wurde. |
Das wichtigste scheint mir zu sein: Was steht unter
InsertCommand.CommandText und
UpdateCommand.CommandText?
[Offtopic]Es rächt sich jetzt, dass du mit dem Datenmonster TableAdapter arbeitest. Der nimmt zwar Anfängern manche Schritte ab, aber versteckt sehr viel im Hintergrund und erschwert IMHO dadurch das Verständnis. Es wird jetzt auch schwierig, die SQL-Befehle herauszusuchen. Vielleicht bringt es etwas, wenn du in der Designer.cs mit der Suchen-Funktion nach den Befehlen schaust. Sind sie überhaupt enthalten?[/Offtopic]
Schmido hat folgendes geschrieben : |
| Also muss ich einen separaten Speicher Button auf das Fenster legen um die Speichern Methode aufzurufen? |
Es ist kein Muss, aber in der Arbeitspraxis erheblich sinnvoller.
Schmido hat folgendes geschrieben : |
| Habe gedacht, dass das auch so geht in einer GridView. |
Nicht standardmäßig, sondern nur dadurch, dass es in ein passendes Ereignis eingebaut wird. CellEndEdit passt aber, wie gesagt, nicht. Außerdem:
| Zitat: |
| Benutze immer die korrekten Begriffe. GridView ungleich DataGridView ungleich DataGrid (Win) ungleich DataGrid (Web). |
Schmido hat folgendes geschrieben : |
| Ich spreche von Events, da dies im VS2010 so heißt, wo ich die Methoden hinterlegt habe. |
So stimmt es mit Sicherheit nicht. Aber vielleicht liest du auch nur darüber hinweg, wie du auch nicht zwischen DataGridView und GridView unterscheiden willst. Aber es bringt nichts, wenn wir das jetzt vertiefen; du solltest wirklich zwischen Event/Ereignis, EventHandler (spezielle Methoden) und Methoden (allgemein) unterscheiden.
Jürgen
Schmido - Sa 27.02.10 17:36
Insert.Command:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23:
| public virtual int Insert(string kategorie_name, bool kategorie_typ) { if ((kategorie_name == null)) { throw new global::System.ArgumentNullException("kategorie_name"); } else { this.Adapter.InsertCommand.Parameters[0].Value = ((string)(kategorie_name)); } this.Adapter.InsertCommand.Parameters[1].Value = ((bool)(kategorie_typ)); global::System.Data.ConnectionState previousConnectionState = this.Adapter.InsertCommand.Connection.State; if (((this.Adapter.InsertCommand.Connection.State & global::System.Data.ConnectionState.Open) != global::System.Data.ConnectionState.Open)) { this.Adapter.InsertCommand.Connection.Open(); } try { int returnValue = this.Adapter.InsertCommand.ExecuteNonQuery(); return returnValue; } finally { if ((previousConnectionState == global::System.Data.ConnectionState.Closed)) { this.Adapter.InsertCommand.Connection.Close(); } } } |
Update.Command:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24:
| public virtual int Update(string kategorie_name, bool kategorie_typ, int kategorie_id) { if ((kategorie_name == null)) { throw new global::System.ArgumentNullException("kategorie_name"); } else { this.Adapter.UpdateCommand.Parameters[0].Value = ((string)(kategorie_name)); } this.Adapter.UpdateCommand.Parameters[1].Value = ((bool)(kategorie_typ)); this.Adapter.UpdateCommand.Parameters[2].Value = ((int)(kategorie_id)); global::System.Data.ConnectionState previousConnectionState = this.Adapter.UpdateCommand.Connection.State; if (((this.Adapter.UpdateCommand.Connection.State & global::System.Data.ConnectionState.Open) != global::System.Data.ConnectionState.Open)) { this.Adapter.UpdateCommand.Connection.Open(); } try { int returnValue = this.Adapter.UpdateCommand.ExecuteNonQuery(); return returnValue; } finally { if ((previousConnectionState == global::System.Data.ConnectionState.Closed)) { this.Adapter.UpdateCommand.Connection.Close(); } } } |
Wie soll man auch in einer Englischen Version zwischen Event und Ereignis unterscheiden :)
JüTho - Sa 27.02.10 17:56
Ich vermisse etwas wie:
SQL-Anweisung
1:
| INSERT INTO Kategorie (ID, Name...) VALUES (@ID, @Name ...) |
Entsprechend so:
SQL-Anweisung
1:
| UPDATE Kategorie SET ID = @ID, Name = @Name ... WHERE ... |
Aber da ich nicht mit dem Datenmonster TableAdapter arbeite, kann ich keinen Hinweis darauf geben, wo und wie solche Befehle zu finden sind. Ich weiß nur: Wenn du den SELECT-Befehl mit dem Designer erstellt hast und die von mir genannten Voraussetzungen erfüllt sind, müssten auch INSERT und UPDATE irgendwo stehen.
Wenn solche Befehle tatsächlich nicht zu finden sind, dann hat sie der Table-Designer nicht erstellt (warum auch immer). Dann ist es auch überhaupt kein Wunder, dass Änderungen nicht in die Datenbank übertragen werden.
Dann kannst du den TableAdapter.Update-Befehl an noch so vielen Stellen aufrufen; es tut sich nichts.
Event ist gleich Ereignis; das ist nur die Übersetzung. Aber "Methode" ist "method", und "event" ist
ungleich "method".
Jürgen
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!