I can easily list all controls in a Form, after creating an instance of it.
Is there any mechanism to list all declared variables or such objects?
Perhaps I shall call it declarations. Only top-level declarations are enough.
Let's assume we have MyForm
Form with such top-level declarations:
Dim Town as String
Dim ZIP as String
Dim StreetName as String
Dim StreetNo as String
Public dtCountries as DataTable
Public LstCities as List(Of String)
...
Pseudo-code example:
Dim MyForm as New MyForm ' create instance of the form
Dim dtVariables as New Datatable ' create a datatable to store found objects
dtVariables.Columns.Add("ID", GetTy(Int32))
dtVariables.Columns.Add("VariableName", GetTy(String))
dtVariables.Columns.Add("VariableType", GetTy(String))
For Each Varbl In MyForm.***variables*** ' <<< (how) to read all variables
Dim nr as Datarow = dtVariables.NewRow
nr("ID") = dtVariables.Rows.Count + 1
nr("VariableName") = Varbl.Name
nr("VariableType") = Varbl.GetType.ToString.Replace("System.Windows.Forms.", "")
dtVariables.Rows.Add(nr) ' add found object/variable to our datatable
Next
The result I am looking for is something like:
1 Town String
2 ZIP String
3 StreetName String
4 StreetNo Int32
5 dtCountries DataTable
6 LstCities List(Of String)
... ... ...
I know that I can read MyForm.designer.vb
file and look there for declarations.
This question is about getting it from an object model of a Form / instance of a Form.
An example using a filtered collection of FieldInfo objects returned by Type.GetType().GetFields()
Since you want this method to return both Public and non-Public Fields, the collection must be filtered because, since this is a Form class, it will include all the controls a Form contains.
The collection of FieldInfo
is then filtered using FieldType.Namespace
, where the Namespace
is not System.Windows.Forms
.
The BindingFlags are set to Instance | Public | NonPublic | DeclaredOnly
.
When the Field represents a Collection (List, Dictionary etc.), the Type.GenericTypeArguments property needs to be parsed to extract the arguments Collection.
I'm using a couple of helper functions to clean up the Fields Name and to retrieve the collection of arguments as a formatted string.
Using the sample Fields you posted (I added a Dictionary to test the output):
Dim Town As String
Dim ZIP As String
Dim StreetName As String
Dim StreetNo As String
Public dtCountries As DataTable
Public LstCities As List(Of String)
Public DictOfControls As Dictionary(Of String, Control)
this is the result:
Dim ClassFields As New DataTable
ClassFields.Columns.Add("ID", GetType(Integer))
ClassFields.Columns.Add("Name", GetType(String))
ClassFields.Columns.Add("FieldType", GetType(String))
Dim flags As BindingFlags = BindingFlags.Instance Or
BindingFlags.Public Or BindingFlags.NonPublic Or BindingFlags.DeclaredOnly
Dim allFields As List(Of FieldInfo) =
Me.GetType().GetFields(flags).
Where(Function(f) (Not (f.FieldType.Namespace.Equals("System.Windows.Forms"))) AndAlso f.Name <> "components").
ToList()
For Each field As FieldInfo In allFields
Dim dr As DataRow = ClassFields.NewRow
dr("ID") = ClassFields.Rows.Count + 1
dr("Name") = field.Name
dr("FieldType") = GetFieldTypeName(field.FieldType.Name) &
GetTypeArguments(field.FieldType.GenericTypeArguments)
ClassFields.Rows.Add(dr)
Next
Private Function GetFieldTypeName(field As String) As String
Dim EndPosition As Integer = field.IndexOf(ChrW(96))
Return If(EndPosition > 0, field.Substring(0, EndPosition), field)
End Function
Private Function GetTypeArguments(args As Type()) As String
If args.Length = 0 Then Return String.Empty
Return $" ({String.Join(", ", args.Select(Function(arg) arg.Name))})"
End Function
If Interpolated String is not available (before VB.Net version 14), use a Composite Format string:
Return $" ({String.Join(", ", args.Select(Function(arg) arg.Name))})"
can be expressed as:
Return String.Format(" ({0})", String.Join(", ", args.Select(Function(arg) arg.Name)))