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
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
www.gssg.de (mit VB-Tipps u. Beispielprogrammen)
>
> 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
> 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
www.gssg.de -> Visual Basci -> VB.net
-> DataGridViewComboBoxColumn
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
> 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.
> 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
> 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
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.
Hartmut Callies
> 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.