How to get child datagrid values - vb.net

How can I save values in child popup DataGridView?
I am having parent datagridview and child DataGridView in vb.net
Consider I have 2 columns and 2 rows.
When I click 1st column, I will get child DataGridView just near to this cell. Child DataGridView also has 2 rows and 2 columns where I can enter values.
When I click 2nd column, I'll get another new child DataGridView near this cell.
Now if I move back to first column, values I entered are lost. How can I save entered values in popup child window?
Here is my code:
sub cell_click Dim _pointCell As Point = Me.DgV.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, True).Location Dim _pointGrid As Point = DgV.Location Dim _pointLocation As Point _pointLocation.X = _pointCell.X 'width _pointLocation.Y = _pointCell.Y 'height SelectionInGrid() mPopup.Show(DgV.PointToScreen(New Point(_pointLocation.X, _pointLocation.Y))) end sub
Public SelectionInGrid() Dim t1,t2 As New DataGridViewTextBoxColumn() Dim gv As New DataGridView
gv.Columns.Add(t1)
gv.Columns.Add(t2)
gv.Columns(0).HeaderText = "Employee"
gv.Columns(1).HeaderText = "Currency"
gv.Width = t1.Width + t2.Width
Dim mControlHost As ToolStripControlHost = New ToolStripControlHost(gv)
mControlHost.Padding = Padding.Empty
mControlHost.AutoSize = False
mPopup = New ToolStripDropDown()
mPopup.Padding = Padding.Empty
mPopup.Items.Add(mControlHost)
End
sub cell_click
Dim _pointCell As Point = Me.DgV.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, True).Location
Dim _pointGrid As Point = DgV.Location
Dim _pointLocation As Point
_pointLocation.X = _pointCell.X 'width
_pointLocation.Y = _pointCell.Y 'height
SelectionInGrid()
mPopup.Show(DgV.PointToScreen(New Point(_pointLocation.X, _pointLocation.Y)))
end sub
Public SelectionInGrid()
Dim t1,t2 As New DataGridViewTextBoxColumn()
Dim gv As New DataGridView
gv.Columns.Add(t1)
gv.Columns.Add(t2)
gv.Columns(0).HeaderText = "Employee"
gv.Columns(1).HeaderText = "Currency"
gv.Width = t1.Width + t2.Width
Dim mControlHost As ToolStripControlHost = New ToolStripControlHost(gv)
mControlHost.Padding = Padding.Empty
mControlHost.AutoSize = False
mPopup = New ToolStripDropDown()
mPopup.Padding = Padding.Empty
mPopup.Items.Add(mControlHost)
End

The problem lies in the SelectionInGrid Sub which is called every single time you click a cell. In this function you have these lines:
Dim gv As New DataGridView
Dim mControlHost As ToolStripControlHost = New ToolStripControlHost(gv)
mPopup = New ToolStripDropDown()
This means that everytime cell_click runs a new DataGridView, a new ToolStripControlHost and a new ToolStripDropDown are created. To solve this you need to keep track of the different ToolStripDropDowns. For example using a dictionary:
Private PopUps As New Dictionary(Of String, ToolStripDropDown)
sub cell_click
Dim _pointCell As Point = Me.DgV.GetCellDisplayRectangle(e.ColumnIndex, e.RowIndex, True).Location
Dim _pointGrid As Point = DgV.Location
Dim _pointLocation As Point
_pointLocation.X = _pointCell.X 'width
_pointLocation.Y = _pointCell.Y 'height
If PopUps.ContainsKey(<Parent Selected cell identifyer>) Then
mPopup = PopUps(<Parent Selected cell identifyer>)
Else
SelectionInGrid()
PopUps.Add(<Parent Selected cell identifyer>,mPopup)
End If
mPopup.Show(DgV.PointToScreen(New Point(_pointLocation.X, _pointLocation.Y)))
end sub
I do believe this should work. "Parent Selected cell identifyer" must be something unique from the Parent DGV row/cell that was clicked.

Related

Read data from dynamically created text-box

I'm trying to collect data after creating dynamic text-box with vb.net
Private Sub btn_OK_lines_number_Click(sender As Object, e As EventArgs)
Handles btn_OK_lines_number.Click
Dim i As Integer
Dim x As Integer
Dim Z As Integer
Z = 150
If IsNumeric(txt_lines_number.Text) Then
Int32.TryParse(txt_lines_number.Text, x)
For i = 1 To x
Dim newTB As New TextBox
Dim newLB As New Label
newLB.Name = "lbl_workstation_number_line" & i
newLB.Text = "Nbr Work Station in Line" & i
newLB.Size = New Size(190, 20)
newLB.ForeColor = Color.White
newLB.Font = New Font("consolas", 12, FontStyle.Regular, GraphicsUnit.Pixel)
newLB.Location = New Point(20, Z + i * 30)
newTB.Name = "Textbox" & i
newTB.Size = New Size(170, 20)
newTB.Location = New Point(200, Z + i * 30)
Me.Controls.Add(newTB)
Me.Controls.Add(newLB)
Next
i = i + 1
Else
MessageBox.Show("please enter a number")
txt_lines_number.Text = ""
End If
End Sub
Let's say you just have one row, and only create one TextBox. You set the name here:
newTB.Name = "Textbox" & i
where the resulting TextBox is named Textbox1. The problem is you can't just reference the identifier Textbox1 directly in your code, as you do with txt_lines_number. You can't even reference it as a member of the class (Me.Textbox1). This name didn't exist at compile time, and so it's not an identifier you can use, and it's not a member of the class at all. There was never a matching Dim statement for that name.
What you can do, though, is look again in the Controls collection where you added the TextBox to the form:
Me.Controls("Textbox1")
or
Me.Controls("Textbox1").Text
You may also need to cast the value to a TextBox:
Dim box As TextBox = DirectCast(Me.Controls("Textbox1"), TextBox)
MessageBox.Show(box.Text)
Remember that case matters here.
Further saving this in a DB is out of scope for one question. There are as many ways to do that as there are programmers in the world. You should make your own attempt first, and come back here with a new question when you run into specific problems.
Thank you,
this is my attempt and it is done !
Dim userInput As TextBox = Form1.Controls.Item("TextBox" & i.ToString)
mycommand.Parameters.AddWithValue("#workstation", userInput.Text)
:D
Because you creating dynamic amount of input controls, right tool for the job will be DataGridView control.
Create a class to represent your data
Public Class LineInfo
Public Property Number As Integer
Public Property WorkStationNumber As Integer
End Class
Create `DataGridView in the form designer.
Private Sub btn_OK_lines_number_Click(sender As Object, e As EventArgs) Handles btn_OK_lines_number.Click
Dim linesAmount As Integer
If Integer.TryParse(txt_lines_number.Text, linesAmount) = False Then
MessageBox.Show("please enter a number")
txt_lines_number.Text = ""
Exit Sub
End If
' Create class instance for every line
Dim lines =
Enumerable.Range(1, linesAmount)
.Select(Function(i) New LineInfo With { .Number = i })
.ToList()
'Set lines as DataSource to the DataGridView
Me.DataGridView1.DataSource = lines
End Sub
DataGridView will display all lines and provide input fields to update work station numbers.
You can access updated lines later by casting DataSource back to the List
Dim lines = DirectCast(Me.DataGridView1.DataSource, List(Of LineInfo))
' Now you can access all data and save it to the database
Dim parameters =
lines.Select(Function(line)
Return new SqlParameter With
{
.ParameterName = $"#workstation{line.Number}",
.SqlDbType = SqlDbType.Int,
.Value = line.WorkStationNumber
}
End Function)
.ToList()
myCommand.Parameters.AddRange(parameters)
You can freely change style, font colors of different columns in the datagridview.

VB.NET How to add Event Handler to ComboBoxColumn located in programmatically created controls?

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.

ListView combobox control at the end of line

Wondering how to place combobox control as last sub item for each row with some data coming from datasource. Have this code below:
LvSelMat.BeginUpdate()
Dim rodzajID as String = TreeMaterials.SelectedValue
Dim rodzajName as string = TreeMaterials.SelectedNode.Text
Dim parent as string = TreeMaterials.SelectedNode.Parent.Text
Dim li as ListViewItem
li = LvSelMat.Items.Add(parent)
li.SubItems.Add(rodzajName)
li.SubItems.Add(rodzajID)
'Here want to add combobox...
so far i tried like this but its only showing up combobox without any other items in row...
Dim combo as new combobox
combo.DataSource = New Variation().GetAll
combo.DisplayMember = "Name"
combo.ValueMember = "Id"
combo.dropdownstyle = ComboBoxStyle.DropDownList
' combo.height = item.bounds.height
' combo.location = new point(item.bounds.right, item.bounds.y)
LvSelMat.controls.add(combo)

Changing double clicking activation on Combo box cell to single click?

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

Controls are not added to tabpage VB.NET

I run the following code in the constructor of a window. The "label" gets added but none of the other controls are shown on screen. If I debug the newTab.Controls there are several controls in it. Why don't they show up on the screen and I only see the "label" control.
Thanks
Dim graphlist As ArrayList = New ArrayList
For Each funct As TL_FUNCTION In functionlist
If (funct.functionname = functi) Then
If Not (graphlist.Contains(funct.picture)) Then
graphlist.Add(funct.picture)
End If
End If
Next
For Each picture In graphlist
Dim NewTab As New TabPage
NewTab.Name = picture
NewTab.Text = NewTab.Name
Me.TabControl1.Controls.Add(NewTab)
Me.TabControl1.SelectedIndex = Me.TabControl1.TabCount - 1
For Each func As TL_FUNCTION In functionlist
If (func.picture = picture) Then
Dim label As Label = New Label
label.Text = func.curve.ToString
NewTab.Controls.Add(label) 'This label shows up
Dim key As String
Dim values() As String
For Each key In func.values.Keys
values = func.values.GetValues(key)
For Each value As String In values
Dim label2 As New Label
label2.Text = key.ToString
Dim textb As TextBox = New TextBox
textb.Text = value
NewTab.Controls.Add(label2) 'this one is not shown on the tab
NewTab.Controls.Add(textb) 'this one is not shown on the tab
Next value
Next key
End If
Next
Next
You are placing the new labels and textboxes underneath the new label that you see in the TabPage because you never set their location, so it defaults to point (0, 0).
Try setting the location for the controls:
For Each value As String In values
Dim label2 As New Label
label2.Text = key.ToString
label2.Location = New Point(10, NewTab.Controls.Count * 24)
Dim textb As TextBox = New TextBox
textb.Text = value
textb.Location = New Point(label2.Right + 4, label2.Top)
NewTab.Controls.Add(label2)
NewTab.Controls.Add(textb)
Next value