Introduction
Whether you are new to development, or coming from Visual Basic, C++, Java, or Delphi, managing forms in a WinForms can be initially confusing. This is an article targeted at those who are new to WinForms to demonstrate how to easily manage and work with forms in a WinForms application.
Non Modal
A non modal form is a form that is opened, but allows other windows to be focused while the window is open. This allows a user to work with more than one form at a time.
Pattern
The basic pattern to open a non modal form is as follows:
C#
private void button1_Click(object sender, System.EventArgs e) {
Form2 xForm = new Form2();
xForm.Show();
}
Visual Basic
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim xForm As Form2
xForm = New Form2
xForm.Show()
End Sub
The Show
method will return after the form is displayed and the next code to execute depends on the users action on the New
, or any other currently open form that the user may choose.
Disposal
When a non modal form is closed, the Dispose
will automatically be called by WinForms. This can be seen by setting a break point in the Dispose
method (C#) and then closing the form. Because of this, there is no need to call Dispose
from the code that created this form.
Modal
Modal, or dialog style forms prevent the user from removing the focus from the form. The user must either open another form, or close the form. Forms opened before the modal form cannot be accessed by the user.
Pattern
C#
private void button2_Click(object sender, System.EventArgs e) {
using (Form2 xForm = new Form2()) {
xForm.ShowDialog(this);
}
}
Visual Basic
Private Sub Button2_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button2.Click
Dim xForm As Form2
xForm = New Form2
Try
xForm.ShowDialog(Me)
Finally
xForm.Dispose()
End Try
End Sub
The ShowDialog
method functions differently than the Show
method. ShowDialog
blocks execution until the form has been closed. Because of this, the Dispose
can follow the ShowDialog
call immediately as it will not be called until the form has been closed. If the Dispose
call was made immediately after a Show
method, the form would simply flash on the screen as it would be shown, and then immediately be disposed of after it was shown.
Disposal
WinForms does not automatically call the Dispose
method when a user closes a modal form. Because of this, the Dispose
is explicitly called. In Visual Basic this is done by calling the Dispose
method directly, while in C# the using
construct is used.
Returning a Result
The ShowDialog
method also differs from the Show
method in that it offers a return value. The result can be used to determine how the user closed the form. To do this, the event code can either set the return value, or more simply the DialogResult
property of buttons can be used.
To see this in action, drop two buttons on a modal form. Now set the DialogResult
property of one to OK, and the other to Cancel. This will cause the buttons to close the form, and return the specified value as the return value of ShowDialog
.
The pattern can then be modified as shown:
C#
private void button2_Click(object sender, System.EventArgs e) {
using (Form2 xForm = new Form2()) {
if (xForm.ShowDialog(this) == DialogResult.OK) {
}
}
}
Visual Basic
Private Sub Button2_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button2.Click
Dim xForm As Form2
xForm = New Form2
Try
If xForm.ShowDialog(Me) = DialogResult.OK Then
End If
Finally
xForm.Dispose()
End Try
End Sub
Passing Data
Passing data into a form can easily be done by creating public methods, members, or properties and accessing them before the form is shown.
As an example, imagine that the following is declared in the second form:
C#
public void SetValue(string aValue) {
button1.Text = aValue;
}
Visual Basic
Public Sub SetValue(ByVal aValue As String)
button1.Text = aValue
End Sub
This method can then be called from the calling code:
C#
private void button1_Click(object sender, System.EventArgs e) {
Form2 xForm = new Form2();
xForm.SetValue("Test");
xForm.Show();
}
Visual Basic
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim xForm As Form2
xForm = New Form2
xForm.SetValue("Test")
xForm.Show()
End Sub
This example is shown using the Show
method, but can also be used with ShowDialog
.
This same method can be used to retrieve data from a modal form, by calling methods, or accessing members or properties after the ShowDialog
has returned, but before the Dispose
has been called. In fact, this is why WinForms does not auto dispose modal forms.
An example might be as follows:
C#
private void button2_Click(object sender, System.EventArgs e) {
using (Form2 xForm = new Form2()) {
if (xForm.ShowDialog(this) == DialogResult.OK) {
_Value = xForm.GetValue();
}
}
}
Visual Basic
Private Sub Button2_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button2.Click
Dim xForm As Form2
xForm = New Form2
Try
If xForm.ShowDialog(Me) = DialogResult.OK Then
_Value = xForm.GetValue()
End If
Finally
xForm.Dispose()
End Try
End Sub
where GetValue
is a function of your own definition.
Static Show
If a form is always shown and certain arguments are required, the process can be encapsulated into a static
method of the form class. Assuming the previous example of SetValue
is a requirement, and even returning a result, it can be added to the Form2
class as follows:
C#
public static string Display(string aValue) {
using (Form2 xForm = new Form2()) {
xForm.SetValue("Test");
if (xForm.ShowDialog() == DialogResult.OK) {
return GetValue();
}
else {
return "";
}
}
}
Visual Basic
Public Shared Function Display(ByVal aValue As String) As String
Dim xForm As Form2
xForm = New Form2
Try
xForm.SetValue(aValue)
If xForm.ShowDialog() = xForm.DialogResult.OK Then
Return GetValue()
Else
Return ""
End If
Finally
xForm.Dispose()
End Try
End Function
The SetValue
method should also be declared as private
instead of public
to protect it from outside use.
To show the form, the calling code appears as follows:
C#
private void button1_Click(object sender, System.EventArgs e) {
_Value = Form2.Display("Test");
}
Visual Basic
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
_Value = Form2.Display("Test")
End Sub
This of course can be done without returning a result as well, by simply changing the method type to void
(C#), or type Sub
(Visual Basic). In this example I have also changed it to use Show
, simply as a variation.
C#
public static void Display(string aValue) {
Form2 xForm = new Form2();
xForm.SetValue("Test");
xForm.Show();
}
Visual Basic
Public Shared Sub Display(ByVal aValue As String) As String
Dim xForm As Form2
xForm = New Form2
xForm.SetValue(aValue)
xForm.Show()
End Sub
Keeping a reference
Often it is useful to store a reference to a form for later use. Your application may need to update the form from another event, re-show the form, hide the form, etc. .NET does not support Globals, which many of us have formerly used for this purpose. However static
form members can be used for this purpose.
In Form2
, simply declare the following member:
C#
public static Form2 Form2Ref;
Visual Basic
Public Shared Form2Ref As Form2
This variable can then be used to store a reference to an instance of the form. To reference it again later, for example to re-show the form or refocus it, the following code can be used:
C#
Form2.Form2Ref.Show();
Visual Basic
Form2.Form2Ref.Show()