I have a setup in my code where there is a datagridview. For each row I have a combo box cell that I have a separate combo box cell since I want a different selection of items for each cell.
Problem : The cell only drops down when the arrow is double clicked. How can I change the cell formatting, or possibly a cell click event, so that the cell response to just one click?
Here's my cell creation code. Frankly, I didn't start any other code since I didn't know what event to touch or call. Is there a property I can edit?
Code:
'add items to combobox list
Dim comboCell As New DataGridViewComboBoxCell
comboCell.FlatStyle = FlatStyle.Flat
Dim resolutionList As New List(Of cmbStruct)
Dim currentResIndex As Integer = 0
'create list of resolutions
For j As Integer = 0 To resolutions.Length - 1
Dim resClass As New cmbStruct
resClass.Name = resolutions(j)
resClass.ID = resolutions(j)
resolutionList.Add(resClass)
comboCell.Items.Add(resolutions(j))
Next
'set combocell values
comboCell.DisplayMember = "Name"
comboCell.ValueMember = "ID"
'set the default value to the current resolution index
Try
comboCell.Value = resolutions(currentResIndex)
Catch ex As Exception
End Try
comboCell.ValueType = GetType(cmbStruct)
comboCell.DataSource = resolutionList
editCameraTable("Resolution", i) = comboCell
Next
Change the EditMode property:
DataGridView1.EditMode = DataGridViewEditMode.EditOnEnter
There seems to be a nearly identical question and a very good answer. It involves using the click_event. Here is the link:
How to manually drop down a DataGridViewComboBoxColumn?
In the link:
Private Sub cell_Click(ByVal sender As System.Object, ByVal e As DataGridViewCellEventArgs) Handles DataGridView1.CellClick
DataGridView1.BeginEdit(True)
If DataGridView1.Rows(e.RowIndex).Cells(ddl.Name).Selected = True Then
DirectCast(DataGridView1.EditingControl, DataGridViewComboBoxEditingControl).DroppedDown = True
End If
End Sub
Related
I've got part of my code that creates a tab in a tabcontrol, and then fills it with a datagridview which contains a couple columns that are DataGridViewComboBoxColumn.
It looks like this:
Private Sub NewTabPage()
Dim TabPageCount As Integer = RacerOrderTAB.TabPages.Count
RacerOrderTAB.TabPages.Add(TeamNames(TabPageCount)) 'teamnames() is an array of team names
Dim CurrentTabPage = RacerOrderTAB.TabPages(TabPageCount)
Dim GridToAdd As New DataGridView
GridToAdd.Size = CurrentTabPage.Size
GridToAdd.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill
GridToAdd.Location = New Point(CurrentTabPage.Location.X, CurrentTabPage.Location.Y)
GridToAdd.Columns.Add("ShiftCOL", "Shift Name")
GridToAdd.Name = "grid_" & CurrentTabPage.Text
For y As Integer = 1 To ShiftSetup.racerspershift 'add extra column for each racer in shift
Dim cmb As New DataGridViewComboBoxColumn
cmb.HeaderText = "Racer" & y
cmb.Name = "Racer_" & y
cmb.MaxDropDownItems = AmountOfRacers
cmb.DisplayStyle = DataGridViewComboBoxDisplayStyle.DropDownButton
GridToAdd.Columns.Add(cmb)
Next
RacerOrderTAB.TabPages(TabPageCount).Controls.Add(GridToAdd)
End Sub
But I've been having difficulty in adding an eventhandler for the comboboxes. What I want to happen is that when a combobox is clicked and opened, I populate it with the items I want.
I managed to vaguely get it working by adding:
AddHandler GridToAdd.EditingControlShowing, AddressOf <sub name>
but then have been unable to figure out which combobox was clicked, and how to populate it. It's also been requiring like four clicks before the drop list will appear. I'm only slightly very confused.
Thanks for any advice; these DataGridViewComboBoxColumns [deep breath] have been confusing me a lot!
It may be a little hacky but it should do what you are asking… hopefully. I created two List(Of String) variables. AllRacers contains all the racers… i.e. all the names we want to appear in a combo box such that there is no other combo box on that row that has an item selected. These names are what all combo boxes on all rows would initially contain in the selectable items list.
The other List(Of String) UsedRacers contains a list of all the “comboboxes” on the current row that have selected items. Each time a cell value is changed and it is one of the “combobox” column cells, then UsedRacers is cleared/updated to reflect the added/changed selected item on the current row.
When a “comboBox” cell value is changed, SetUsedRacersForRow is called…
Private Sub SetUsedRacersForRow(rowIndex As Int16)
UsedRacers.Clear()
Dim curValue = ""
For i = 1 To racersPerShift
If (Not (dgvRacers.Rows(rowIndex).Cells(i).Value Is Nothing)) Then
curValue = dgvRacers.Rows(rowIndex).Cells(i).Value.ToString()
If (Not (String.IsNullOrEmpty(curValue))) Then
UsedRacers.Add(curValue)
End If
End If
Next
End Sub
The code above loops through all the “combobox” cells in the given row and if a “combobox” cell has something selected, the selected value is added to the UsedRacers list.
Now that the selected items for all the “comboboxes” in that row are in the UsedRacers list, we can now loop through each “combobox” cell in that row and set the proper list of names. To help, a method is created that returns a DataGridViewComboBoxCell such that the names in the current UsedRacers list will NOT be in the DataGridViewComboBoxCell’s list of selectable names.
The only issue here would be with cells that currently have an item selected. Each “combobox” cell with an item selected will uniquely need to have its selected item in its list of items. To remedy this, a check is needed to see if the “combobox” cell contains a value. If the “combobox” cell DOES contain a selected value, then this value is also contained in the UsedRacers list. Since THIS cell is the cell that is in the UseRacers list… then we need to ADD this value to this cells items list. Otherwise, we would not be able to display the unique selection.
To keep the UsedRacers list consistent, we need to add this item directly to the individual “combobox” cell and not remove or alter the UsedRacers list as this will be used for the other “combobox” cells. In other words… whatever value is selected in a combo box, we need to make sure it is one of the items in the “combobox’s” list of selectable items. I hope that makes sense.
This can all be done in the DataGridViews CellChanged event.
Private Sub dgvRacers_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles dgvRacers.CellValueChanged
If (e.ColumnIndex >= 1 And e.ColumnIndex <= racersPerShift) Then
SetUsedRacersForRow(e.RowIndex)
For i = 1 To racersPerShift
Dim newCell As DataGridViewComboBoxCell = GetCurrentComboBoxCell()
If (Not (dgvRacers.Rows(e.RowIndex).Cells(i).Value Is Nothing)) Then
Dim curValue = dgvRacers.Rows(e.RowIndex).Cells(i).Value.ToString()
newCell.Items.Add(curValue)
newCell.Value = curValue
End If
dgvRacers.Rows(e.RowIndex).Cells(i) = newCell
Next
End If
End Sub
In the code above, a method GetCurrentComboBoxCell (below) returns a DataGridViewComboBoxCell such that the items in the combo boxes list of items does not contain any items that are in the UsedRacers list. Because of this, a check is needed (above) to see if the cell already contains a value. NOTE: the DataGridViewComboBoxCell returned will always contain a “blank” empty item. This is necessary to allow the user to “De-Select” any currently selected value and then make the “De-Selected” item available to the other combo box cells.
Public Function GetCurrentComboBoxCell() As DataGridViewComboBoxCell
Dim newComboCell = New DataGridViewComboBoxCell()
newComboCell.DisplayStyle = DataGridViewComboBoxDisplayStyle.DropDownButton
newComboCell.FlatStyle = FlatStyle.Flat
newComboCell.Items.Add("")
For Each curRacer In AllRacers
If (Not UsedRacers.Contains(curRacer)) Then
newComboCell.Items.Add(curRacer)
End If
Next
Return newComboCell
End Function
Finally, putting all this together…
Dim racersInShift = 3
Dim AllRacers As List(Of String) = New List(Of String) From {"John", "Bobby", "Trent", "Josh", "Chapman", "Henry", "George", "Marvin"}
'Dim racersPerShift As Int16 = AllRacers.Count '<-- should be MAX value
Dim racersPerShift As Int16 = 4
Dim UsedRacers = New List(Of String)
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
BuildGrid()
End Sub
Private Sub BuildGrid()
dgvRacers.Size = New Size(800, 200)
dgvRacers.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill
'dgvRacers.Location = New Point(50, 200)
dgvRacers.Columns.Add("ShiftCOL", "Shift Name")
dgvRacers.Name = "RacersDGV"
dgvRacers.EditMode = DataGridViewEditMode.EditOnEnter
dgvRacers.AllowUserToAddRows = False
AddRacerColumns()
AddRacerRows()
End Sub
Private Sub AddRacerColumns()
Dim newColumn As DataGridViewComboBoxColumn
For i As Integer = 1 To racersPerShift
newColumn = GetNewComboBoxColumn("Racer" & i, "Racer " & i)
dgvRacers.Columns.Add(newColumn)
Next
End Sub
Private Sub AddRacerRows()
For i As Integer = 1 To racersInShift
Dim row As New DataGridViewRow
dgvRacers.Rows.Add(row)
Next
End Sub
Private Sub dgvRacers_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs)
‘See code above
End Sub
Private Sub SetUsedRacersForRow(rowIndex As Int16)
‘See code above
End Sub
Public Function GetCurrentComboBoxCell() As DataGridViewComboBoxCell
‘See code above
End Function
‘Lastly a method to set a whole `DataGridviewComboBoxColumn` which is used to initialize all the combo box columns
Public Function GetNewComboBoxColumn(colName As String, colHeader As String) As DataGridViewComboBoxColumn
Dim newComboCol = New DataGridViewComboBoxColumn()
newComboCol.DisplayStyle = DataGridViewComboBoxDisplayStyle.DropDownButton
newComboCol.FlatStyle = FlatStyle.Flat
newComboCol.Items.Add("")
newComboCol.HeaderText = colHeader
newComboCol.Name = colName
For Each curRacer In AllRacers
newComboCol.Items.Add(curRacer)
Next
Return newComboCol
End Function
I hope this helps, I am guessing there is an easier way to do this.
I have a datagridview which I have furnished using the following code...
The trouble I have though is with the combobox column.
First off how can I have a preset value already selected in the combobox.
Secondly When I run my code I have to click the combobox's twice how can I change this to only having to click them once?
'CREATE DATAGRIVIEW 1 COLUMN LAYOUT...S
DataGridView1.ColumnCount = 8
DataGridView1.Columns(0).Name = "QTY"
DataGridView1.Columns(1).Name = "H"
DataGridView1.Columns(2).Name = "L"
DataGridView1.Columns(3).Name = "W"
DataGridView1.Columns(4).Name = "ANG 1"
DataGridView1.Columns(5).Name = "ANG 2"
DataGridView1.Columns(6).Name = "MAT"
DataGridView1.Columns(7).Name = "THK"
Dim ComboBoxColumn As New DataGridViewComboBoxColumn()
ComboBoxColumn.HeaderText = "TYPE"
ComboBoxColumn.Name = "ComboBoxColumn"
ComboBoxColumn.MaxDropDownItems = 5
ComboBoxColumn.Items.Add("NON")
ComboBoxColumn.Items.Add("SNG")
ComboBoxColumn.Items.Add("PER")
ComboBoxColumn.Items.Add("PAR")
ComboBoxColumn.Items.Add("AXS")
DataGridView1.Columns.Insert(8, ComboBoxColumn)
Dim checkBoxColumn As New DataGridViewCheckBoxColumn()
checkBoxColumn.HeaderText = "IDW"
checkBoxColumn.Name = "checkBoxColumn"
DataGridView1.Columns.Insert(9, checkBoxColumn)
'CREATE DATAGRIVIEW 1 COLUMN LAYOUT...E
If you mean a defaultvalue for the combobox:
Private Sub DataGridView1_CellFormatting(sender As Object, e As DataGridViewCellFormattingEventArgs) Handles DataGridView1.CellFormatting
If (e.ColumnIndex = 8) Then ' your combo column index
e.Value = "PER"
End If
End Sub
The selection in the combo box reflects the Value of the cell. If you want something to be selected then you have to set the Value of the cell accordingly.
Your second issue, which is unrelated and should therefore have been asked in an unrelated post, is as a result of the EditMode of the grid. Change that to the appropriate value for the behaviour you want.
I have a winform with a bound datagridview, 4 text boxes and a button. With the click of the button the "fillby" statement is called, the data is loaded on the datagridview and the content of the text boxes become the default value of some fields in the new rows of the datagridview.
I need to check all the text boxes to make sure they're not empty, if any of them is empty then a message should pop up saying which text box is empty and also keeps the datagridview from filling.
This is the code I have so far:
Private Sub btnCargarInformacion_Click(sender As System.Object, e As System.EventArgs) Handles btnCargar.Click
Dim emptyTextBoxes =
From txt In Me.Controls.OfType(Of TextBox)()
Where txt.Text.Length = 0
Select txt.Name
If emptyTextBoxes.Count >= -1 Then
MessageBox.Show(String.Format("Please fill following textboxes: {0}", String.Join(",", emptyTextBoxes)))
Else
Dim PartePersonalTableApt As New PersonalObraDataSetTableAdapters.PartePersonalTableAdapter
Dim PersonalObTableApt As New PersonalObraDataSetTableAdapters.PersonalObTableAdapter
PartePersonalTableApt.ClearBeforeFill = True
PartePersonalTableApt.FillByFecha(PersonalObraDataSet.PartePersonal, txtDate.Text, txtDepartamento.Text, txtTurno.Text)
PersonalObTableApt.ClearBeforeFill = True
PersonalObTableApt.Fillby(PersonalObraDataSet.PersonalOb)
End If
End Sub
I don't get any errors, the message appears even if all textboxes are filled, the message box does not specifying any text boxes as empty and stops the datagridview from filling.
I'm very new to codding so please explain in more detail your solution. Thanks
.Count >= -1
The count will be 0 if it's empty
If emptyTextBoxes.Count <> 0 Then
MessageBox.Show(String.Format("Please fill following textboxes: {0}", String.Join(",", emptyTextBoxes)))
Else
Dim PartePersonalTableApt As New PersonalObraDataSetTableAdapters.PartePersonalTableAdapter
Dim PersonalObTableApt As New PersonalObraDataSetTableAdapters.PersonalObTableAdapter
PartePersonalTableApt.ClearBeforeFill = True
PartePersonalTableApt.FillByFecha(PersonalObraDataSet.PartePersonal, txtDate.Text, txtDepartamento.Text, txtTurno.Text)
PersonalObTableApt.ClearBeforeFill = True
PersonalObTableApt.Fillby(PersonalObraDataSet.PersonalOb)
End If
You can try to loop at your container (ie form, panel, groupbox) for each textbox without content, then increment whenever there is a textbox that doesn't have content.
Example:
Dim checkr as integer = 0
Dim this As Control
For Each this In that.Controls
If TypeOf this Is TextBox Then
If this.text = "" then
Checkr += 1
End if
End If
Next
If checkr > 0 then
msgbox("Cannot proceed because a textbox has no content")
Else
'......(what you were gonna do)
End If
I am using a double click event on a listview that will add three columns to a datagridview. I'm not sure how to set the "Tag" property on the "selectedText" variable.
Private Sub lwArticles_DoubleClick(sender As Object, e As System.EventArgs) Handles lwArticles.DoubleClick
Dim selectedText = lwArticles.SelectedItems(0).SubItems.Item(0).Text 'Article No
Dim selectedDesc = lwArticles.SelectedItems(0).SubItems.Item(1).Text 'Description
Dim currRowNo As String = ""
Dim alreadyExists = False
For i As Integer = 0 To dgvDetail.Rows.Count - 1
currRowNo = dgvDetail.Rows(i).Cells(0).Value
If currRowNo = selectedText Then
alreadyExists = True
dgvDetail.Rows(i).Cells(2).Value += 1
Exit For
End If
Next
'If the entry doesn't exist, add it
If Not alreadyExists Then
dgvDetail.Rows.Add(New String() {selectedText, selectedDesc, 1})
End If
End Sub
After this I loop through the row's tags to see the article numbers. It will be near my dgvDetail.Rows.Add() that I should be setting the Tag property to equal the selectedText ... Any one know how to do this?
Edit:
The datagridview columns being populated are: "Article Number", "Description" and "Quantity". The quantity is set in the loop, basically if I've double clicked on the same thing twice, it will increment the third column (Cell(2)) by one.
The Add "function" for the DataGridView control returns the index of the row in the grid, so you can try using that to reference the row:
Dim rowIndex As Integer
rowIndex = dgvDetail.Rows.Add(New String() {selectedText, selectedDesc, 1})
dgvDetails.Rows(rowIndex).Tag = selectedText
This is a VB.NET, Winforms App. I have a datagridview on "Form1" that uses a databinding.datasource which is an Entity Framework table. I fill the datagridview with the below function on Form1:
Sub PM_UnitViewGrid()
Try
_form1.UnitsBindingSource.DataSource = db.units.Where(Function(f) f.propertyId = _form1.CurrentPropertyId).OrderBy(Function(F) F.unitNumber)
_form1.UnitDataGridView.DataSource = _form1.UnitsBindingSource.DataSource
Dim iCount As Integer = _form1.UnitDataGridView.RowCount
For x As Integer = 0 To iCount - 1
If Not IsNothing(_form1.UnitDataGridView.Rows(x).Cells(4).Value) Then
Dim tid As Integer = _form1.UnitDataGridView.Rows(x).Cells(4).Value
Dim _ten As tenant = db.tenants.Single(Function(f) f.Occupantid = tid)
_form1.UnitDataGridView.Rows(x).Cells(1).Value = _ten.first_name + ", " + _ten.last_name
Else
Dim btnColumn As DataGridViewButtonCell = CType(_form1.UnitDataGridView.Rows(x).Cells(1), DataGridViewButtonCell)
btnColumn.Style.BackColor = Color.Green
_form1.UnitDataGridView.Rows(x).Cells(1).Value = "VACANT"
End If
Next
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
Return
End Sub
This works great and also assigns the needed values to an unbound column. The problem is that the cells(1) is a button. Which when clicked takes the user to another form as a new dialog window. The function for which is below. However, once the changes are made in that form I need for the datagridview to refresh the data that its using from the database and show the correct data. As it stands right now the values are not updating on the datagridview unless the app is completely exited and restarted. Nothing I have found seems to work and Refresh and Update only redraw the control. I need the underlying datasource to refresh and then the datagridview once the child form is exited.. This has had me stumped for a good 36 hours now and I am lost as to why nothing I am trying is working. ANY and all help would be greatly appreciated.
The sub that loads the child form based on the cells(1) button clicked is as follows:
Private Sub UnitDataGridView_CellContentClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles UnitDataGridView.CellContentClick
UnitDataGridView.CommitEdit(DataGridViewDataErrorContexts.CurrentCellChange)
Dim y As DataGridViewCellEventArgs = e
Dim Tid As Integer = Nothing
If e.ColumnIndex = 1 Then
If Not e.RowIndex = -1 Then
If Not IsNothing(UnitDataGridView.Rows(e.RowIndex).Cells(4).Value) Then
currentTenent = UnitDataGridView.Rows(e.RowIndex).Cells(4).Value
TenentIdentification = currentTenent
If Not IsNothing(e) Then
If Not IsNothing(UnitDataGridView.Rows(e.RowIndex).Cells(4).Value) Then
Tid = UnitDataGridView.Rows(e.RowIndex).Cells(4).Value
Dim _ten As tenant = db.tenants.Single(Function(f) f.Occupantid = Tid) 'tenant is a table entity
TenantViewSubs.tenId = _ten.Occupantid
Dim t As New TenantView
t.tenId = tid
t.ShowDialog()
End If
End If
PropertyManagSubs.PM_UnitViewGrid() 'This is the function that is above that fills the datagridview
Else
Dim uTview As New UnassignedTenants
uTview.selectedProperty = selectedProperty 'selectedProperty is Integer
uTview.ShowDialog()
PropertyManagSubs.PM_UnitViewGrid() 'This is the function that is above that fills the datagridview
End If
End If
End If
End Sub
I tried each of the following code blocks after the t.ShowDialog() line with no change at all.
UnitDataGridView.Refresh()
.
UnitsBindingSource.Dispose()
UnitsBindingSource.DataSource = db.units.Where(Function(f) f.propertyId = selectedProperty).OrderBy(Function(f) f.unitNumber)
UnitDataGridView.DataSource = UnitsBindingSource.DataSource
.
UnitsBindingSource.DataSource = nothing
unitsBindingSource.DataSource = db.units.Where(Function(f) f.propertyId = selectedProperty).OrderBy(Function(f) f.unitNumber)
UnitDataGridView.DataSource = UnitsBindingSource.DataSource
I finally fixed this on my own.. It was in the way I passed my db context to the databinding..
I simply wrote the below sub:
Private Sub UpdateValues()
Dim context As New storageEntities 'storageEntities is an Entity
Dim query = context.units.Where(Function(F) F.propertyId = selectedProperty).OrderBy(Function(f) f.unitNumber)
UnitDataGridView.DataSource = query
End Sub
Then anytime a child form updated data I simply call
UpdateValues()
After the dialog box closes.
This may help someone else with the same problems so that is why I am posting it.