Khalid Kagzi
Khalid Kagzi

Reputation: 3

VB.NET 2019 Open a form from another form

I know this appears to be a rather common topic and should have been resolved from earlier posts. But what I am experiencing still does not seem to have a solution online: I have a form called ExpenseEntry in which there is a sub procedure called Public Sub OpenVoucher. I want to call this sub from another form for which I use the following code:

        Dim ExpForm As New ExpenseEntry
         ExpForm.Show()
        ExpForm.OpenVoucher()

While this works well enough, the problem is everytime I click the button, a new window of ExpenseEntry is launched. As per how I have designed the application, repeat windows is not permissible and only one window should be available at a time. I have tried various methods to restrict more than one form such as by using a variable to control the form but that gives rise to other issues. If I use Application.OpenForms but still does not resolve the issue. I have earlier queried in this regard in the following link: Textbox not refreshing

I am using VB.NET 2019 which does not allow the launch of default instance of a form like Form.Show. I know this is bad practice but it was easier to manage with that till VB.NET 2017.

Now by creating a form variable and launching that creates an infinite loop where I cannot have just one instance of a form running on a single thread.

Upvotes: 0

Views: 2001

Answers (1)

jmcilhinney
jmcilhinney

Reputation: 54467

The really simple way to handle this is to use the default instance of the form type. In VB, since 2005, each form type has a default instance that you can access via the type name. Read here for more info. In your case, you can do this:

'Display the form if it is not already displayed.
ExpenseEntry.Show()

'Activate the form if it is already displayed.
ExpenseEntry.Activate()

'Do the deed.
ExpenseEntry.OpenVouncher()

That said, default instances are a bit dodgy. They do enable beginners to access forms from anywhere in their project under certain circumstances but they also have limitations that can cause issues. Most importantly though, they help to prevent you learning proper OOP by treating forms differently to other types. If you want to do this the way a proper developer would then simply declare a variable to refer to the current instance of the form:

Private expenseEntryDialogue As ExpenseEntry

When it's time to use the form, you simply check whether that variable refers to a usable instance and use it if it does, otherwise create a new one:

If expenseEntryDialogue Is Nothing OrElse expenseEntryDialogue.IsDisposed Then
    expenseEntryDialogue = New ExpenseEntry
End If

expenseEntryDialogue.Show()
expenseEntryDialogue.Activate()
expenseEntryDialogue.OpenVoucher()

A third option would be to implement your own singleton, i.e. a type that can only ever have a single instance. You probably wouldn't do that in VB, given that the default instance is basically a thread-specific singleton and does more automatically but, if you wanted to, you could do this:

Public Class ExpenseEntry

    Private Shared _instance As ExpenseEntry

    'The one and only instance of the type.
    Public Shared ReadOnly Property Instance As ExpenseEntry
        Get
            If _instance Is Nothing OrElse _instance.IsDisposed Then
                _instance = New ExpenseEntry
            End If

            Return _instance
        End Get
    End Property

    'The constructor is private to prevent external instantiation.
    Private Sub New()
        ' This call is required by the designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.
    End Sub

End Class

and then this:

ExpenseEntry.Instance.Show()
ExpenseEntry.Instance.Activate()
ExpenseEntry.Instance.OpenVoucher()

Upvotes: 1

Related Questions