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
Related
I have a main form (FormXYZ) with a DataGridView which includes XYZ coordinates and names and descriptions of points. I am using a MenuStrip to call events using the selected points in the DGV.
When I call the event it will open a new form (Form4) with the relevant parameters for the function. I want to include a new DGV on this new form, which includes all of the points on the base DGV.
Below is the code I have so far which has been adapted from other posts I found on the subject. It seems to run without errors, but the new DGV does not show any data. This code describes how it will create the columns, based on the base DGV. I do not need this, as my DGVs will all contain the same columns, but I have left it in at this stage, until I can get some data transferred.
Thanks in advance for any help.
Public Class FormTranslate
Private Sub FormTranslate_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim sourceGrid As DataGridView = FormXYZ.DataGridView1
Dim targetGrid As DataGridView = Me.DGV1
'----------
'Copy all rows and cells.
Dim targetRows = New List(Of DataGridViewRow)
For Each sourceRow As DataGridViewRow In sourceGrid.Rows
If (Not sourceRow.IsNewRow) Then
Dim targetRow = CType(sourceRow.Clone(), DataGridViewRow)
For Each cell As DataGridViewCell In sourceRow.Cells
targetRow.Cells(cell.ColumnIndex).Value = cell.Value
Next
targetRows.Add(targetRow)
End If
Next
'Clear target columns and then clone all source columns.
targetGrid.Columns.Clear()
For Each column As DataGridViewColumn In sourceGrid.Columns
targetGrid.Columns.Add(CType(column.Clone(), DataGridViewColumn))
Next
'It's recommended to use the AddRange method (if available)
'when adding multiple items to a collection.
targetGrid.Rows.AddRange(targetRows.ToArray())
End Sub
End Class
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
I am trying to get a value fro a DataGridView 'DGV' when my winform loads ie, Forms2_load. DGV is bound and I am using the code below to Fill the DGV.
My question is, how do I get a value from 'DGV' without any user intervention, just when the form loads. I tried a for next loop on the form load event, but no message pops up. Can someone please help with this. Thanks
Me.CustomersTableAdapter.Fill(Me.StorageDataSet1.Customers)
Dim values As String
For Each RW As DataGridViewRow In DGV.SelectedRows
'Send the first cell value into messagebox'
values = RW.Cells(0).Value.ToString
Next
MessageBox.Show(values)
You might get better results if you use the bindingsource that the DGV is connected to. It will get a CurrentChanged event only after its loaded or when the position moves.
Private Sub BindingSource(sender As System.Object, e As System.EventArgs) Handles BindingSource.CurrentChanged
Dim oVw As DataRowView
oVw = TryCast(BindingSource.Current, DataRowView)
If Not oVw Is Nothing Then
MessageBox.Show(oVw.Item(0).ToString)
'
End If
End Sub
This will trigger each time the DGV moves to a new position. Change the name to whatever your BindingSource is.
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)
How can I select a single cell from selected row in datagridView and after selecting that I want to put simple search functionality (like we have in our windows folders-typing any characters and search should work)?
I do not really understand your question. If you want to select one cell, you can use the celldoubleclick event for exemple. And the to get the selected cell, use e.rowindex and e.columnindex which will give you the row and the column where the cell is located.
You can try this as a possible solution.
Dim nwData as CustomersDataSet = CustomersDataSet.GetCustomers()
m_CustomersGrid.DataSource = m_CustomersBindingSource
m_CustomersBindingSource.DataSource = nwData.Customers
Then you can sort using the BindingSource.
CustomersBindingSource.Sort = "ContactName ASC"
And you can find using the BindingSource.
Dim index as integer = _
CustomersBindingSource.Find("CompanyName", CompanyNameTextBox.Text)
If index <-1 then 'it was found; move to that position
CustomersBindingSource.Position = index
End If
You could then populate:
CustomersBindingSource.Find("CompanyName", CompanyNameTextBox.Text)
with the keys pressed in the cell by capturing them by utilizing:
Private Sub DataGridView1_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles DataGridView1.KeyUp
Dim dgv As DataGridView = TryCast(sender, DataGridView)
If dgv IsNot Nothing Then
'You will need some logic here to determine how long to wait between keyups
'Perhaps a timer that ticks every500 milliseconds and reset on keyup.
e.KeyData
End If
End Sub
I found the original Biding Source Logic at : This Location