字符串表单名称以形成引用

时间:2017-11-16 07:42:47

标签: vb.net winforms

基本上,我正在重写一些工作多年的代码。随着时间的推移,我有很多(60+)个表单引用 - 每个表单都有一个带有OnClick事件的menuitem,其中创建了一个表单引用:

Private Sub SomeForm_Click(sender As Object, e As EventArgs) Handles MenuItemForSomeForm.Click
    NewTab("Some Form", New SomeForm, 0)
End Sub

...其中第一个参数是放在表单打开的tabPage.Text中的名称,第二个是(特定)表单的新实例SomeForm和0是要显示的默认记录(0表示没有默认值记录)。

现在,我创建了一个动态菜单,并将表单名称存储在数据库中(由于对访问权限的更好的访问控制等)。现在,因为菜单是在运行时生成的,所以我不能让OnClick事件具有单独的表单实例定义,并且必须在创建MenuItem之后在运行时创建它。副作用的想法是通过仅使用1个OnClick事件或者使用MenuItem.Tag参数作为FormName来缩短代码。类似的东西:

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)

但是我没能找到从这个字符串引用创建表单(实例)的方法。我相信通过集合(即List(of)或Dictionary)也可以参考。

结构显然是:

对象→表格→表格1(班级)→MyForm1(实例)

我知道我可以创建像this这样的对象:

' Note that you are getting a NEW instance of MyClassA
Dim MyInstance As Object = Activator.CreateInstance(Type.GetType(NameOfMyClass))

我可以将其重新键入Form类型:

Dim NewForm as Form = CType(MyInstance,Form)

...来处理一些表格属性,如Width,TopLevel等,但这就是它。我不能这样做:

Dim NewForm1 as Form1 = CType(NewForm,Form1)

...因为很明显,Form1是一个字符串“Form1”。

我不知道如何从“Form1”文本创建Form1引用(然后创建实例很容易)或如何直接创建实例(MyForm1)。

随着时间的推移,我用反射来获取表格。我找到的唯一方法就是:

    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

我使用VB.net CallByName来设置公共变量和相同的函数来运行一个子方法(每个表单包含RecordID变量和LoadRecords子):

    CallByName(f2, "RecordID", CallType.Set, 111)
    CallByName(f2, "LoadRecords", CallType.Method, Nothing)

出于测试目的,我将以下内容放入测试表单中:

Public RecordID As Int32
Public Sub LoadRecords()
    MsgBox("Load records!!!!" & vbCrLf & "RecordID = " & RecordID)
End Sub

3 个答案:

答案 0 :(得分:1)

Activator.CreateInstance(TypeFromName("Form1"))

TypeFromName功能:

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

答案 1 :(得分:0)

所以,我们假设我有一个名为“WindowsApp2”的程序集,在该程序集中我定义了Form1Form2。我也在同一个程序集中创建了这个模块:

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

现在,在另一个程序集“ConsoleApp1”中,我写了这个:

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

当我运行我的控制台应用程序时,我会弹出一个表单,其中包含"This is Form 1"消息。

如果我将行formAssembly.GetType("WindowsApp2.Form1")更改为formAssembly.GetType("WindowsApp2.Form2"),则会收到消息"Wow this is cool"

这就是你如何使用动态实例化的强类型对象。

答案 2 :(得分:-1)

    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