VB.Net Form DirectCast on Forms.Panel - vb.net

I need to loop through the textboxes of my form, which are located inside a panel. I'm trying to do it like this....
For Each Cntrl As Control In DirectCast(Me.Controls(PanelName), Panel).Controls
next
The reason I need to feed the panel's name to the loop is because I have two panels that exist in 2 different TabPages. A button exists on each TabPage that performs the same function, but the panels and textboxes have different names. I have the loop inside a function that handles both TabPage button clicks, therefore I need the loop to point to the right panel.
The "PanelName" matches the target panel's name, and the panel is of System.Windows.Form.Panel.
I get the "Object reference not set to an instance of an object." message.
Is this not possible?

No need to cast:
For Each Cntrl As Control In PanelName.Controls
Next
If all you have is the name of the panel and not the control reference, then you at least need to know which TabPage has the panel:
For Each ctrl As Control In TabControl1.TabPages(1).Controls("panel1").Controls
Next
Alternatively, you can use:
Me.Controls.Find(PanelName, True)
to return the panel by name while searching child controls recursively.

Related

Is there a way to update a TextBox when is not visible?

I have a TextBox nested inside a TabControl.
Form->TabControl1->TabPage1->TabControl2->TabpPage2->GroupBox->TextBox
When the TabPage1, TabPage2 is selected, so the TextBox is visible to the user all the TextBoxEvents works OK, but when the user selects another TabPage it doesn't work.
I have a timer that send data periodically to know if an external device is present on a specific virtual COM port.
When the external device answer I put that data in that TextBox and set a global flag(boolean) to let the rest of the program that a device is present.
I'm processing the received data on a Private Sub and changing that TextBox with a Lambda expression like this
Me.Invoke(Sub()
Me.VersionFirmwareTxt.Text = RespX.Substring(5)
End Sub)
You can access the TextBox by name from anywhere whether it is visible or not, via casting (CType), and update its text value using the syntax:
'(from within the same Form, e.g., Form1)
CType(TabControl1.TabPages(1).Controls("VersionFirmwareTxt"), TextBox).Text = RespX.Substring(5)
'(from a different Form)
CType(Form1.TabControl1.TabPages(1).Controls("VersionFirmwareTxt"), TextBox).Text = RespX.Substring(5)
If you dynamically added the TextBox to the controls of the parent (TabPage), you will know exactly where the TextBox is located, since you would have already used, e.g.:
TabControl1.TabPages(1).Controls.Add(VersionFirmwareTxt)
Whereas if you manually added the TextBox to the TabPage, you also know the parent control.

VB - Reference Control via a string stored in My.Settings

I'm making an extremely simple app which has multiple screens (as Panels) that are hidden/shown clicking buttons on a left sidebar.
I have a PNLHome, PNLServerSettings, PNLScripts, and PNLSettings as the main panels.
Each of the Panels .Name properties are "PNLHome", "PNLServerSettings", ....etc.
I want to be able to change the "Start Up Screen" based on the selection you make in a ComboBox in PNLSettings, so when you launch the app, the Panel that is immediately showing is based on that ComboBox selection.
I have the ComboBox items in place and I have a function that hides all panels and shows the one you pass into it:
showPanel(PNLHome) for example which will essentially just show the Panel you give it, all this is working fine. This showPanel() is triggered upon clicking one of the main buttons on the left sidebar
What I want is to pass a Control.Name string into my showPanel() func, then I want to store this .Name string into My.Settings via a "Save/Apply" button in the Settings Panel which I can set up easily.
Since I will be passing the .Name String into my showPanel() function, I need to be able to reference the Panel I'm showing by it's name rather than the Object ID itself (I'm not sure if it's called an ID but it's the 'name' declaring the Panel via a "DIM WithEvents PNLHome As Panel" declaration.
To summarize the question; Can I reference the PNLHome by its .Name Property?
Otherwise can I store the ID of PNLHome directly in My.Settings instead? I could easily pass My.Settings.StartPanel into my showPanel() func.
Just use the Controls collection to find the control.
Private Function GetPanel(PanelName As String) As Panel
Dim SomePanel As Panel = CType(Controls(PanelName), Panel)
Return SomePanel
End Function

Do you have to show every tab before all textboxes actually populate?

I have a vb.net form that uses multiple textboxes across several different tabs. Within one of those tabs, I have a sub set of tabs. My save functionality calls stored procs for each tab and cycles through the values on each page to either do an update or a "add new". I noticed that while testing, some of the pages do not save or update any of the values in the textboxes. After a few days of investigating, I realized that if I edit something, then physically click through the other tabs, it all saves/updates properly. If I don't click through them, they don't all save. Is there a reason for this that I am missing? When you enter a search value, I cycle through the pages and populate them all at the same time so I was assuming it wrote those values BEFORE it physically rendered...I guess I am wrong?
From the TabPage documentation Remarks section
Controls contained in a TabPage are not created until the tab page is shown, and any data bindings in these controls are not activated until the tab page is shown.
So the answer to your question is "Yes the tabpage must be shown".
However, the definition of "shown" is subject to interpretation. In reality, all you need to do set the TabPage.Visible property to True and not actually cycle through and display each TabPage.
A recursive scan of the form for TabPage controls will work:
Private Shared Sub TabPagesVisible(parent As Control)
For Each c As Control In parent.Controls
If TypeOf c Is TabPage Then c.Visible = True
TabPagesVisible(c)
Next
End Sub
Example usage:
Sub SaveFormTabData()
TabPagesVisible(Me) ' Me refers to the containing form
' code to save control data
End Sub

vb.net Loop through Controls on Form and if ListView Loop through Columns and Rows

I have 3 ListViews in a UserForm and also a few other items. Currently when I expand the UserForm, the ListViews and other items expand in relation to the increase in size of the UserForm.
What I'm after doing is also expanding the size of the Columns within the ListViews by cycling through all Controls on the UserForm and checking if it is a ListView, then cycling through all the columns and extending as required.
This is where I am currently at...
For Each Ctrl As Control In Me.Controls
If (TypeOf Ctrl Is ListView) Then
' This is where I'm not sure what to do!
' I want to loop through this Ctrl and view its columns
End If
Next
Anyone any ideas?
If Plutonix' suggestion of enabled auto-resizing columns doesn't work, then read on...
To access the control's properties, you'll need to cast it to ListView first (so far you've only checked to see if it is a ListView. Then, you can loop through the rows and columns:
For Each Ctrl As Control In Me.Controls
If TypeOf Ctrl Is ListView Then
Dim currentListView As ListView = DirectCast(Ctrl, ListView)
' Loop over the rows (items) in the view
For Each item As ListViewItem In currentListView.Items
Next
End If
Next
You might also end up needing a recursive control search -- your current loop will only look for controls that are a direct child of Me.
Another idea: simply return controls of the correct type in the outer for-loop:
For Each listViewControl As Control In Me.Controls.OfType(Of ListView)()
For Each item As ListViewItem In listViewControl.Items
Next
Next

Clean way to display/hide a bunch of buttons based on a ComboBox selection

I'm writing a standalone application in VB.NET using Visual Studio 2005.
I want to display/hide a bunch of Buttons based on the selected value of a ComboBox. Each selection would have a different set of Buttons to display, and I'd like to have them arranged in a nice grid.
Driving a TabControl with the ComboBox value would be the kind of behavior I want, but I don't want it to look like a TabControl to the user because it might be confusing.
Is there a way to do this?
Basically, I'd like Selection1 of the ComboBox to show Buttons 1-4, Selection2 to show Buttons 5-11, Selection3 to show (maybe) Buttons 1, 3, 5, 6, and 8, etc., have them arranged nicely, and have the GUI show only the ComboBox and the buttons.
Thanks in advance as always!
Use a Panel control (or multiple if the items aren't grouped right next to each other) and set the visibility accordingly.
(Added)
You CAN stack panels on top of each other, so that the buttons all look like they're in the same location. but it becomes a maintenance nightmare and I don't recommend it.,
Hack warning - the following is a hack, but it works.
Another option is to use a tab control, but hide the tab buttons. (You can do this by positioning a panel over the buttons, but you have to be careful of letting the user resize the form.) Then you set the TabIndex based on the drop-down changing.
Edit again - added per comment
If you use the hack, you can add this into the ComboBox's selected index changed event....
(code may be wrong, as I'm not at my dev pc and can't check, but you get the idea)
TabControl1.SelectedIndex = ComboBox1.SelectedIndex
You could put all of your buttons on a panel on your form. Then when the SelectedIndex event of the combobox fires, you can loop through the buttons on the panel and turn them on and off based on their Tag property.
For this example you would set the Tag property of each button equal to the combobox index or indexes that you want it to turn on for. If you want it visible for more than one combo selection just comma seperate the index values in the tag property.
You don't have to key off of the combobox index. You could use the selected text for example. If you did that, just put the texts to show the button for in the tag property and change the code from ComboBox1.SelectedIndex.ToString to ComboBox1.SelectedText.
The buttons will turn on and off where they are placed at design time, but you could add some code here to arrange them dynamically as well so that all the visible buttons are neatly arranged.
Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
For Each ctrl As Control In Me.Panel1.Controls
If TypeOf ctrl Is Button Then
If Array.IndexOf(Split(ctrl.Tag, ","), ComboBox1.SelectedIndex.ToString) > -1 Then
ctrl.Visible = True
Else
ctrl.Visible = False
End If
End If
Next
End Sub
Maybe using a FlowLayoutPanel will help you display the buttons.
You can use a jagged array to define which buttons belong to which combo-box item.