I'm using vb.NET in Visual Studio 2010. I found an example of how to add a ComboBox to a DataGridView cell, and I added it to my code. When I run the code, and I add a new row, the ComboBox is visible, but it has no value displayed in it and it won't drop down.
Have I missed something from the code? Does the DataGridView need to have certain properties set?
dgvFiles.Rows.Add({"Cell1","Cell2"})
Dim gridComboBox As New DataGridViewComboBoxCell
gridComboBox.Items.Add("A") 'Populate the Combobox
gridComboBox.Items.Add("B") 'Populate the Combobox
gridComboBox.Items.Add("C") 'Populate the Combobox
dgvFiles(2, dgvFiles.Rows.Count - 1) = gridComboBox
Edit:
I had set four columns at design time, that wasn't the issue. The issue turned out to be that I had set the DataGridView to 'EditProgrammatically'. I had changed it to that initially to stop users from editing the text cells, but apparently, it prevented the ComboBoxes from dropping.
I appreciate all the answers given. My apologies that I forgot to mention that I had set four columns in design time, and that this issue was caused by me not realising the EditProgrammatically setting had this effect.
Your code is almost fine. Everything drops down. You could have the default value displayed on your list.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
dgvfiles.Columns.Add("Column1", "Column 1")
dgvfiles.Columns.Add("Column2", "Column 2")
dgvfiles.Columns.Add("Column3", "Column 3")
dgvfiles.Columns.Add("Column4", "Column 4")
dgvfiles.Rows.Add({"Cell1", "Cell2"})
Dim gridComboBox As New DataGridViewComboBoxCell
gridComboBox.Items.Add("A") 'Populate the Combobox
gridComboBox.Items.Add("B") 'Populate the Combobox
gridComboBox.Items.Add("C") 'Populate the Combobox
gridComboBox.Value = gridComboBox.Items(0)
dgvfiles(2, dgvfiles.Rows.Count - 2) = gridComboBox
End Sub
Private Sub dgvfiles_CellBeginEdit(sender As Object, e As DataGridViewCellCancelEventArgs) Handles dgvfiles.CellBeginEdit
If e.ColumnIndex = 2 Then
'Do something
Else
e.Cancel = True
End If
End Sub
Related
I have two datagridviews. One is dtgridPopulate and is populated with data from the database.
dtgridPopulate columns are (checkbox, code, name)
checkbox
code
name
checkbox icon
c1
customer_one
Then the second datagridview is dtgridGenerate which has generated values from dtgridPopulate.
I use the code dtgridPopulate.Rows.Add(code, name) to add manually the value from dtgridPopulate to dtgridGenerate.
dtgridGenerate columns are (code, name)
code
name
c1
customer_one
When I check the checkbox in the dtgridPopulate it will transfer the values (code, name) to the dtgridGenerate. But the problem is when I uncheck the checkbox in the dtgridPopulate, It should also REMOVE the values in the dtgridGenerate.
Private Sub dtgridPopulateSelectAll_CurrentCellDirtyStateChanged(ByVal sender As Object, ByVal e As EventArgs) Handles dtgridPopulate.CurrentCellDirtyStateChanged
RemoveHandler dtgridPopulate.CurrentCellDirtyStateChanged, AddressOf dtgridPopulateSelectAll_CurrentCellDirtyStateChanged
If TypeOf dtgridPopulate.CurrentCell Is DataGridViewCheckBoxCell Then
dtgridPopulate.EndEdit()
Dim Checked As Boolean = CType(dtgridPopulate.CurrentCell.Value, Boolean)
If Checked Then
code = dtgridPopulate.CurrentRow.Cells(1).Value.ToString
name = dtgridPopulate.CurrentRow.Cells(2).Value.ToString
dtgridGenerate.Rows.Add(code, name)
Else
For Each drow As DataGridViewRow In dtgridPopulate.SelectedRows 'This is for uncheck but it doens't work
dtgridGenerate.Rows.Remove(row)
Next
End If
End If
AddHandler dtgridPopulate.CurrentCellDirtyStateChanged, AddressOf dtgridPopulateSelectAll_CurrentCellDirtyStateChanged
End Sub
I refer to this reference
Error when I uncheck the checkbox: row provided does not belong to this datagridview control. parameter name: datagridviewrow
I am not sure “why” you have unsubscribed and then re-subscribed to the event. Typically, this is only needed if the code in the event “changes” something in the grid that would cause the event to re-fire and this is not happening in your current code. Nor is ending the grids edit necessary.
Also, your use of the grids CurrentCellDirtyStateChanged event has one drawback in relation to what you want to do… it will NOT re-fire if the user checks and unchecks the same cell over and over. In other words, if the user clicks a check box cell and the check box becomes checked and the event fires… then … if the user “unchecks” the same cell before clicking on any other cell, then the event will NOT refire.
Also, it looks like the event is using a different grid from the signature of the event… dtgridPopulateSelectAll_CurrentCellDirtyStateChanged … ? … “SelectAll” and the grid in the event is called… dtgridPopulate … this is confusing.
Given this, I suggest two things to help. 1) create and use an “Empty” DataTable for the second grid. This way we could simply add and remove items from that table. 2) use the grids CellContnetClick event for this. It will re-fire if the user clicks on the same cell over and over in addition to firing ONLY when the check box is changed.
So, I propose these small changes. First add a global variable named generateDT as a DataTable used as a DataSource to the second grid. Initially this table would be empty. Second use the grids CellContentClick event to make these additions and removal of the rows.
Dim generateDT As DataTable
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim dt As DataTable = New DataTable()
dt.Columns.Add("checkbox", GetType(Boolean))
dt.Columns.Add("code", GetType(String))
dt.Columns.Add("Name", GetType(String))
dt.Rows.Add(False, "c1", "customer 1")
dt.Rows.Add(False, "c2", "customer 2")
dt.Rows.Add(False, "c3", "customer 3")
dtgridPopulate.DataSource = dt
generateDT = New DataTable()
generateDT.Columns.Add("code", GetType(String))
generateDT.Columns.Add("Name", GetType(String))
dtgridGenerate.DataSource = generateDT
End Sub
Then in the cell content click event, if the clicked cell is a check box cell, then… grab the checked state and both the code and name of the clicked-on row. Then if the check box cell is checked, then simply add the code and name to the second grids global DataTable variable generateDT. If the check box is unchecked, then we will loop through each row in the second grid and if we find a match then simply remove that row from the second grids global DataTable… something like…
Private Sub dtgridPopulate_CellContentClick(sender As Object, e As DataGridViewCellEventArgs) Handles dtgridPopulate.CellContentClick
If e.ColumnIndex = 0 Then
Dim Checked = CType(dtgridPopulate.Rows(e.RowIndex).Cells(e.ColumnIndex).EditedFormattedValue, Boolean)
Dim code = dtgridPopulate.CurrentRow.Cells(1).Value.ToString
Dim Name = dtgridPopulate.CurrentRow.Cells(2).Value.ToString
If Checked Then
generateDT.Rows.Add(code, Name)
Else
Dim rowToRemove As DataRowView
For Each row As DataGridViewRow In dtgridGenerate.Rows
If row.Cells(0).Value.ToString() = code Then
rowToRemove = CType(row.DataBoundItem, DataRowView)
generateDT.Rows.Remove(rowToRemove.Row)
Exit For
End If
Next
End If
End If
End Sub
I'm having an issue with my ComboBoxes whereby if I type into it to get a value & then tab out the Text changes to the first item in the list with the first letter typed.
I have:
AutoCompleteMode set to SuggestAppend
AutoCompleteSource set to ListItems
DropDownStyle set to DropDownList
I add the items for the ComboBox in the Load event of the Form the ComboBox is on.
e.g. the below is code from a Load event where I populate a ComboBox that I have set up as below.
`Me.ComboBox1.Text = ""
Me.ComboBox1.Items.Add("a")
Me.ComboBox1.Items.Add("aaa")
Me.ComboBox1.Items.Add("combo")
Me.ComboBox1.Items.Add("combobox")
Me.ComboBox1.Items.Add("combobox test")
Me.ComboBox1.Items.Add("common")
Me.ComboBox1.Items.Add("common dialog")`
After running the code, if I select the ComboBox1 & type in common - common is selected in ComboBox1 but if I leave ComboBox1 the Text reverts to combo.
It gets a bit stranger as if I user the below code in the ComboBox1_Leave event procedure it throws common:
MsgBox(ComboBox1.Text)
I've also tried assigning the value of Text to a string in the ComboBox1_KeyUp event procedure & then assign that to ComboBox1.Text in the ComboBox1_Leave event procedure but that doesn't do anything.
If I put a the above MsgBox code before assigning the strings value to ComboBox1.Text then the Text value does revert to Common but this is isn't a practical solution.
I've also noticed that if I hit Enter before hitting tab it retains the correct value but again I'm don't think this is a particularly practical solution.
Does anyone have any idea what's going on here & how I can fix it?
It is absolutely necessary to have the DropDownStyle set to DropDownList?
Because if you set DropDownStyle to DropDown the selected value will be retained when you press tab or lose the focus.
If it's absolutely necessary to have it that way, you could try this.
Public Class Form2
Dim selectedTextForCombo As String = ""
Private Sub Form2_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Me.ComboBox1.Text = ""
Me.ComboBox1.Items.Add("a")
Me.ComboBox1.Items.Add("aaa")
Me.ComboBox1.Items.Add("combo")
Me.ComboBox1.Items.Add("combobox")
Me.ComboBox1.Items.Add("combobox test")
Me.ComboBox1.Items.Add("common")
Me.ComboBox1.Items.Add("common dialog")
End Sub
Private Sub ComboBox1_LostFocus(sender As Object, e As System.EventArgs) Handles ComboBox1.LostFocus
ComboBox1.SelectedItem = selectedTextForCombo
'This is just for a visualization of your issue
'Label1.Text = selectedTextForCombo
End Sub
Private Sub ComboBox1_SelectedIndexChanged(sender As System.Object, e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
selectedTextForCombo = ComboBox1.Text
'This is just for a visualization of your issue
'Label1.Text = selectedTextForCombo
End Sub
End Class
Warning:
This example works with the tab action.
If the users writes something that doesn't exist like "commun" the
selected value will end up being the visually selected value, in this
case: "common"
The title is somewhat misleading. I can reduce the .Items Count to zero by the usual methods, but the dropdown list area keeps its former dimensions.
When adding items to ComboBox manually, I can do ComboBox.Items.Clear. The ComboBox.Items count is reduced to zero.
When databinding ComboBox, I can do ComboBox.DataSource = Nothing. Or, set the BindingSource = Nothing, if using one. The ComboBox.Items Count is reduced to zero.
However, the combobox dropdown area retains the rows it had been populated with, except that they are "empty". In other words, it's a white box which is the same height as the list it had contained.
Seems to me that if I clear a ComboBox, it ought to appear identical to one which has never been bound or filled.
The DropDownStyle = DropDownList
ComboBox before filling/binding:
ComboBox after filling/binding:
ComboBox after clearing/setting datasource/bindingsource = Nothing:
Does anyone know a way to prevent this? If I unbind or otherwise clear the ComboBox, I'd like the dropdown to then consist of one empty row, as in the first image.
Thanks.
The following should fix that:
ComboBox.DropDownStyle = ComboBoxStyle.DropDown
ComboBox.DropDownStyle = ComboBoxStyle.DropDownList
For some reason changing the 'DropDownStyle' property of the combobox to something that is not DropDownList, and then changing it back resizes the DropDownList to the minimum possible height for its entries, or at least in Visual Studio 2015 with .NET Framework 4.5. Hope this helps.
Edit: It's strange that if the ComboBox's style is ComboBoxStyle.DropDown that ComboBox.DropDownHeight = 106 will change the height, but if the style is ComboBoxStyle.DropDownList it won't. Yet another mystery of .NET!
To force reset a height of dropdown element you need to change ComboBox.DropDownStyle to some other and back to the original
Me.ComboBox1.DataSource = Nothing
Me.ComboBox1.DropDownStyle = ComboBoxStyle.DropDown
Me.ComboBox1.DropDownStyle = ComboBoxStyle.DropDownList
You must set the DropDownHeight property of the ComboBox control after clearing the DataSource. Here is an example that sets it back to a default that you can adapt for your own purposes.
Private m_intDefaultDropDownHeight As Integer = 1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim lstItems As New List(Of String)
lstItems.Add("A")
lstItems.Add("B")
lstItems.Add("C")
m_intDefaultDropDownHeight = ComboBox1.DropDownHeight
ComboBox1.DataSource = lstItems
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
ComboBox1.DataSource = Nothing
ComboBox1.DropDownHeight = m_intDefaultDropDownHeight
End Sub
how i can change the item of combo box that is a column of data grid view according to the combobox that is present in the form
Dim productGrid as DataGridView
Dim objProductGroup As New DataGridViewComboBoxColumn
With productGroup
.HeaderText = "ProductGroup"
.Name = "ProductGroup"
.ReadOnly = True
.Items.Add("Server")
.Items.Add("Standalone")
End With
.Columns.Add(objProductGroup)
I have to select the objProductGroup combo box as per combo box that is on the form
dim box1 as ComboBox
box1..Items.Add("Server")
box1.Items.Add("Standalone")
When i will select the box1 item Server then objProductGroup comboBox should automatically updated.
The following code will change your DataGridView's CurrentRow Column "ProductGroup" to the value you selected in box1. I am not sure if you were trying to set ALL of the rows to the value in the combobox or just the current row.
In any case, you may want to test if the CurrentRow actually has any cells. For example:
If Not productGrid.CurrentRow Is Nothing Then [Execute the value changed]
For the sake of making it work after I selected a row, this is the code I used:
Private Sub box1_SelectedIndexChanged(sender As System.Object, e As System.EventArgs) Handles box1.SelectedIndexChanged
productGrid.CurrentRow.Cells("ProductGroup").Value = box1.SelectedItem
End Sub
Good day everyone.
I need your help in this project I am into (a Visual Basic program with no database.) It just contains a Datagridview, a Textbox, and three buttons (an "Add" Button, a "Edit" and an "Update" Button).
1 . Is there any way (like using "for loop") to automatically assign DataGridView1.Item("item location") to the one edited and be updated?
2 . Or is it possible to just click an item in the Datagridview then it will be edited at that without passing it to a Textbox, and to be updated at that.
The DataGridViewCellEventArgs variable (e in the method stub the designer will generate for you) of the double click event of the cell has RowIndex and ColumnIndex properties which refer to the position of the cell you clicked.
Save those (in a class variable possibly or a local one if that's all you need) and then refer to them when you update the cell in your DataGridView, possibly like this MyDataGridView.Item(e.ColumnIndex, e.RowIndex) or MyDataGridView.Rows(e.RowIndex).Cells(e.ColumnIndex) where e is the variable from the double click event handler.
For you cell double click event you could have something like this:
Private Sub DataGridView1_CellDoubleClick(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellDoubleClick
Using myEditor As New frmCellEditor(Me.DataGridView1.Item(e.ColumnIndex, e.RowIndex).Value)
If myEditor.ShowDialog() = DialogResult.OK Then
Me.DataGridView1.Item(e.ColumnIndex, e.RowIndex).Value = myEditor.NewCellValue
End If
End Using
End Sub
This will call a new instance of your editor and get a value from you. For the purpose of this demo I have made a form like this:
Public Class frmCellEditor
Public NewCellValue As Integer
Public Sub New(ByVal CurrentCellValue As Object)
InitializeComponent()
Me.TextBox1.Text = CStr(CurrentCellValue)
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Me.NewCellValue = CInt(Me.TextBox1.Text)
Me.DialogResult = DialogResult.OK
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Call Me.Close()
End Sub
End Class
Which just has two buttons (Button1 = OK, Button2 = Cancel). When you click OK, it just returns the value 1 which then gets set as the value of the cell.
This is a VERY simplistic example, but it should provide you the basics of what you are trying to do.
UPDATE:
I updated the code for the editor interface so it will include handling for passing the value back and forth from the form with your datagridview.
In your project, make a new form called frmCellEditor. This forms has to have two buttons and a textbox (Make sure that the programmatic names match!). Replace the code with the code listed above. You will have to add Imports System.Windows.Forms above the class as well.
Amend the event handler for the cell double click event of your datagrid to pass the cell value when frmCellEditor is constructed (the line going ... New frmCellEditor(...).
How many columns does your DataGridView has?
Based on how you populate your DataGridView, I'll assume only 1.
Declare this on top of your form
Dim i as Integer
On your btnUpdate_Click Event (Just combine your Edit and Update button into One)
SELECT CASE btnUpdate.Text
Case "Update"
With DataGridView1
'Check if there is a selected row
If .SelectedRows.Count = 0 Then
Msgbox "No Row Selected for Update"
Exit Sub
End If
i = .CurrentRow.Index 'Remember the Row Position
Textbox1.Text = .item(0 ,i).value 'Pass the Value to the textbox
.Enabled = False 'Disable DataGridView to prevent users from clicking other row while updating.
btnUpdate.Text = "Save"
End With
Case Else 'Save
DatagridView1.Item(0,i).Value = Textbox1.Text
btnUpdate.Text = "Update"
END SELECT
Thanks for those who contributed to finding answers for this thread. I have not used your solutions for now (maybe some other time). After some research, I've found an answer for problem 2 (more user friendly at that):
2 . Or is it possible to just click an item in the Datagridview then
it will be edited at that without passing it to a Textbox, and to be
updated at that.
Here's what i did:
in Private Sub Form1_Load, just add:
yourDataGridView.EditMode = DataGridViewEditMode.EditOnEnter
in Private Sub yourDataGridView_(whatever event here: DoubleCellClick, CellContentClick, etc.) add:
DataGridView1(e.ColumnIndex, e.RowIndex).[ReadOnly] = False
DataGridView1.BeginEdit(False)