how to reference to data from listviews on different tabpages? - vb.net

i have several tabpages in one tabcontrol, each contains nothing but a listview. I need to get the data/items from the listview in the selected tab. My problem is, I can't refer to the listview. I tried
exportpath = TabControl1.SelectedTab.Controls(0).
but at this point, the IDE doesn't know that there's a listview, so I can't choose the
.items(i).tostring
The variables to create the tabpage and the listviews are already overwritten at this moment. Do you think I should choose another way to create the tabs and the listview (maybe create a list(of listviews) to remember the stuff), or is there a way close to my example try?
Best regards, Jan

dim lst as listview = TabControl1.SelectedTab.Controls(0)
dim exportpath as string = lst.items(i).tostring
? Would that work.
edit: assuming the listview is the only control you have there.

I wouldn't load the control based off index in the collection.
I'm assuming since you are trying to access these dynamically you are also creating them dynamically?
Add a tag that can be referenced on the control or use the same naming convention. listview for the name ie MainListView# where # is just incremented or just assign all the tags on the listview to something consistent.
Then use helper function to loop through the controls collection for that tab and find the actual control.
Then loop through the collection of controls and find the one you want to target.
Dim lstView As ListView = ControlNameStartsWith(TabControl1.SelectedTab, "MainListView")
lstView.Items.Add("test")
FUNCTIONS:
Function ControlByTag(ByRef parent As Control, ByVal tag As String)
For Each Cntl As Control In parent.Controls
If Cntl.Tag.ToString.ToLower = tag.ToLower Then
Return Cntl
Exit For
End If
Next
Return Nothing
End Function
Function ControlNameStartsWith(ByRef parent As Control, ByVal likePhrase As String)
For Each Cntl As Control In parent.Controls
If Cntl.Name.ToLower.StartsWith(likePhrase.ToLower) Then
Return Cntl
Exit For
End If
Next
Return Nothing
End Function
Function ControlByName(ByRef parent As Control, ByVal name As String)
For Each Cntl As Control In parent.Controls
If Cntl.Name.ToLower = name.ToLower Then
Return Cntl
Exit For
End If
Next
Return Nothing
End Function

Related

How to save data into database from dynamically created text boxes

I have dynamically created text boxes on flowlayout panel. The text box can be any number. I am trying to save those value(integer) from text box into database. It takes me a day to achieve this, and i am a newbie by the way. Please guide me how to achieve this. Thank you so much. I try to save into List(Of...) collection but it only returns last value.Here is how i am trying to achieve this. I declare shared list of List type in another class called clsHelper.
Private Sub saveIntoList(flp As FlowLayoutPanel)
clsHelper.list = New List(Of String)
For Each tb in flp.Controls
If TypeOf tb Is TextBox Then
txtNo = DirectCast(tb,TextBox)
If txtNo.Name = "txtNo" Then
clsHelper.list.Add(txtNo.Text)
End If
End If
Next
End Sub
FlowLayoutPanel with six text boxes
The problem is probably this If statement. Only the content of the TextBox whose name is "txtNo" is added to your list. The content of other TextBoxes with different names are not added. Remove the If and the content all TextBoxes will be added to your list.
If txtNo.Name = "txtNo" Then
clsHelper.list.Add(txtNo.Text)
End If
If TextBoxes are not all immediate children of the FlowLayoutPanel, you will need to modify your code as follows, to recursively iterate all the controls hierarchy below the FlowLayoutPanel.
Private Sub saveIntoList(flp As FlowLayoutPanel)
clsHelper.list = New List(Of String)
_saveIntoList(flp)
End Sub
Private Sub _saveIntoList(control As Control)
If TypeOf control Is TextBox Then
clsHelper.list.Add(DirectCast(control, TextBox).Text)
Return
End If
For Each child As Control In control.Controls
_saveIntoList(child)
Next
End Sub

VB Net access to form control by their variable names

From a FormName2, and I need to set a text in a TextboxName1 that is in a FormName1, by their string names.
Then, from FormName2, I should set the text like FormName1.TextboxName1.text = "test".
However, I need to achieve it with string names of the controls.
stringFormName.stringTextboxName.text ="test"
How to reach it?
You could retrieve all the opened instances of your forms in the Application.OpenForms collection.
Using that collection you can retrieve the form with the specified name
Dim aForm = Application.OpenForms.Item("FormName1")
At this point, you can scan the controls of this form with the same pattern for a control with a specific name
If aForm IsNot Nothing Then
Dim aControl = aForm.Controls.Item("TextBoxName1")
if aControl IsNot Nothing then
aControl.Text = "test"
End If
End If
The only problem with this search for a control is the possibility of the control to be contained in a control container different from the top level form. For example the control could be inside a GroupBox or a Panel. In this case you need to use the Find method from the Control collection with the second parameter set to true to search all the control hierarchy
Dim aControl = aForm.Controls.Find("TextBoxName1", True)
Use FindControl:
Private Sub Button1_Click(sender As Object, MyEventArgs As EventArgs)
Dim myControl1 As Control = FormName1.FindControl("stringTextboxName")
If (Not myControl1 Is Nothing)
' Get control's parent.
Dim tb as TextBox= CType(myControl1, TextBox)
tb.text="test"
Else
Console.WriteLine("Control not found.....")
End If
End Sub
If you have nested elements you may need to call find control recursively.

Looping through all Combo boxes on a VB form

I am making a grade application for a school project and I am wondering how I can loop through and check a value in all combo boxes on a certain form, I have 19 units to check; trying to be efficient without making 19 case statements. I have tried an array and me.controls.
Try this :
For Each c As Control In Me.Controls.OfType(Of ComboBox)()
'You cann acces to ComboBox her by c
Next
Note that if you have controls host by containers (TabControl, SPlitPanel, etc.) you may not find all of your controls.
Here is a recursive call that should return all of your controls:
Sub GetControlList(container As Control, ByVal ctlList As List(Of Control))
For Each child As Control In container.Controls
ctlList.Add(child)
If (child.HasChildren) Then
GetControlList(child, ctlList)
End If
Next
End Sub
I have on occasion had problems with the controls on SplitContainer panels so if you use a splitter make sure you are getting all your controls.
Once you have a complete list of controls you can operate on them. This sample is working with DataGridView controls:
Dim ctrls As New List(Of Control)
GetControlList(Me, ctrls)
For Each dgv As DataGridView In ctrls.OfType(Of DataGridView)()
AddHandler dgv.DataError, AddressOf DataGridView_DataError
Debug.Print(dgv.Name)
Next
FYI the generic data error code:
Private Sub DataGridView_DataError(sender As Object, e As DataGridViewDataErrorEventArgs)
Dim dgv As DataGridView = sender
Dim sGridName As String = dgv.Name.Replace("DataGridView", "")
Dim col As DataGridViewColumn = dgv.Columns(e.ColumnIndex)
Dim sColName As String = col.HeaderText
MsgBox(sGridName & vbNewLine & "Column " & sColName & vbNewLine & e.Exception.Message, MsgBoxStyle.Exclamation)
End Sub
You already have the OfType(OF T) method. You use it like this:
ForEach box As ComboBox In MyForm.Controls.OfType(Of ComboBox)()
Next
But this only checks the direct children of your control. If you have container controls like GroupBox, Panels, FlowControlLayoutPanel, etc, you'll miss the controls nested inside them. But we can build a new OfType() method to search these recursively:
Public Module ControlExtensions
<Extension()>
Public Iterator Function OfTypeRecursive(Of T As Control)(ByVal Controls As ControlCollection) As IEnumerable(Of T)
For Each parent As Control In Controls
If parent.HasChildren Then
For Each child As Control In OfTypeRecursive(Of T)(parent.Controls)
Yield child
Next child
End If
Next parent
For Each item As Control In Controls.OfType(Of T)()
Yield item
Next item
End Function
End Module
And you use it the same way:
ForEach box As ComboBox In MyForm.Controls.OfTypeRecursive(Of ComboBox)()
Next
You'll probably want to check containers for controls of the type you're looking for, here's a little function that should do the trick for you.
Private Function GetControls(Of T)(container As Control, searchChildren As Boolean) As T()
Dim Controls As New List(Of T)
For Each Child As Control In container.Controls
If TypeOf Child Is T Then
DirectCast(Controls, IList).Add(Child)
End If
If searchChildren AndAlso Child.HasChildren Then
Controls.AddRange(GetControls(Of T)(Child, True))
End If
Next
Return Controls.ToArray()
End Function
Here's the usage, if search children is True then all child containers will be searched for the control you're looking for. Also, for the top most container we'll just pass in Me assuming you're calling the code from within your Form, otherwise you could pass the Form instance or a specific Panel, GroupBox, etc.
Dim ComboBoxes As ComboBox() = GetControls(Of ComboBox)(Me, True)

Deleting controls each time ShowDialog is called

I have a form that I display exclusively with the ShowDialog method. In the Form_Shown event, I dynamically create a set of labels and text boxes based on a public variable set in the form making the call.
I understand that the form is not closed or destroyed but simply hidden between calls, and as such I added code at the top of my Form_Shown event to clear out any controls from a previous call, but the controls aren't being removed. I have tried ctrl.Dispose (as in the code below) and Me.Controls.Remove(ctrl). Neither produces an error, but the Textboxes are not removed and new ones are created over them. (For some reason,
This is the first time I've dynamically created/removed controls in .NET, so it's possible my yearning for VB6's control arrays have something to do with the error.
The form builds itself based on the calling form's public ListView variable. The calling form makes certain this variable is not nothing and that items are selected if and only if the user is editing an existing row.
Public Class frmTableEdit
Private isNew As Boolean
Private inputText() As TextBox
Private Sub FormTableEdit_Shown(sender As Object, e As EventArgs) Handles MyBase.Shown
For Each ctrl As Control In Me.Controls
If TypeOf (ctrl) Is TextBox Or TypeOf (ctrl) Is Label Then
ctrl.Dispose()
End If
Next
With frmKioskData.TBLobj
Dim fieldCount As Integer = .Columns.Count - 1
isNew = .SelectedIndices.Count = 0
'(code setting size of form and location of OK/Cancel buttons is here)
ReDim inputText(fieldCount)
For i As Integer = 0 To fieldCount
Dim lbl As New Label, txt As New TextBox
inputText(i) = txt
Me.Controls.Add(lbl)
Me.Controls.Add(txt)
'(code setting size and and position of lbl & txt is here)
'lbl.Tag = i (I commented these lines out because I never used the
'txt.Tag = i Tag property, but can if a solution calls for it.)
lbl.Text = .Columns(i).Text
If isNew Then
txt.Text = ""
Else
txt.Text = .Items(.SelectedIndices(0)).SubItems(i).Text
End If
Next
End With
End Sub
End Class
If #Plutonix's suggestion in the comment above does not quite work for you, I think it would be easiest and make more sense to dispose of the form after calling ShowDialog, and then when you need to show that form you create a new instance with a parameter that tells it what dynamic controls to load.
So you'd have a New method in frmTableEdit that uses this parameter:
Public Sub New(ByVal fieldCount As Integer)
InitializeComponent()
fieldCount = fieldCount 'Where fieldCount is a class variable
End Sub
And when you call this form from frmKioskData, you can do so like this:
Dim newTableEdit As New frmTableEdit(Me.TBLobj.Columns.Count - 1)
newTableEdit.ShowDialog()
newTableEdit.Dispose()
Then the code in your frmEditTable's Shown event just simply has to add the controls accordingly, without the need to remove old ones:
ReDim inputText(fieldCount)
For i As Integer = 0 To fieldCount
Dim lbl As New Label, txt As New TextBox
inputText(i) = txt
Me.Controls.Add(lbl)
Me.Controls.Add(txt)
'(code setting size and and position of lbl & txt is here)
'lbl.Tag = i (I commented these lines out because I never used the
'txt.Tag = i Tag property, but can if a solution calls for it.)
lbl.Text = .Columns(i).Text
If isNew Then
txt.Text = ""
Else
txt.Text = .Items(.SelectedIndices(0)).SubItems(i).Text
End If
Next
How you get the isNew value is up to you - you can add that as a second parameter to the form's New, or get it the same way you are now...w/e. If it were me I'd normally add that as another New parameter.

Issue when binding combobox and listbox to List (VB.NET)

I'm trying to bind a ComboBox and a ListBox to a List(Of String) in Vb.Net (VS2013), this is for a WinForms application, the thing is that after setting the DataSource property on both the ComboBox and the ListBox, selecting one item on either one of them affects the other control, for example, after the controls have been populated with the information if I select an item from the ListBox, then the same item gets selected in the ComboBox, and this goes the same way for the ComboBox, if I select an item from it, then that item gets also selected in the ListBox, so my question is... how can I bind the combobox and listbox to the same List(Of String) without affecting the behavior on the controls, the purpose is to keep all the controls within that form syncronized based on the contents of the List, I declared the List in a module like this:
Public listaAreas As New List(Of String)
then the controls are populated like this on form load:
cmbArea.DataSource = listaAreas
lstAreas.DataSource = listaAreas
And I run this method whenever I need to update the information:
Private Sub RefreshLists()
lstAreas.DataSource = Nothing
lstAreas.DataSource = listaAreas
cmbArea.DataSource = Nothing
cmbArea.DataSource = listaAreas
End Sub
Please let me know if I'm missing some information, this is my first post but I think it is clear enough so you get the idea of what I'm trying to accomplish here ... =)
Thanks in advance!
Try setting up separate BindingSources and try using a BindingList(Of String) instead of just a List, which won't report item changes:
Private listaAreas As New BindingList(Of String)
Private cbSource As New BindingSource(listaAreas, String.Empty)
Private lbSource As New BindingSource(listaAreas, String.Empty)
Public Sub New()
InitializeComponent()
cmbArea.DataSource = cbSource
lstAreas.DataSource = lbSource
End Sub
The same currency position is being used in your code, but by defining two separate binding sources, each one will have its own position property.