Using string as object name - vb.net

I'm trying to use string as object name. Example I have an object and has a name = Label1. Can I do this?
Dim i As String = "Label1"
someVariable = i.Text
I'm using string as object name, is it possible?

You could iterate over all of the controls as #Christian Sauer said but you might run into problems if any controls are containers of controls. You'd need to do a recursive search to solve that. However, the ControlCollection actually has a Find() method that you can use. It returns an array of controls that match the name and optionally performs a recursive search.
''//Our final control
Dim someVariable As Control = Nothing
''//Search recursively for our control
Dim SearchedControls = Me.Controls.Find(key:="Label1", searchAllChildren:=True)
''//If we found one and only one control
If SearchedControls.Count = 1 Then
''//Set it to our variable
someVariable = SearchedControls(0)
Else
''//Whatever your logic dictates here
End If

This is not possible - but what you can do:
Dim i As String = "Label1"
Dim Obj as Label
for each elem in me.controls
if elem.Name = i then
Obj = elem
exit for
end if
next
someVariable = obj.Text
I am iterating over all WinForms control to find the label with the Name "Label1" - when found, i assign the label to a Variable.
This works, but can be quite dangerous, especially if you add controls

I know it's been answered, but this is from my library, and I use it all the time. It will iterate over all controls, and containers' controls recursively as #ChrisHaas suggested.
Public Function GetControlByName(ByRef parent As Control, ByVal name As String) As Control
For Each c As Control In parent.ChildControls
If c.Name = name Then
Return c
End If
Next
Return Nothing
End Function
<Extension()> _
Public Function ChildControls(ByVal parent As Control) As ArrayList
Return ChildControls(Of Control)(parent)
End Function
<Extension()> _
Public Function ChildControls(Of T)(ByVal parent As Control) As ArrayList
Dim result As New ArrayList()
For Each ctrl As Control In parent.Controls
If TypeOf ctrl Is T Then result.Add(ctrl)
result.AddRange(ChildControls(Of T)(ctrl))
Next
Return result
End Function
(It's been asked and answered before)
Loop Through Controls on Web User Control

I'm sure it's answered but some points to be clear it's control array and result so as to be sure it's corrected.
Private Sub btn1_click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn1.Click
Dim Ds As New DataSet
Dim str As String = ""
str = " SELECT TOP (10) t_Suppliers.STNo from t_Suppliers "
Ds = SqlHelper.ExecuteDataset(ConnectionString, CommandType.Text, str)
For i As Integer = 0 To Ds.Tables(0).Rows.Count - 1
Dim str1 As String = "lblInv" & i + 1
Dim OBj As New Label
Try
Dim SearchedControls() As Control = Me.Controls.Find(key:=str1, searchAllChildren:=True)
If SearchedControls.Length > 0 Then
SearchedControls(0).Text = Ds.Tables(0).Rows(i).Item("STNo").ToString
End If
Catch
End Try
Next
End Sub

I found the following solution on another site.
It works.
--Quote -
Dim TextBox As TextBox
Dim I As Integer = 2
Dim name As String = "TextBox" & I.ToString
TextBox = Me.Controls.Item(name)
TextBox.Text = "Something special"

Related

Check the item in ToolStripMenuItem dynamically through Sub Function

I am new to .Net Visual Basic, I am currently self learning and trying to make some small application.
I need a help on Checking a sub menu item of ToolStripMenuItem
Complete concept is like:
I have a datagridview in which user will be able to rearrange the column or make a column visible or Hidded for this I have Sub / Function like below:
Public Sub Fun_Grid_Colomn_Visibility(ByVal GridName As DataGridView, ByRef ColName As String, ByVal MS_col As ToolStripMenuItem, ChkVal As Boolean)
If ChkVal = True Then
With GridName
.Columns("" & ColName & "").Visible = False
End With
MS_col.Checked = False
Exit Sub
End If
If ChkVal = False Then
GridName.Columns("" & ColName & "").Visible = True
MS_col.Checked = True
Exit Sub
End If
End Sub
On the form close I will be saving the user grid format as below (Got code from another Q/A Post) :
Public Sub WriteGrideViewSetting(ByVal dgv As DataGridView, ByVal FileName As String)
Dim settingwriter As XmlTextWriter = New XmlTextWriter("C:\Users\<username>\Desktop\temp\" & FileName & ".xml", Nothing)
settingwriter.WriteStartDocument()
settingwriter.WriteStartElement(dgv.Name)
Dim count As Integer = dgv.Columns.Count
For i As Integer = 0 To count - 1
settingwriter.WriteStartElement("column")
settingwriter.WriteStartElement("Name")
settingwriter.WriteString(dgv.Columns(i).Name)
settingwriter.WriteEndElement()
settingwriter.WriteStartElement("width")
settingwriter.WriteString(dgv.Columns(i).Width.ToString())
settingwriter.WriteEndElement()
settingwriter.WriteStartElement("headertext")
settingwriter.WriteString(dgv.Columns(i).HeaderText)
settingwriter.WriteEndElement()
settingwriter.WriteStartElement("displayindex")
settingwriter.WriteString(dgv.Columns(i).DisplayIndex.ToString())
settingwriter.WriteEndElement()
settingwriter.WriteStartElement("visible")
settingwriter.WriteString(dgv.Columns(i).Visible.ToString())
settingwriter.WriteEndElement()
settingwriter.WriteEndElement()
Next
settingwriter.WriteEndElement()
settingwriter.WriteEndDocument()
settingwriter.Close()
End Sub
End Module
If the user is reopening the form I used the below (Q/A code) to rearrange Datagridview column as pervious :
Public Sub ReadDataGridViewSetting(ByVal dgv As DataGridView, ByVal FileName As String, ByRef Frm_name As Form)
Dim xmldoc As XmlDocument = New XmlDocument()
Dim xmlnode As XmlNodeList
Dim CMSN_ToolName As String
Dim Var_file_Chk As String = "C:\Users\<user>\Desktop\temp\" & FileName & ".xml"
If System.IO.File.Exists(Var_file_Chk) = True Then
Dim fs As FileStream = New FileStream(Var_file_Chk, FileMode.Open, FileAccess.Read)
xmldoc.Load(fs)
xmlnode = xmldoc.GetElementsByTagName("column")
For i As Integer = 0 To xmlnode.Count - 1
Dim columnName As String = xmlnode(i).ChildNodes.Item(0).InnerText.Trim()
Dim width As Integer = Integer.Parse(xmlnode(i).ChildNodes.Item(1).InnerText.Trim())
Dim headertext As String = xmlnode(i).ChildNodes.Item(2).InnerText.Trim()
Dim displayindex As Integer = Integer.Parse(xmlnode(i).ChildNodes.Item(3).InnerText.Trim())
Dim visible As Boolean = Convert.ToBoolean(xmlnode(i).ChildNodes.Item(4).InnerText.Trim())
dgv.Columns(columnName).Width = width
dgv.Columns(columnName).HeaderText = headertext
dgv.Columns(columnName).DisplayIndex = displayindex
dgv.Columns(columnName).Visible = visible
Next
fs.Close()
End If
End Sub
Now what I need is that a Function or Sub for the Itemmenu. If a Particular column is Visible in the datagridview then the particular Itemmenu should be checked else it would be unchecked. I need this function when Itemmenu is being displayed / opened.
what I tried just (for sample) in Itemmenu opening is like
Private Sub ColumnsToolStripMenuItem_DropDownOpening(sender As Object, e As EventArgs) Handles ColumnsToolStripMenuItem.DropDownOpening
If DGV_CompList.Columns("DGC_Est").Visible = True Then
Dim CMSN_ToolName = MS_CV_Est.Name
Dim unused As ToolStripMenuItem = New ToolStripMenuItem(CMSN_ToolName) With {
.Checked = True
}
End If
End Sub
DGV_CompList -> DataGridView
DGC_Est -> Column Name of datagridview
MS_CV_Est -> - ToolStripMenuItem which need to checked
(Note: I will be changing the MenuItem Name to Match Datagrid Column name for Sync)
But the ToolStripMenuItem is not getting checked.
Actually I need function / Sub where I will be able to pass the grid name and the Menuname and loop through the grid columns and check if the column is visible or not if the particular column is visible then I need to check that item in the itemmenu.
I am requesting for the sub / function because it can be used for any toolstripmenuitem in any form.
Thanks and Regards.
As per #Jimi's hint, assigned each required Menuitem's Tag property with the datagridview column name and created the below sub / function :
Public Sub Fun_ToolStripMenuItem_Check(ByVal dgv As DataGridView, ByVal TS_Menu_Items As ToolStripItemCollection)
For Each item As ToolStripMenuItem In TS_Menu_Items.OfType(Of ToolStripMenuItem)
If Not item.Tag = "" Then
If dgv.Columns(item.Tag).Visible = True Then
item.Checked = True
Else
item.Checked = False
End If
End If
For Each submenu_item As ToolStripMenuItem In item.DropDownItems.OfType(Of ToolStripMenuItem)
If Not submenu_item.Tag = "" Then
If dgv.Columns(submenu_item.Tag).Visible = True Then
submenu_item.Checked = True
Else
submenu_item.Checked = False
End If
End If
Next
Next
End Sub
Note in the loop used - " OfType(Of ToolStripMenuItem) " because I have ToolStripSeparator between the Itemmenus.
On mouse over called the Sub by :
Private Sub MS_ColumnVisible_DropDownOpening(sender As Object, e As EventArgs) Handles MS_ColumnVisible.DropDownOpening
Fun_ToolStripMenuItem_Check(DGV_CompList, MS_CompDGV.Items)
End Sub
'DGV_CompList' - Datagridview Name and 'MS_CompDGV' - ContextMenuStrip Name
More important is that I did not assign any value to the Tag property to Menuitems which are not used show or hide the datagridview columns.

String form name to form reference

Basically, I am rewriting some code working for years. Over the time I have many (60+) references to forms - there's a menuitem with OnClick event for each form, where a form reference was created:
Private Sub SomeForm_Click(sender As Object, e As EventArgs) Handles MenuItemForSomeForm.Click
NewTab("Some Form", New SomeForm, 0)
End Sub
...where first parameter is a name to put in a tabPage.Text where the form is opened, second is a new instance of the (particular) form SomeForm and 0 is a default record to display (0 means no default record).
Now, I created a dynamic menu and stored the form names in a database (due to better access control over the access rights, etc). Now, because the menu is generated at runtime, I can't have the OnClick event with separate instance definition of the form and have to create it at runtime, after the MenuItems are created. The side-effect idea was to cut the code short by using only 1 OnClick event or such with MenuItem.Tag paremeter as FormName. Something like:
Private Sub clickeventhandler(sender As Object, e As EventArgs)
Dim tsmi As ToolStripMenuItem = CType(sender, ToolStripMenuItem)
Dim newForm As New >>>FormFrom(tsmi.Tag.ToString)<<< ' only explanation, this won't work
MainW.OpenModuleInTab(new newForm, tsmi.Tag.ToString, 0)
However I am failing to find a way to create form (instances) from this string reference. Reference through collection (i.e. List(of) or Dictionary) would be fine too, I believe.
The structure is obviously:
Object → Form → Form1 (class) → MyForm1 (instance)
I know I can create an object like this:
' Note that you are getting a NEW instance of MyClassA
Dim MyInstance As Object = Activator.CreateInstance(Type.GetType(NameOfMyClass))
I can re-type it to a Form type:
Dim NewForm as Form = CType(MyInstance,Form)
... to acccess some of the form properties like Width, TopLevel, etc., but that's about it. I can't do:
Dim NewForm1 as Form1 = CType(NewForm,Form1)
...because obviously, Form1 comes as a string "Form1".
I don't know how to create a Form1 reference from a "Form1" text (then it would be easy to create an instance) or how to create an instance directly (MyForm1).
SOLUTION
As sugested, I used reflection to get the form. The only way working for me I found was this:
Dim T As Type = System.Type.GetType(FormName, False)
If T Is Nothing Then 'if not found prepend default namespace
Dim Fullname As String = Application.ProductName & "." & FormName
T = System.Type.GetType(Fullname, True, True)
End If
Dim f2 As New Form ' here I am creating a form and working with it
f2 = CType(Activator.CreateInstance(T), Form)
f2.TopLevel = False
f2.Name = FormName.Replace(" ", "") & Now.ToString("yyyyMMddmmhh")
f2.FormBorderStyle = FormBorderStyle.None
f2.Dock = DockStyle.Fill
I am using VB.net CallByName to set public variable and same function to run a sub method (every form contains RecordID variable and LoadRecords sub):
CallByName(f2, "RecordID", CallType.Set, 111)
CallByName(f2, "LoadRecords", CallType.Method, Nothing)
For testing purposes, I put following into the testing form:
Public RecordID As Int32
Public Sub LoadRecords()
MsgBox("Load records!!!!" & vbCrLf & "RecordID = " & RecordID)
End Sub
Activator.CreateInstance(TypeFromName("Form1"))
TypeFromName Function:
Dim list As Lazy(Of Type()) = New Lazy(Of Type())(Function() Assembly.GetExecutingAssembly().GetTypes())
Function TypeFromName(name As String) As Type
Return list.Value.Where(Function(t) t.Name = name).FirstOrDefault()
End Function
So, let's go with the idea that I have an assembly called "WindowsApp2" and in that assembly I've defined Form1 and Form2. I've also created this module in the same assembly:
Public Module Module1
Public Function GetDoStuffWiths() As Dictionary(Of Type, System.Delegate)
Dim DoStuffWiths As New Dictionary(Of Type, System.Delegate)()
DoStuffWiths.Add(GetType(WindowsApp2.Form1), CType(Sub(f) WindowsApp2.Module1.DoStuffWithForm1(f), Action(Of WindowsApp2.Form1)))
DoStuffWiths.Add(GetType(WindowsApp2.Form2), CType(Sub(f) WindowsApp2.Module1.DoStuffWithForm2(f), Action(Of WindowsApp2.Form2)))
Return DoStuffWiths
End Function
Public Sub DoStuffWithForm1(form1 As Form1)
form1.Text = "This is Form 1"
End Sub
Public Sub DoStuffWithForm2(form2 As Form2)
form2.Text = "This is Form 2"
End Sub
End Module
Now, in another assembly "ConsoleApp1" I write this:
Sub Main()
Dim DoStuffWiths As Dictionary(Of Type, System.Delegate) = WindowsApp2.Module1.GetDoStuffWiths()
Dim formAssembly = System.Reflection.Assembly.Load("WindowsApp2")
Dim typeOfForm = formAssembly.GetType("WindowsApp2.Form1")
Dim form As Form = CType(Activator.CreateInstance(typeOfForm), Form)
DoStuffWiths(typeOfForm).DynamicInvoke(form)
Application.Run(form)
End Sub
When I run my console app I get a form popping up with the message "This is Form 1".
If I change the line formAssembly.GetType("WindowsApp2.Form1") to formAssembly.GetType("WindowsApp2.Form2") then I get the message "Wow this is cool".
That's how you can work with strongly typed objects that you dynamically instantiate.
Dim AssemblyProduct As String = System.Reflection.Assembly.GetExecutingAssembly().GetName.Name
Dim FormName As String = "Form1"
Dim NewForm As Object = Reflection.Assembly.GetExecutingAssembly.CreateInstance(AssemblyProduct & "." & FormName)
If TypeOf (NewForm) Is Form1 Then
Dim NewForm1 As Form1 = CType(NewForm, Form1)
NewForm1.BackColor = Color.AliceBlue
NewForm1.Show()
End If

How to use a GetType and pass it to a function

why doesn't passing a datatype of an object to a function work? and how do you get around it?
Dim MyObj as new CustomObj
Dim t As Type = MyObj.GetType
Call My_Fuction(Of t)
I'm saving serializable objects to file, then open them up later on, and then the code needs to find the UI based on the object datatype, so it can populate the UI from the object
Private Function My_Fuction(Of t As Base_Object)() As UserControl
Dim UI_Type As Type = GetType(UI_Common_Panel(Of t))
For Each Object_type As Type In Project_Solution.GetTypes()
For Each Itype As Type In Object_type.GetInterfaces()
If Itype Is UI_Type Then Return DirectCast(Activator.CreateInstance(Object_type), UI_Common_Panel(Of t))
Next
Next
Return Nothing
End Function
It is difficult to give a good answer because you have all custom classes in your question. If the problem you are trying to solve is to create a new control based on the object's Type, here is a way to do that using built-in controls:
Function GetControl(o As Object) As Control
If o.GetType Is GetType(Boolean) Then
Return New CheckBox With {.Checked = DirectCast(o, Boolean)}
ElseIf o.GetType Is GetType(Date) Then
Return New DateTimePicker With {.Value = DirectCast(o, Date)}
ElseIf o.GetType Is GetType(String) Then
Return New TextBox With {.Text = DirectCast(o, String)}
Else
Return New TextBox With {.Text = o.ToString}
End If
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim c As Control = GetControl("Hello, world!")
Me.Controls.Add(c)
c.Visible = True
Dim c2 As Control = GetControl(#05/04/2017#)
Me.Controls.Add(c2)
c2.Visible = True
c2.Top = 100
End Sub

How to return specific properties of a custom vb.net object

I'm trying to generate a list of all of the TableName and FieldName properties for a custom object type called LxTextBox. I've gotten as far as generating a list of all of the LxTextBox names on my form, but I can't figure out a way to call the properties of the custom object... I've been looking into System.Reflection, but I haven't ever used it. Additionally, I'm returning the list to a RichTextBox while I'm testing this out, but ultimately, I need to return each objects properties as a data row. Example:
ObjectName Table Field
---------------------------------------
LxTextBox23 SomeTbl SomeFld
Here's my code to return the list - updated based on #OneFineDay...
Imports System.Collections.Generic
Imports Application.UDF.Controls
Public Class MeasurementsControl
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim textBoxList As New List(Of Control)
Dim customTbs = GetAllControls(Me)
Dim sb As New System.Text.StringBuilder
For index As Integer = 0 To customTbs.Count - 1
sb.Append(customTbs.Item(index).TableName & "." & customTbs.Item(Index).FieldName & System.Environment.NewLine)
Next
RichTextBox1.Text = sb.ToString
End Sub
Private Function GetAllControls(ByVal searchWithin As Control) As List(Of LxTextbox)
Dim returnList As List(Of LxTextbox) = Nothing
If searchWithin.HasChildren Then
returnList = searchWithin.Controls.OfType(Of LxTextbox).ToList
For Each ctrl As Control In searchWithin.Controls
returnList.AddRange(GetAllControls(ctrl))
Next
End If
Return returnList
End Function
End Class
I made the changes suggested and I'm throwing an error: OfType is not a member of System.Windows.Forms.Control.ControlCollection
FYI - Adding Imports System.Linq did not fix the error.
You are boxing it into a Control the object from where it derives, where you're custom properties cannot be found. You can cast it right from the control collection.
Dim customTbs = GetAllControls(Me)
'recursive function
Private Function GetAllControls(ByVal searchWithin As Control) As List(Of LxTextbox)
Dim returnList As List(Of LxTextbox) = Nothing
returnList = searchWithin.Controls.OfType(Of LxTextbox).ToList
If searchWithin.HasChildren Then
For Each ctrl As Control In searchWithin.Controls
Dim ctrls = GetAllControls(ctrl)
If Not ctrls Is Nothing Then returnList.AddRange(ctrls)
Next
End If
Return returnList
End Function

Modify a structure field containing combobox when SelectedIndex event fires

I am trying to have a generic widget composed of a label and a value. The value is set by a combobox. Here is the structure:
Structure tParam
Dim label As Label
Dim comboBox As ComboBox
Dim valueX As String
End Structure
Dim parameter1 As tParam
I'd like to modify the valueX as the SelectedIndexChanged event is fired.
For now I have set
parameter1.label.text = "Id"
parameter1.comboBox.Tag = parameter1 ' the struct itself
AddHandler parameter1.comboBox.SelectedIndexChanged, AddressOf updateParam
and in the handler
Private Sub updateParam(sender As Object, e As System.EventArgs)
Dim parameterX As tParam = sender.Tag
With parameterX
Select Case .label.Text
Case "Id"
parameter1.valueX = .comboBox.SelectedIndex
End Select
End Sub
The problem is that I have a lot (>50) parameters of type tParam and I like not to check every parameter name with the select case.
Note that I am calling directly parameter1 in the handler, because parameterX (=sender.Tag) is read-only, as any update to parameterX is local.
I cant quite tell what you are trying to do, but tStruct.ComboBox.Tag = Me seems a convoluted way to track your widgets. Using a class, you could internalize and simplify some of what it seems you are trying to do:
Public Class CBOWidgetItem
Private WithEvents myCBO As ComboBox
Private myLbl As Label
Public Property Name As String
Public Property Value As String
Public Sub New(n As String, cbo As ComboBox, lbl As Label)
Name = n
myCBO = cbo
myLbl = lbl
End Sub
Private Sub myCBO_SelectedIndexChanged(sender As Object,
e As EventArgs) Handles myCBO.SelectedIndexChanged
Value = myCBO.SelectedIndex.ToString
End Sub
Public Overrides Function ToString() As String
Return Name
End Function
End Class
The widget is able to handle the Value change itself (again, I dont quite know what you are up to). You might have other wrapper props to expose certain info the widget is managing:
Public ReadOnly Property LabelText As String
Get
If myLbl IsNot Nothing Then
Return myLbl.Text
Else
Return ""
End If
End Get
End Property
To use it:
' something to store them in:
Private widgets As List(Of CBOWidgetItem)
...
widgets = New List(Of CBOWidgetItem)
' long form
Dim temp As New CBOWidgetItem("ID", ComboBox1, Label1)
widgets.Add(temp)
' short form:
widgets.Add(New CBOWidgetItem("foo", ComboBox2, Label2))
Elsewhere if you need to find one of these guys:
Dim find = "ID"
Dim specificItem = widgets.Where(Function(s) s.Name = find).FirstOrDefault
If specificItem IsNot Nothing Then
Console.WriteLine(specificItem.Name)
End If
Alternatively, you could use a Dictionary(Of String, CBOWidgetItem) and get them back by name.