expertenaustausch > microsoft.* > microsoft.german.entwickler.dotnet.vb

Hartmut Callies (31.03.2008, 21:31)
Hallo,
mit dem folgenden Code füge ich einem DataGridView eine Spalte
mit einer ComboBox hinzu mit den Einträgen Hallo1 und Hallo2.

Dim cbo As New DataGridViewComboBoxColumn
cbo.Items.Add("Hallo1")
cbo.Items.Add("Hallo2")
cbo.HeaderText = "Test"
cbo.DisplayIndex = 1
DataGridView1.Columns.Add(cbo)

Wenn ich aber nicht mit Code sondern bereits beim Entwurf über
die DataGridView-Eigenschaft Columns die Spalte Test hinzufüge
mit dem Typ ComboBox, dann schaffe ich es nicht (ohne DataTable)
die beiden Einträge Hallo1 und Hallo2 einzufügen.
Weiß jemand wie das funktioniert?

Hartmut Callies
Peter Götz (01.04.2008, 10:22)
Hallo Hartmut,

[..]
> dann schaffe ich es nicht (ohne DataTable)
> die beiden Einträge Hallo1 und Hallo2 einzufügen.
> Weiß jemand wie das funktioniert?


Ich verstehe Deine Frage resp. Dein Problem nicht
so ganz.

Wenn Du dem DGV zur Entwurfszeit eine ComboBoxSpalte
gegeben hast (z.B. Spalte 2) dann kannst Du die zugehörige
ComboBox so mit Werten füllen:

Dim DGVCol as DataGridViewComboBoxColumn = _
DirectCast(DGV.Columns(2), DataGridViewComboboxColumn)

With DGVCol
.Items.Add("1. Zeile")
.Items.Add("2. Zeile")
.Items.Add("3. Zeile")
.Items.Add ...
End With

Zur Entwurfszeit kannst Du die Items so hinzufügen:

Rechter Mausklick auf das Grid
-> Spalten bearbeiten
-> ComboBox-Spalte unter "Ausgewählte Spalten:" markieren
-> unter "Daten" im rechten Feld "Eigenschaften für nicht
gebundene Spalten" die Eigenschaft "Items" wählen und
dann
-> in der geöffneten Liste für die "Auflistung" die einzelnen
Zeilen für die ComboBox eintragen.

Gruß aus St.Georgen
Peter Götz
(mit VB-Tipps u. Beispielprogrammen)
Hartmut Callies (01.04.2008, 15:27)
Hallo Peter,
mir hat die folgende Befehlszeile gefehlt:

> Dim DGVCol as DataGridViewComboBoxColumn = _
> DirectCast(DGV.Columns(2), DataGridViewComboboxColumn)


Ich wußte nicht, wie ich die "manuell" eingerichtete ComboBox ansprechen
kann.
Jetzt funktioniert es bestens.
Danke.

Hartmut Callies
Peter Götz (01.04.2008, 15:40)
Hallo Harmut,

> mir hat die folgende Befehlszeile gefehlt:
> > Dim DGVCol as DataGridViewComboBoxColumn = _
> > DirectCast(DGV.Columns(2), DataGridViewComboboxColumn)


Ja, die Zusammenhänge zwischen dem gehosteten Control
und den übrigen untergeordneten Objekten sind beim
DataGridView nicht immer auf den ersten Blick zu
sehen.

Aber warum möchtest Du die ComboBox nicht einfach an
eine DataTable resp. DataView binden?
Ein entspr. Beispiel findest Du unter

-> Visual Basci -> VB.net
-> DataGridViewComboBoxColumn

Gruß aus St.Georgen
Peter Götz
(mit VB-Tipps u. Beispielprogrammen)
Hartmut Callies (01.04.2008, 23:00)
Hallo Peter,
ohne DataTable/DataView deshalb, da ich ohne eine Datenbank
Einstellungen in jeder Spalte vornehmen will und diese miteinander
kombiniere, d.h. eine Zeile mit verschiedenen Einstellungen ergibt
mit der letzten Spalte die gewünschte Endeinstellung.
Nun bin ich aber inzwischen doch der Meinung, diese Einstellvarianten
einfach in einer Tabelle(n) abzulegen. Bin gerade dabei.

Nun habe ich aber wieder ein Problem mit der ComboBox im DataGridView.
Wie erhalte ich ein Event für diese (manuell) erzeugte ComboBox?
Ich will mit der Änderung der Einstellung in der ComboBox von Spalte 0
eine andere Anzeige in der TextBox von Spalte 1 erreichen.
Gesucht habe ich viel, jedoch nichts zu den Ereignissen der ComboBox
gefunden. Hast Du auch einen kurzen Lösungsansatz?

Hartmut Callies
Peter Götz (02.04.2008, 11:04)
Hallo Hartmut,

> ohne DataTable/DataView deshalb, da ich ohne
> eine Datenbank Einstellungen in jeder Spalte
> vornehmen will und diese miteinander kombiniere,


Eine DataTable kann, aber muss nicht mit Daten aus
einer Datenbank befüllt werden. DataTables sind
völlig unabhängig von Datenbanken und können wie
Colliction, List(of..) usw. Speicher für Daten genutzt
werden. Datenursprung kann der Programmcode
selbst, eine Datei, ein Datenstrom aus einer ext.
HW-Schnittstelle und natürlich auch eine Datenbank
sein.

> d.h. eine Zeile mit verschiedenen Einstellungen ergibt
> mit der letzten Spalte die gewünschte Endeinstellung.
> Nun bin ich aber inzwischen doch der Meinung, diese
> Einstellvarianten einfach in einer Tabelle(n) abzulegen.
> Bin gerade dabei.


Ich verstehe nicht so ganz um welche Art von "Einstellungen"
es geht. Bei "Einstellungen" würde ich als Speicherort erst
mal an > My.Settings < denken.

> Nun habe ich aber wieder ein Problem mit der ComboBox
> im DataGridView.
> Wie erhalte ich ein Event für diese (manuell) erzeugte
> ComboBox?


Im DataGridView.EditingControlShowing-Ereignis bekommt
man einen Verweis auf die ComboBox.

> Ich will mit der Änderung der Einstellung in der ComboBox
> von Spalte 0 eine andere Anzeige in der TextBox von
> Spalte 1 erreichen.
> Gesucht habe ich viel, jedoch nichts zu den Ereignissen
> der ComboBox gefunden.


Ja, auch das ist nicht so ganz leicht zu finden.

> Hast Du auch einen kurzen Lösungsansatz?


Hier mal ein Beispiel.

' /// Code in einer leeren Form1
Public Class Form1
' DataTable für Grid
Private WithEvents DGV As DataGridView
Private mDT As DataTable
Private mDV As DataView

' DataTable für ComboBox
Private mDTcbo As DataTable
Private mDVcbo As DataView

' Objektvariable für ComboBox im Grid
Private WithEvents cboGrid As ComboBox

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

DGV = New DataGridView
DGV.Dock = DockStyle.Fill
Me.Controls.Add(DGV)

CreateData()

InitDGV()
DGV.AutoResizeColumns()

End Sub

Private Sub InitDGV()
Dim TBCol As DataGridViewTextBoxColumn
Dim CBCol As DataGridViewComboBoxColumn

TBCol = New DataGridViewTextBoxColumn
With TBCol
.Name = "ID"
.HeaderText = .Name
.DataPropertyName = .Name
.ValueType = GetType(Integer)
End With
DGV.Columns.Add(TBCol)

TBCol = New DataGridViewTextBoxColumn
With TBCol
.Name = "Mon"
.HeaderText = .Name
.DataPropertyName = .Name
.ValueType = GetType(String)
End With
DGV.Columns.Add(TBCol)

CBCol = New DataGridViewComboBoxColumn
With CBCol
.Name = "Monat"
.HeaderText = .Name
.DataPropertyName = .Name
.ValueType = GetType(String)
.DataSource = mDVcbo
.DisplayMember = .Name
End With
DGV.Columns.Add(CBCol)

DGV.DataSource = mDV
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("Mon", GetType(String))
.Columns.Add("Monat", GetType(String))

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

mDV = New DataView(mDT)

mDTcbo = New DataTable
With mDTcbo
.Columns.Add("ID", GetType(Integer))
.Columns.Add("Monat", GetType(String))

For i = 1 To 12
DR = .NewRow
DR.Item(0) = i
DR.Item(1) = MonthName(i)
.Rows.Add(DR)
Next
.AcceptChanges()
End With

mDVcbo = New DataView(mDTcbo)
End Sub

Private Sub DGV_DataError _
(ByVal sender As Object, _
ByVal e As DataGridViewDataErrorEventArgs) _
Handles DGV.DataError

Dim Exc As Exception = e.Exception
MsgBox(Exc.Message, MsgBoxStyle.Exclamation)
End Sub

Private Sub DGV_EditingControlShowing _
(ByVal sender As Object, _
ByVal e As DataGridViewEditingControlShowingEventArgs _
) Handles DGV.EditingControlShowing

If DGV.CurrentCellAddress.X = 2 Then
' *** Hier Verweis auf die ComboBox im Grid holen*****
cboGrid = DirectCast(e.Control, ComboBox)
' ************************************************** ************
End If
End Sub

Private Sub cboGrid_SelectedIndexChanged _
(ByVal sender As Object, _
ByVal e As System.EventArgs _
) Handles cboGrid.SelectedIndexChanged

If cboGrid.SelectedIndex > -1 Then
Dim DRVcbo As DataRowView
Dim DRV As DataRowView

DRVcbo = _
DirectCast(cboGrid.SelectedItem, DataRowView)

DRV = mDV.Item(DGV.CurrentCellAddress.Y)

If Not (DRVcbo.Item(1).Equals(DRV.Item(2))) Then
DRV.Item(1) = _
MonthName(CType(DRVcbo.Item(0), Integer), True)

DGV.InvalidateRow(DGV.CurrentCellAddress.Y)
End If
End If
End Sub
End Class
' \\\ E N T E

Programm starten und Werte in den ComboBoxen ändern.
Mit jeder Änderung in der ComboBox wird der Wert in
Spalte 1 (Mon) geändert.

Gruß aus St.Georgen
Peter Götz
(mit VB-Tipps u. Beispielprogrammen)
Hartmut Callies (03.04.2008, 19:26)
Hallo Peter,
vielen Dank für Dein tolles Beispiel. Es hat mir sehr geholfen.

> Ich verstehe nicht so ganz um welche Art von "Einstellungen"
> es geht. Bei "Einstellungen" würde ich als Speicherort erst
> mal an > My.Settings < denken.

Es müssen verschiedene Parameter für einen Artikel
gewählt werden , bevor die endgültige Artikelart festgelegt ist.
Natürlich kann man das auch mit einzelnen ComboBoxen und
TextBoxen bewerkstelligen (und zusätzlich TablelayoutPanel),
aber das DataGridView ist platzsparender und passt sich beim
Resize der Form sehr gut an.

Inzwischen verwende ich eine dantenbankunabhängige Tabelle
als Datenquelle für das DataGridView, wie von Dir empfohlen.

Trotzdem habe ich nochmals eine Frage, da ich anfangs diese
Lösung realisieren wollte.
An die typischen ComboBox-Eigenschaften wie z.B. SelectedIndex
von einer ComboBox im DataGridView gelange ich nur durch
die Typ-Konvertierung mit DirectCast, wie in Deinem Beispiel:
> cboGrid = DirectCast(e.Control, ComboBox)


Ausgangspunkt dafür ist aber, dass ich die ComboBox im
DataGridView z.B. per Klick auswählt habe.
Wie kann ich aber eine ComboBox im DataGridView zu einer
"Standard"-ComboBox konvertieren, wenn ich diese nicht per Klick
ausgewählt habe, um z.B. an die Eigenschaft SelectedIndex zu gelangen?

Folgender Hintergrund dazu.
Bevor ich das DataGridView verwendet habe, hatte ich eine ComboBox
Artikel (als DropDownList) und eine ComboBox ArtikelStatus (als Simple).
Beide hatte ich mit den Ergebnissen aus der Abfrage von der Datenbank
versehen. Mit der folgenden Codezeile habe ich dann immer den passenden
Artikelstatus dem Artikel zugeordnet.
cboArtikelStatus.SelectedIndex = cboArtikel.SelectedIndex
Genau das wollte ich im DataGridView ebenfalls nachbilden. Bin jetzt aber
auf eine lose DataTable umgestiegen.
Trotzdem würde es mich interessieren, wie ich die SelectedIndex-Eigenschaft
von einer nicht ausgewählten (Klick) ComboBox (DisplayStyle = Nothing)
erhalte, um auch hier den Index von der ComboBox in Spalte 0 gleich dem
Index von der ComboBox von Spalte 1 zu setzen.
Hast Du auch dafür eine Lösung?

Hartmut Callies
Peter Götz (05.04.2008, 11:35)
Hallo Hartmut,

> An die typischen ComboBox-Eigenschaften wie z.B.
> SelectedIndex von einer ComboBox im DataGridView
> gelange ich nur durch die Typ-Konvertierung mit
> DirectCast, wie in Deinem Beispiel:
> cboGrid = DirectCast(e.Control, ComboBox)


Ja, zwangsläufig, weil DataGridView.EditingControl
ja nicht nur eine ComboBox, sondern z.B. ja auch
eine Textbox oder irgendein anderer ControlTyp
sein könnte.

> Ausgangspunkt dafür ist aber, dass ich die ComboBox
> im DataGridView z.B. per Klick auswählt habe.


Ja, zumindest einmal muss das .EditingControl sichtbar
geworden sein, um eine entspr. Zuordnung machen zu
können.

> Wie kann ich aber eine ComboBox im DataGridView
> zu einer "Standard"-ComboBox konvertieren, wenn ich
> diese nicht per Klick ausgewählt habe, um z.B. an die
> Eigenschaft SelectedIndex zu gelangen?


Mindestens einmal musst Du in _EditingControlShowing
einer Objektvariablen, die Du z.B. mit WithEvents
deklariert hast einen Verweis aus e.Control übergeben
und ab dann bekommst Du über diese Ojektvariable
alle Ereignisse der ComboBox mit und hast darüber
auch Zugriff auf alle Eigenschaften der ComboBox.

Das Problem dabei ist nur, dass ComboBox.SelectedItem
ständig wechselt, je nachdem welchen Datensatz Du
auswählst, bzw. abhängig davon, ob die ComboBox
sichtbar gemacht wird oder nicht.

.... schnipp...

> Trotzdem würde es mich interessieren, wie ich die
> SelectedIndex-Eigenschaft von einer nicht ausgewählten
> (Klick) ComboBox (DisplayStyle = Nothing) erhalte, um
> auch hier den Index von der ComboBox in Spalte 0
> gleich dem Index von der ComboBox von Spalte 1
> zu setzen.
> Hast Du auch dafür eine Lösung?


Das Problem dabei ist, dass sich ComboBox.SelectedItem
nicht unbedingt beim Wechsel zu einem neuen Datensatz
ändert, sondern erst dann, wenn die ComboBox wirklich
durch Anklicken der jeweiligen Grid-Zelle geöffnet wird.
Das nachfolgende Beispiel zeigt, in welchen Situationen
sich ComboBox.SelectedItem ändert.

Public Class Form1
Private WithEvents DGV As DataGridView
Private mDT As DataTable
Private mDV As DataView
Private mDTcbo As DataTable
Private mDVcbo As DataView
Private WithEvents mCM As CurrencyManager

Private WithEvents mCBox As ComboBox

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

CreateData()
InitDGV()
DGV.DataSource = mDV
DGV.AutoResizeColumns()
End Sub

Private Sub InitDGV()
Dim dgvTBCol As DataGridViewTextBoxColumn
Dim dgvCBCol As DataGridViewComboBoxColumn
Dim i As Integer

DGV = New DataGridView
With DGV
.Dock = DockStyle.Fill
.AutoGenerateColumns = False
For i = 0 To 1
dgvTBCol = New DataGridViewTextBoxColumn
With dgvTBCol
.Name = mDT.Columns(i).ColumnName
.HeaderText = .Name
.DataPropertyName = .Name
.ValueType = mDT.Columns(i).DataType
End With
.Columns.Add(dgvTBCol)
Next i

dgvCBCol = New DataGridViewComboBoxColumn
With dgvCBCol
.Name = mDT.Columns(2).ColumnName
.HeaderText = .Name
.DataPropertyName = .Name
.DataSource = mDVcbo
.DisplayMember = mDTcbo.Columns(1).ColumnName
'.ValueMember = mdtb
End With
.Columns.Add(dgvCBCol)

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

.ColumnHeadersDefaultCellStyle.Font = _
New Font("Arial", 8, FontStyle.Bold)

End With
Me.Controls.Add(DGV)
End Sub

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

mDTcbo = New DataTable
With mDTcbo
.Columns.Add("ID", GetType(Integer))
.Columns.Add("Monat", GetType(String))
For i = 1 To 12
DR = .NewRow
DR.Item(0) = i
DR.Item(1) = MonthName(i)
.Rows.Add(DR)
Next
.AcceptChanges()
End With
mDVcbo = New DataView(mDTcbo)

mDT = New DataTable
With mDT
.Columns.Add("ID", GetType(Integer))
.Columns.Add("Mon", GetType(String))
.Columns.Add("Monat", GetType(String))
For i = 1 To 12
DR = .NewRow
DR.Item(0) = i
DR.Item(1) = MonthName(i, True)
DR.Item(2) = MonthName(i, False)
.Rows.Add(DR)
Next
.AcceptChanges()
End With
mDV = New DataView(mDT)
mCM = DirectCast(Me.BindingContext(mDV), CurrencyManager)
End Sub

Private Sub DGV_EditingControlShowing _
(ByVal sender As Object, _
ByVal e As DataGridViewEditingControlShowingEventArgs _
) Handles DGV.EditingControlShowing

' Hier wird einmalig der Objektverweis auf die
' ComboBox geholt und bleibt dann bestehen.
If mCBox Is Nothing Then
If DGV.CurrentCellAddress.X = 2 Then
mCBox = DirectCast(e.Control, ComboBox)
End If
End If
End Sub

Private Sub mCM_PositionChanged _
(ByVal sender As Object, _
ByVal e As System.EventArgs _
) Handles mCM.PositionChanged

If mCBox IsNot Nothing Then
Console.WriteLine _
("mCM_PositionChanged mCBox.SelectedIndex: " _
& mCBox.SelectedIndex.ToString)
End If
End Sub

Private Sub mCBox_SelectedIndexChanged _
(ByVal sender As Object, _
ByVal e As System.EventArgs _
) Handles mCBox.SelectedIndexChanged

Console.WriteLine _
("mCBox_SelectedIndexChanged mCBox.SelectedIndex: " _
& mCBox.SelectedIndex.ToString)
End Sub
End Class

Nach dem Programmstart muss einmal die ComboBox
in irgendeiner Zelle geöffnet werden um für die Variable
mCBox einen Verweis auf das .EditingControl (ComboBox)
zu erhalten. Im Ausgabefenster siehst Du dann bei
Datensatzwechseln bzw. beim Öffnen der ComboBox in
verschiedenen Zellen, wie sich mCBox.SelectedIndex
ändert.
Beim Abfragen von mCBox.SelectedItem musst Du Dir
also immer erst mal überlegen, ob dies der Zustand ist
wie er in einer vorher aktiven Zelle war oder ob es der
Zustand in der gerade aktiven Zelle ist.

Das Problem ist halt einfach, dass es ja nur eine einzige
ComboBox für alle Zellen Deiner DataGridComboBoxColumn
gibt und deren SelectedIndex-Eigenschaft sich halt ständig,
je nach Benutzeraktion ändert.

Gruß aus St.Georgen
Peter Götz
(mit VB-Tipps u. Beispielprogrammen)
Hartmut Callies (07.04.2008, 10:15)
Hallo Peter,
danke für Deine Hinweise. Es wird deutlich, dass das DataGridView als
Datenquelle eine DataTable/DataView benötigt und jegliche Nutzung des
DataGridView mit "manuell" hinzugefügten Daten und der damit
verbundenen Auswertung der Ereignisse schwierig ist.

Hartmut Callies
Peter Götz (07.04.2008, 11:14)
Hallo Hartmut,

> danke für Deine Hinweise. Es wird deutlich, dass das
> DataGridView als Datenquelle eine DataTable/DataView
> benötigt


Es sind schon auch andere Datenquellen möglich,
die aber meist nicht ganz so bequem zu handhaben sind.

> und jegliche Nutzung des DataGridView mit "manuell"
> hinzugefügten Daten und der damit verbundenen
> Auswertung der Ereignisse schwierig ist.


Im Falle einer ComboBoxColumn ist es halt wichtig,
sich immer bewusst zu sein, dass ComboBox.SelectedItem
je nach Benutzeraktion im Grid eben ständig wechselt und
auch mal den Wert -1 annehmen kann.

Gruß aus St.Georgen
Peter Götz
(mit VB-Tipps u. Beispielprogrammen)
markus.breitenstein.ag (04.06.2016, 08:25)
Am Montag, 7. April 2008 11:14:24 UTC+2 schrieb Peter Götz:
> Hallo Hartmut,
> Es sind schon auch andere Datenquellen möglich,
> die aber meist nicht ganz so bequem zu handhaben sind.
> Im Falle einer ComboBoxColumn ist es halt wichtig,
> sich immer bewusst zu sein, dass ComboBox.SelectedItem
> je nach Benutzeraktion im Grid eben ständig wechselt und
> auch mal den Wert -1 annehmen kann.
> Gruß aus St.Georgen
> Peter Götz
> (mit VB-Tipps u. Beispielprogrammen)


Hallo Peter

Ich hätte auch ne Combobox Frage....

Ich habe in einer Forme eine Combobox, welche mit binding an eine Tabelle angehängt ist.
DisplayMember ist aktuell "text1"

Nun möchte ich auf Knopfdruck, dass das DisplayMember zu "text2" geändert wird.

Beide Felder sind in der DataSource immer vorhanden, Spalte 1 und Spalte 2

Hast du eine Idee, wie ich das in VB realisieren kann ?

Den Key Event konnte ich erstellen.

Gruss

Markus
Ähnliche Themen