Search code examples
.netvb.netwinforms.net-core.net-assembly

Best practices on load a form inside a main form, both residing in an external DLL assembly


I've loaded an external DLL into your project like this

Dim assembly As Assembly = Assembly.LoadFile(libraryPath & "filename.dll")
Dim type As Type = assembly.[GetType]("NameSpace.ClassName")

// i'm loading as a form here but can be any control
Dim frm As Form = TryCast(Activator.CreateInstance(type), Form)

What are the best practices if you're loading a class or a control inside the loaded form (above) that resides also inside the same assembly ?

for instance: Lets say you loaded an assembly consisted of several forms. You load the assembly and create the instance of one of the forms, frm. But inside the loaded form, frm is also loaded another 2nd form, frm2 also belonging to the same assembly. How do i instantiate the second form? do i need to load the assembly again ?

Edit: The assembly is a. Net 4.8 class library, that holds several forms, modules and abstract classes. Is being loaded into a winforms also in. Net 4.8. This question applies to both VB and C#. But on my case I'm coding on VB.


Solution

  • You can load your external assembly in the StartUp event of your application.
    Open Project->Properties->Application and click the View Application Events button.
    This will open or generate the ApplicationEvents.vb class file (you'll see, in some comments, the events that are more often handled using the My.Application class).

    Here, we add a handler to the StartUp event: this event is raised before the application startup form is loaded and shown.
    We define a Public class object that references the external Library containing the Form resources.
    This public class object is visible by all other classes in the Application, through the My.Application reference.
    This class exposes a Public Method, LoadForm(), that allows to load an external Form by Name.

    Imports System.IO
    Imports System.Reflection
    Imports Microsoft.VisualBasic.ApplicationServices
    
    Namespace My
        Partial Friend Class MyApplication
    
            Public FormResources As ResourceBag
    
            Protected Overrides Function OnStartup(e As StartupEventArgs) As Boolean
                FormResources = New ResourceBag()
                Return MyBase.OnStartup(e)
            End Function
    
            Friend Class ResourceBag
                Private Shared libraryPath As String = "[Your Library path]"
                Private Shared asm As Assembly = Nothing
                Public Sub New()
                    Dim resoursePath As String = Path.Combine(libraryPath, "[Your .dll Name].dll")
                    If File.Exists(resoursePath) Then
                        asm = Assembly.LoadFile(resoursePath)
                    End If
                End Sub
    
                Public Function LoadForm(formName As String) As Form
                    If asm Is Nothing Then Throw New BadImageFormatException("Resource Library not loaded")
                    Return TryCast(Activator.CreateInstance(asm.GetType($"[Library Namespace].{formName}")), Form)
                End Function
            End Class
        End Class
    End Namespace
    

    Now, let's assume you have a Form named Form1 in your external library.
    You can make Form1 load another Form from the external Library or a Form from your assembly using either the LoadForm() method (it creates an instance of a Form in the external library) or the New keyword to create an instance of local Form class.

    ► If Form1 of the external Library already shows another Form from the same Library, e.g., clicking a Button, there's nothing we have to do: the external new Form is generated as usual.

    In the sample code that follows, we are instead adding two Buttons to the external Form1 class:

    • One Button loads a Form, Form2, from the external library, using the public method previously defined: Using extForm1 As Form = My.Application.FormResources.LoadForm("Form1")
    • The other Button loads a Form also named Form2, which is instead part of the current Application, using the New keyword: Dim f2 As New Form2()

    ► The external Form1 instance is created with a Using statement because the ShowDialog() method is used to show the new Form: this requires that we dispose of the Form when it closes, otherwise it cannot dispose of itself when show like this.
    If you use Show() or Show(Me), the Using block needs to be removed otherwise the Form will be closed instantly. The Form and its Controls/components will be disposed of when it closes anyway.

    ► The Form2 Form class of your Application cannot have Controls added from the Application Settings (these Control will be disposed of and generate an exception if the Form is shown a second time)


    Using extForm1 As Form = My.Application.FormResources.LoadForm("Form1")
        If extForm1 IsNot Nothing Then
            Dim btnExt = New Button() With {
                .Location = New Point(20, 50),
                .Size = New Size(100, 30),
                .Text = "Lib Form2"
            }
            AddHandler btnExt.Click,
                Sub()
                    Dim f2ext = My.Application.FormResources.LoadForm("Form2")
                    f2ext.Show()
                End Sub
    
            Dim btn = New Button() With {
                .Location = New Point(140, 50),
                .Size = New Size(100, 30),
                .Text = "My Form2"
            }
            AddHandler btn.Click,
                Sub()
                    Dim f2 As New Form2()
                    f2.Show()
                End Sub
    
            extForm1.Controls.AddRange({btnExt, btn})
            btnExt.BringToFront()
            btn.BringToFront()
            extForm1.StartPosition = FormStartPosition.CenterParent
            extForm1.ShowDialog(Me)
        End If
    End Using