Introduction
We might have seen a lot of wizards which we come across, with Back, Next, Cancel Buttons. It tends to be tedious if we design seperate forms for each of the wizard step with a seperate copy of buttons in each form. Hence I decided to create a basic template (parent form) that will load a form (of the wizard step) based on the user's click on Back or Next Buttons. An added advantage in the layout is that, the back and next buttons become disabled automatically, based on the form that is loaded.
Using the code
Let me tell you about some variables that I'll be using to change the forms.
Variable |
Purpose |
int top |
The index of the current form that is in use. |
int count |
The total count of forms, which we are going to use in the wizard. |
Form[] frm |
The array collection of forms used in the wizard |
Let us assume the case of a stack. A stack has a top
variable that corresponds to the current element of the stack. The top
variable is kept changing based on the event. (i.e.) it is increased for the next element (Next) and decreased for the previous element (Back).
Let us assume that the stack takes up a value, top = -1
to show that there are no more forms that can be moved back (underflow condition). If top = count
then there are no more forms that can be moved next (overflow condition). We will be implementing the same concept, but we'll be working with forms.
Follow the following steps,
Designing the Parent Form
- Create a new Windows Forms project.
- Add a form. Name this as
frmParent
. This will be our parent (host) form.
- Add three panels (based on your content) to the form and name them,
pnlLeft
, pnlContent
, pnlNavigation
and set their dock properties to Left, Fill, Bottom
(respectively).
- We will be using
pnlLeft
to display the logo, pnlContent
to change the forms and pnlNavigation
for the navigation buttons.
Now the layout of the Parent Form should look like this,
- Use appropriate controls to design the basic layout of the form. I have used a picture box to display the logo of the wizard. I've added a
TableLayoutPanel
in the pnlNavigation
, that holds the three buttons (namely Back, Next and Cancel).
- Add the buttons, and name them
btnBack
, btnNext
, btnCancel
.
- I've added required padding to achieve the look and feel. You may try this based on your layout design.
The output would be similar to,
Designing the Child Forms
You can create as many as child forms as much as you want in the wizard. But make sure that every child form that you design have the following properties,
Property |
Value |
FormBorderStyle |
None |
AutoScroll |
True |
|
|
Design the child forms based on your requirement, from the starting form to the ending form. For this demonstration, I am designing three forms, namely frm1
, frm2
, frm3
. In this case frm1
will act as the first form and frm3
acts as the final form.
I've attached a sample of the first form (frm1
) in here. The FormBorderStyle has been set to none and the AutoScroll Property has been turned on. I've also applied necessary padding, and tweaked other properties to get the look of the form.
Coding
Initially, I'll have to initialize the Form
array with the forms I am going to use in the wizard. The code must be placed in the parent form before the constructor.
Form[] frm = { new frm1(), new frm2(), new frm3() };
int top = -1;
int count;
Now in the constructor of the parent form, we have to initialize the count
variable.
public frmParent()
{
count = frm.Count();
InitializeComponent();
}
I'm creating a function that will load a currently set form into the panel (pnlContent
) of the main form. I'll call it LoadNewForm()
. This function will be called thrice,
- During the loading of the parent form (first time, first form must be shown)
- During the click of the Back Button (previous form must be loaded)
- During the click of the Next Button (next form must be loaded).
It will look similar to this,
frm[top].TopLevel = false;
frm[top].Dock = DockStyle.Fill;
this.pnlContent.Controls.Clear();
this.pnlContent.Controls.Add(frm[top]);
frm[top].Show();
The function, makes the child form, to act as a child form (using TopLevel
property), fills the form as a content in the panel of the Parent Form (using DockStyle.Fill
), clears all content in the panel for fresh loading of the form (pnlContent.Controls.Clear()
), adds the current form (top
) into the panel and displays the form in the panel.
To understand this piece of code, you can refer to this question posted in Codeproject, http://www.codeproject.com/Questions/414107/Csharp-Form-inside-a-Panel
Moving to the next form
The following must happen if the next button is clicked,
- The variable
top
must be incremented.
- If value of
top
exceeds or equals, the total count of forms, then do nothing (return
).
- Otherwise,
Load
the current form into the panel and check if the current form is the last form of the list. If yes, then disable the next button.
- If there is no more forms available (i.e.
top == -1
) then disable the Back button.
The code will look like,
private void Next()
{
top++;
if (top >= count)
{
return;
}
else
{
btnBack.Enabled = true;
btnNext.Enabled = true;
LoadNewForm();
if (top + 1 == count)
{
btnNext.Enabled = false;
}
}
if (top <= 0)
{
btnBack.Enabled = false;
}
}
Call Next()
during the Form Load
and as well as when the next button
is clicked.
Moving to the previous form
Moving to the previous form is the exact opposite of Moving to the next form. Hence the code will be as follows,
private void Back()
{
top--;
if (top <= -1)
{
return;
}
else
{
btnBack.Enabled = true;
btnNext.Enabled = true;
LoadNewForm();
if (top - 1 <= -1)
{
btnBack.Enabled = false;
}
}
if (top >= count)
{
btnNext.Enabled = false;
}
}
Call Back()
when back button
is clicked.
Voila. That's it. The entire code will look like,
public partial class frmParent : Form
{
Form[] frm = { new frm1(), new frm2(), new frm3(), new frm4(),
new frm5()};
int top = -1;
int count = 5;
public frmParent()
{
InitializeComponent();
}
private void LoadForm()
{
frm[top].TopLevel = false;
frm[top].AutoScroll = true;
frm[top].Dock = DockStyle.Fill;
this.pnlContent.Controls.Clear();
this.pnlContent.Controls.Add(frm[top]);
frm[top].Show();
}
private void Back()
{
top--;
if(top <= -1)
{
return;
}
else
{
btnBack.Enabled = true;
btnNext.Enabled = true;
LoadForm();
if (top - 1 <= -1)
{
btnBack.Enabled = false;
}
}
if(top>=count)
{
btnNext.Enabled = false;
}
}
private void Next()
{
top++;
if (top >= count)
{
return;
}
else
{
btnBack.Enabled = true;
btnNext.Enabled = true;
LoadForm();
if(top+1 == count)
{
btnNext.Enabled = false;
}
}
if (top <= 0)
{
btnBack.Enabled = false;
}
}
private void frmParent_Load(object sender, EventArgs e)
{
Next();
}
private void btnNext_Click(object sender, EventArgs e)
{
Next();
}
private void btnBack_Click(object sender, EventArgs e)
{
Back();
}
}
I've applied Docking for certain components. So they can adapt even if you resize the application, or maximize it. The cancel button can also be renamed to "Finish" Button depending on the flavour of the design.
History
Version 1 : Current Version