Entwickler-Ecke

WinForms - Verbindung zwischen DataSet und DataGridView?


BlackMatrix - Do 22.09.11 22:13
Titel: Verbindung zwischen DataSet und DataGridView?
Hi.

Ich habe mir ein nicht typisiertes DataSet und ein DGV angelegt. DataSource des DGV ist das DataSet mit einer DataTable als Member.
Nun möchte ich gerne, dass sobald der User einen Button oder Ähnliches klickt mit meinen Objekten gearbeitet wird.

Ich gehe mal davon aus, dass nun z.B. das Objekte Erzeugen und die notwendigen Daten für die Objekte aus der DataTable entnommen werden müssen und nicht aus dem DGV, denn wenn sich im DGV z.B. die Anordnung durch den Benutzer ändert, kann z.B. das Durchlaufen aller Reihen zum Fehlverhalten führen.
Daher meine Frage, liege ich richtig, dass man immer mit der dahinterliegenden DataTable arbeiten sollte oder gibt es auch Ausnahmen, wo man mal direkt die Werte aus dem DGV ließt?
Wenn ich nun z.B. eine Zeile im DGV markiert habe, dann muss ich ja immer erst aus der Zeile im DGV (DataGridViewRow) die Zeile in der DataTable (DataRow) ausfindig machen (DataRow.Find()) um mit dieser zu arbeiten? Irgendwie ist das nervtötend :-/

Wenn man das wirklich mit dem Find machen sollte, dann hätte ich dazu eine Frage, wie kann man damit eine Reihe finden, wenn der Primärschlüssel aus 2 Werten besteht?

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
        private void toolStripMenuItemStart_Click(object sender, EventArgs e)
        {
            var muh = dataGridViewData.SelectedRows[0].Cells[0].Value;
            var maeh = dataGridViewData.SelectedRows[0].Cells[3].Value;
            var test = dataTableData.Rows.Find(new object[]{muh,maeh});
            //...
        }


MfG


mats74 - Fr 23.09.11 07:35

Hallo BlackMatrix

user profile iconBlackMatrix hat folgendes geschrieben Zum zitierten Posting springen:
Hi.
Daher meine Frage, liege ich richtig, dass man immer mit der dahinterliegenden DataTable arbeiten sollte oder gibt es auch Ausnahmen, wo man mal direkt die Werte aus dem DGV ließt?


Der User in meinen Projekten arbeitet ausschliesslich im Dgv direkt und kann dort beliebige Manipulationen der Daten, Zeilen und Spalten vornehmen. Die geänderten Daten des Dgv's werden dann bei einem beliebigen Prozess in das DataSet (oder SQL-DB Tabelle) gespeichert, indem ich die entsprechenden Zeilen ersetze (löschen / erzeugen anhand einer Kennung). Somit hast Du die maximale Funktionalität des Dgv's zur Verfügung und musst dich während der Bearbeitung nicht um die "gespeicherten Daten" kümmern. Wie Du schon erwähnt hast, wäre dies bei komplexeren Manipulationen ansonsten sehr schwierig umzusetzen.

Da gibt es sicherlich noch andere Meinungen :wink: .


Th69 - Fr 23.09.11 09:47

Hallo BlackMatrix,

über die Eigenschaft DataGridViewRow.DataBoundItem kommst du direkt zu der Row in der DataTable.
Du mußt dann nur entsprechend casten:

C#-Quelltext
1:
DataRow row = dataGridViewRow.DataBoundItem as DataRow;                    


BlackMatrix - Fr 23.09.11 13:31

Hatte schon beim Schreiben meines Beitrages vermutet, dass nicht so ganz ersichtlich ist, was ich möchte.

user profile iconmats74 hat folgendes geschrieben Zum zitierten Posting springen:
Hallo BlackMatrix
Der User in meinen Projekten arbeitet ausschliesslich im Dgv direkt und kann dort beliebige Manipulationen der Daten, Zeilen und Spalten vornehmen.


Ja genau, das tut er bei mir auch, aber ich habe z.B. folgendes Szenario:

user defined image

Also habe ich in meiner MainForm eine Liste der Daten angelegt:


C#-Quelltext
1:
private List<Person> Data= new List<Person>();                    


Um dann über die Methoden Start, Stop, usw. mit den Objekten Arbeiten zu können.

Und mir stellt sich die Frage, wie ich denn möglichst effizient, die Datenbindung zwischen der geklickten ToolStripMenuItem (Start, Stop, ...) und dem Objekt mit dieser Methode ohne bei jedem Klick des ToolStripMenuItem erst herausfinden zu müssen, ob sich in der Liste bereits ein Objekt davon befindet, dann erzeugen, ansonsten das richtige Objekt nehmen und die Methode aufrufen.

Ich ahne schon, dass es auf die BindingList hinausläuft, aber irgendwie hat mir die beim letzten Mal nicht zugesagt.

user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
Hallo BlackMatrix,

über die Eigenschaft DataGridViewRow.DataBoundItem kommst du direkt zu der Row in der DataTable.
Du mußt dann nur entsprechend casten:

C#-Quelltext
1:
DataRow row = dataGridViewRow.DataBoundItem as DataRow;                    


Das ist gut zu wissen :) Danke


mats74 - Fr 23.09.11 14:39

Hallo BlackMatrix

Ich habe deine Ausgangslage nachgebaut und habe bis jetzt auch keine Lösung (Vielleicht habe ich auch dein Problem nicht ganz verstanden :gruebel: ).
Wenn ich dich richtig verstehe, willst Du eine direkte Zuweisung der selektierten Dgv-Zeile zum List-Eintrag oder DataTableRow, den Du dann anhand der Dgv-Einträge editieren willst (ohne irgendwelche Abfragen an die DataTable).
Dazu fällt mir eigentlich nur die Übergabe eines eindeutigen ID-Wertes ein (z.B. 2 Tabellen mit Beziehung), den jeder Eintrag beinhaltet.
Die Editierung der DataTable-Eintrages kannst Du dann mit einer eindeutigen ID bewerkstelligen.
Da entfällt lediglich die Abfrage für die List oder DataTableRow.


BlackMatrix - Fr 23.09.11 15:49

Ich will die verschiedenen Methoden der Objekte Person mit dem ToolStripMenuItemClick Ereignis aufrufen. Dabei will ich, je nachdem was für Zeilen markiert sind, genau diese Objekte verwenden. Bisher habe ich es so gemacht, dass über die SelectedRows Property des DGV die Zeilen in der DataTable gesucht und dann in der List<Person> geschaut habe, ob schon so ein Objekt vorhanden ist. Wenn nicht, habe ich ein Objekt erzeugt.

Scheint mir aber irgendwie sehr umständlich, denn das muss ich machen, wenn ich Start, Stop, oder eine der anderen 10 Methoden aufrufen möchte.
Schöne wäre es, wenn ich direkt nach dem Click das Objekt in der "Hand" haben würde.

Mir ist gerade die Idee gekommen, dass ich erstmal ein Ereignis des DataGridView verwende, welches beim hinzufügen einer neuen Row, erstmal ein Objekt erzeugt und in die Liste reinlegt.

Scheint mir aber irgendwie alles nicht ganz lehrbuchgetreu :-/

Liebe Grüße


Kha - Fr 23.09.11 15:52

user profile iconBlackMatrix hat folgendes geschrieben Zum zitierten Posting springen:
Schöne wäre es, wenn ich direkt nach dem Click das Objekt in der "Hand" haben würde.
Was der Code von Th69 doch genau erfüllt. In deinem Fall dann eben ein Cast nach Person statt DataRow.


BlackMatrix - Fr 23.09.11 16:32

user profile iconKha hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconBlackMatrix hat folgendes geschrieben Zum zitierten Posting springen:
Schöne wäre es, wenn ich direkt nach dem Click das Objekt in der "Hand" haben würde.
Was der Code von Th69 doch genau erfüllt. In deinem Fall dann eben ein Cast nach Person statt DataRow.


Das funktioniert aber nur, wenn das DGV die DataSource von Typ Person hat, oder? Mein DataSet, welches die DataSource darstellt, habe ich aber mit dem Anlegen einzelner Spalten gemacht.


Kha - Fr 23.09.11 17:07

Du hast eine List<Person> und eine DataTable? Warum nicht direkt die Liste binden?


BlackMatrix - Fr 23.09.11 17:30

user profile iconKha hat folgendes geschrieben Zum zitierten Posting springen:
Du hast eine List<Person> und eine DataTable? Warum nicht direkt die Liste binden?


Eine normale Liste binden ist ja nicht möglich, oder geht das noch irgendwie anders?

Bei der BindingList habe ich wieder das Problem, dass meine Unterklassen in der Klasse Person mit angezeigt werden und auch Properties dann im DGV angezeigt werden, die ich gar nicht möchte.
Daher habe ich mir eine DataTable angelegt, die dann die Werte, die ich angegeben habe, dem Objekt zuweise. Sehr unschön, aber auch aufwendig.

Oder vielleicht die List<Person> gleich ganz weglassen und nur das Listarray der Row der Klasse Person übergeben?


Kha - Fr 23.09.11 19:14

user profile iconBlackMatrix hat folgendes geschrieben Zum zitierten Posting springen:
Eine normale Liste binden ist ja nicht möglich, oder geht das noch irgendwie anders?
Ich weiß ja nicht, was du unter "anders" verstehst, aber ist eigentlich kein Problem [http://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.datasource.aspx].

user profile iconKha hat folgendes geschrieben Zum zitierten Posting springen:
Bei der BindingList habe ich wieder das Problem, dass meine Unterklassen in der Klasse Person mit angezeigt werden und auch Properties dann im DGV angezeigt werden, die ich gar nicht möchte.
Was für Unterklassen? Und warum gibst du die gewollten Spalten nicht einfach selbst an?


BlackMatrix - Fr 23.09.11 20:31

user profile iconKha hat folgendes geschrieben Zum zitierten Posting springen:
Was für Unterklassen? Und warum gibst du die gewollten Spalten nicht einfach selbst an?


Okay, ob ich nun eine BindingList nehme oder eine BindingSource mit einer Liste verknüpfe scheint wohl am Ende das selbe zu sein.

Was meinst du mit die gewollten Spalten nicht einfach selbst angeben? Wenn ich dem DGV die DateSource mitgebe, was in meinem Fall dann die BindingSource von meiner List<Person> ist, dann werden doch automatisch alle Properties, die public sind, als Spalten in meinem DGV angelegt. Ich habe aber nur einen kleinen Teil meiner Properties, die ich angezeigt bekommen möchte.
Desweiteren befinden sich in mein Klasse Person, eine weitere Klasse (Unterklasse), aus der ich auch 2 Properties im DGV anbinden möchte.

Kannst du mir das bitte nochmal genauer erklären?


Th69 - Sa 24.09.11 09:01

Hallo BlackMatrix,

du kannst beim DGV die Eigenschaft AutoGenerateColumns auf 'false' setzen und dann die einzelnen Spalten bei "Columns" definieren (und mit der Eigenschaft DataPropertyName die zu bindende Eigenschaft angeben).

Such mal im Internet nach "DataGridView FAQ" - es gibt eine DOC Datei, welche ausführlich die vielfältigen Anwendungsmöglichkeiten des DGV erklärt.


BlackMatrix - Sa 24.09.11 19:24

user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
Hallo BlackMatrix,

du kannst beim DGV die Eigenschaft AutoGenerateColumns auf 'false' setzen und dann die einzelnen Spalten bei "Columns" definieren (und mit der Eigenschaft DataPropertyName die zu bindende Eigenschaft angeben).

Such mal im Internet nach "DataGridView FAQ" - es gibt eine DOC Datei, welche ausführlich die vielfältigen Anwendungsmöglichkeiten des DGV erklärt.


Okay, ja das gefällt mir. Problem nur, dass man keine Datenbindung zu den Subklassen aufbauen kann.


Th69 - So 25.09.11 11:00

Hallo BlackMatrix,

wenn du des englischen mächtig bist, könntest du dich mal durch folgenden MSDN-Beitrag durchwühlen: DataGridView Object Data Sources [http://social.msdn.microsoft.com/forums/en-US/winformsdatacontrols/thread/a6f33219-8603-4816-9d0d-ee4e5814de68]
Stichworte: ToString(), ITypedList, Reflection, Nested, derive new column

Edit: Und bei CodeProject gibt es einen Artikel, welcher dies mittels ITypedList und Reflection umsetzt: http://www.codeproject.com/KB/cs/ObjectBindingSource.aspx