Reputation: 3
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
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