Styling the ASP.NET Wizard Control to have the Steps Across the top
The default style of the ASP.NET Wizard control is not the best. For the sidebar to work, and display all the wizard steps in a wizard requires quite a bit of space. And in all the wizards we end up creating, we don't want the user to jump from one step to the next using the sidebar. We make the user click from step to step linearly.
We've spent a little time lately changing the way the wizard looks and have come up with the following look and feel.
The top HeaderTemplate contains the current step the user is on (derived from the WizardStep Title) and an indication of the total number of step (we use three different classes in indicate the current step, completed step and incomplete step). The "steps" also have tooltips added to let the user know what steps are coming. (See image below)
The WizardStep in the image above is all the information regarding "Billing and Shipping" details (this is just standard Wizard Step stuff)
How its done
The markup for the wizard aspx code is as follows:
<asp:Wizard ID="wzd" runat="Server" Width="100%" DisplaySideBar="false"> <HeaderTemplate> <table style="width: 100%" cellpadding="0" cellspacing="0"> <tr> <td class="wizardTitle"> <%= wzd.ActiveStep.Title%> </td> <td> <table style="width: 100%; border-collapse: collapse;"> <tr> <td style="text-align: right"> <span class="wizardProgress">Steps:</span> </td> <asp:Repeater ID="SideBarList" runat="server"> <ItemTemplate> <td class="stepBreak"> </td> <td class="<%# GetClassForWizardStep(Container.DataItem) %>" title="<%# DataBinder.Eval(Container, "DataItem.Name")%>"> <%# wzd.WizardSteps.IndexOf(Container.DataItem as WizardStep) + 1 %> </td> </ItemTemplate> </asp:Repeater> </tr> </table> </td> </tr> </table> </HeaderTemplate> <SideBarTemplate> </SideBarTemplate> <WizardSteps> ... removed... </WizardSteps>
</asp:Wizard>
We add the following event handler to Page_Load in our code-behind
protected void Page_Load(object sender, EventArgs e) { wzd.PreRender += new EventHandler(wzd_PreRender); }
And have the following methods in the code-behind
protected void wzd_PreRender(object sender, EventArgs e) { Repeater SideBarList = wzd.FindControl("HeaderContainer").FindControl("SideBarList") as Repeater; SideBarList.DataSource = wzd.WizardSteps; SideBarList.DataBind(); } public string GetClassForWizardStep(object wizardStep) { WizardStep step = wizardStep as WizardStep; if (step == null) { return ""; } int stepIndex = wzd.WizardSteps.IndexOf(step); if (stepIndex < wzd.ActiveStepIndex) { return "stepCompleted"; } else if (stepIndex > wzd.ActiveStepIndex) { return "stepNotCompleted"; } else { return "stepCurrent"; } }
Explanation of the code above
When the wizard goes into PreRender, we bind the collection of WizardSteps to the Repeater in our HeaderTemplate
The "GetClassForWizardStep" is a helper method we have to determine what wizard step we're on, and render the appropriate class in the table cell.
Style Sheet Rules
The rules I'm using above to generate the page are as below...
/* WIZARD */ .stepNotCompleted { background-color: rgb(153,153,153); width: 15px; border: 1px solid rgb(153,153,153); margin-right: 5px; color: White; font-family: Arial; font-size: 12px; text-align: center; } .stepCompleted { background-color: #4d4d4d; width: 15px; border: 1px solid #4d4d4d; color: White; font-family: Arial; font-size: 12px; text-align: center; } .stepCurrent { background-color: #e01122; width: 15px; border: 1px solid #e01122; color: White; font-family: Arial; font-size: 12px; font-weight: bold; text-align: center; } .stepBreak { width: 3px; background-color: Transparent; } .wizardProgress { padding-right: 10px; font-family: Arial; color: #333333; font-size: 12px; } .wizardTitle { font-family: Arial; font-size: 120%; font-weight: bold; color: #333333; vertical-align: middle;