I'm attempting to move some VB6 code to .Net 2005. The following is how we dynamically create the forms in VB6:
Set frmName = Forms.Add(strFormName)
Call frmName.DisplayForm(Me, strParameter)
' .DisplayForm is a Public Sub. strParameter may or may not be populated.
Since strParameter is sometimes very important to the function of the form being opened I must keep it. What is a good way to do the above in .Net 2005?
In .Net each class is a type, so when you create a form it is inherited from base class Form, when you name it for example testForm then this is a class of its own. To create a new instance of a type from its string name you have to use reflection (you can't write: Dim x As New "testForm1"), or a Select Case with one case for each type, for simple cases with just a few cases this is easier. For example you have two forms testForm1 and testForm2, both have the DisplayForm method:
VB.NET:
Sub createformCase(ByVal name As String)
Select Case name
Case "testForm1"
Dim f As New testForm1
f.Displayform()
Case "testForm2"
Dim f As New testForm2
f.Displayform()
End Select
End Sub
"As New" is short for "Dim f As testForm1 = New testForm1"; declaring the variable, creating the instance and assigning it to the variable.
For reflection the instance created is returned as type Object, you can use late-binding to call the public method directly from this object, but no intellisense support and it's not safe coding. To access the method from the type you have to cast the object to that type. The above example you could have been written like this:
VB.NET:
Dim f As Object = New testForm1
f.DisplayForm() 'late-binding, Object type doesn't have a DisplayForm method, but this works too
DirectCast(f, testForm1).DisplayForm() 'casting and early-binding, testForm1 type have a DisplayForm method
You can't cast to a string literal that is supposed to represent a type. So you couldn't do this:
DirectCast(f, "testForm1").DisplayForm()
Here's where interfaces come to play, you should read up on that topic if it's new to you, it's basic OOP knowledge. In short, all your forms that need to have the DisplayForm method can implement an interface that serves as some kind of base type and provides access to this method, so they can all be casted to the interface type. Here an example of such interface:
VB.NET:
Interface IForm
Sub DisplayForm(Optional ByVal input As String = Nothing)
End Interface
And here a form implementing it:
VB.NET:
Public Class testForm
Implements IForm
Public Sub DisplayForm(Optional ByVal input As String = Nothing) Implements IForm.DisplayForm
If input IsNot Nothing Then
Me.Text = input 'just sets the input as form title
End If
Me.Show()
End Sub
End Class
and finally on to the reflection variant of the createform method:
VB.NET:
Sub createformReflection(ByVal name As String)
Dim f As IForm = Me.GetType.Assembly.CreateInstance(Me.GetType.Namespace & "." & name) 'implicit type casting to IForm
f.DisplayForm("testing") 'IForm type have a DisplayForm method
End Sub
from .NET 2.0 forward. There exists the My.Application.OpenForms property which returns all open forms, regardless of which thread opened them. Any time a form is opened, it is automatically added to the collection by the framework. See this article for more information: How to: Access All Open Forms of an Application.
And this: My.Application.OpenForms
I thought classic VB's Forms.Add("formname") created a new form instance from its string name. OpenForms can't do that if the instance isn't already created.
Imports System.Reflection
Public Class FormFunctions
Public Shared Function GetFormByName(ByVal FormName As String) As Form
'first try: in case the full namespace has been provided (as it should )
Dim T As Type = Type.GetType(FormName, False)
'if not found, search for it
If T Is Nothing Then T = FindType(FormName)
'if still not found, throw exception
If T Is Nothing Then Throw New Exception(FormName + " could not be found")
Return CType(Activator.CreateInstance(T), Form)
End Function
#Region "Assemblies and types"
Public Shared Function GetAllAssemblies() As ArrayList
Dim al As New ArrayList
Dim a As [Assembly] = [Assembly].GetEntryAssembly()
FillAssemblies(a, al)
Return al
End Function
Private Shared Sub FillAssemblies(ByVal a As [Assembly], ByVal al As ArrayList)
If Not al.Contains(a) Then
al.Add(a)
Dim an As AssemblyName
For Each an In a.GetReferencedAssemblies()
If Not an.Name.StartsWith("System") Then FillAssemblies([Assembly].Load(an), al)
Next
End If
End Sub
Public Shared Function GetAllTypes() As ArrayList
Dim a As [Assembly], t As Type, al As New ArrayList
For Each a In GetAllAssemblies()
For Each t In a.GetTypes
If Not al.Contains(t) Then al.Add(t)
Next
Next
Return al
End Function
Public Shared Function FindType(ByVal Name As String) As Type
Dim T As Type
For Each T In GetAllTypes()
If T.Name = Name Then Return T
Next
Return Nothing
End Function
#End Region
End Class
'example call:
Dim f As Form = FormFunctions.GetFormByName("Form1")
f.Show()
This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
By continuing to use this site, you are consenting to our use of cookies.