How to implement the "Step Wizard"

 

 

Create: /models/WizardStepViewModel.cs

using System; namespace {service}.Web.Portal.Models {     public enum WizardStepState     {         NotAccessed,         Completed,         Incomplete,         InProgress,         Inapplicable,         Summary     }     public class WizardStepViewModel     {         public string Title { get; set; }         public string Url { get; set; }         public WizardStepState State { get; set; }         public string GetUrl()         {             return State == WizardStepState.Inapplicable ||                    State == WizardStepState.NotAccessed                 ? null                 : Url;         }     } }

 

Create: /models/WizardViewModel.cs

 

using System.Collections.Generic; using System.Linq; namespace {service}.Web.Portal.Models { public class WizardViewModel { public WizardViewModel() { WizardSteps = new List<WizardStepViewModel>(); } public ICollection<WizardStepViewModel> WizardSteps { get; set; } public int Count => WizardSteps.Count; public int? LastCompletedIndex => WizardSteps.Reverse() .Select((x,i) => new {State = x.State, Index = Count - i - 1}) .FirstOrDefault(x=>x.State == WizardStepState.Completed) ?.Index; public int? InProgressIndex => WizardSteps.Reverse() .Select((x, i) => new { State = x.State, Index = Count - i - 1}) .FirstOrDefault(x => x.State == WizardStepState.InProgress) ?.Index; } }

Create: /views/shared/wizard.cshtml

 

@using {service}.Web.Portal.Models @model {service}.Web.Portal.Models.WizardViewModel <!--From: https://bootsnipp.com/user/snippets/aRlN3 --> @functions { int CalculateConnectingLineWidth(WizardViewModel wizard) { int[] lineMap = { -1, -1, 48, 69, 79, 80, 80, 84, 84, 91, 91 }; return wizard.Count <= 10 ? lineMap[Model.WizardSteps.Count] : 100; } int CalculateCompletionLineStartingPosition(WizardViewModel wizard) { int[] lineMap = { -1, -1, 27, 15, 11, 9, 9, 9, 8, 7, 7 }; return wizard.Count <= 10 ? lineMap[Model.WizardSteps.Count] : 178; } int CalculateCompletionLineWidth(WizardViewModel wizard) { var inProgressIndex = wizard.InProgressIndex; var lastCompletedIndex = wizard.LastCompletedIndex; if (!inProgressIndex.HasValue && !lastCompletedIndex.HasValue) { return 0; } // in case the inProgress index hasn't been defined, use the lastCompleted index int index = inProgressIndex.HasValue ? inProgressIndex.Value : lastCompletedIndex.GetValueOrDefault(); if (index == 0) { return 0; } int fullWidth = CalculateConnectingLineWidth(wizard); int singleWidth = fullWidth / (wizard.Count - 1); return singleWidth * index; } } <style> @@media screen and ( max-width : 585px ) { .app-name-submenu { font-size: 25px; } } .wizard .nav-tabs > li { width: @(100 / Model.WizardSteps.Count)%; } .connecting-line { width: @CalculateConnectingLineWidth(Model)%; } .completion-line { width: @CalculateCompletionLineWidth(Model)%; left: @CalculateCompletionLineStartingPosition(Model)%; } </style> <div class="row"> <section> <div class="wizard"> <div class="wizard-inner"> <div class="completion-line"></div> <div class="connecting-line"></div> <ul class="nav nav-tabs"> @{ int counter = 1; } @foreach (var wizardStep in Model.WizardSteps) { <li role="presentation" class="@(wizardStep.State == WizardStepState.InProgress ? "active": "")@(wizardStep.State == WizardStepState.Completed ? "completed": "")"> <p class="step-label-top">Step @counter</p> <a @Html.Raw(wizardStep.GetUrl() != null ? string.Format("href=\"{0}\"", wizardStep.GetUrl()) : "") aria-label="step@count"> <span class="round-tab@(wizardStep.GetUrl()==null?"":" pointer")"> @if (counter != Model.Count) { switch (wizardStep.State) { case WizardStepState.NotAccessed: <i class="fa fa-file-text"></i> break; case WizardStepState.Completed: <i class="fa fa-check fa-lg"></i> break; case WizardStepState.Incomplete: <i class="fa fa-exclamation-triangle fa-lg"></i> break; case WizardStepState.InProgress: <i class="fa fa-file-text fa-lg bg-white"></i> break; case WizardStepState.Inapplicable: <i class="fa fa-minus fa-lg"></i> break; case WizardStepState.Summary: <i class="fa fa-print fa-lg"></i> break; default: throw new ArgumentOutOfRangeException(); } } else { <i class="fa fa-paper-plane fa-lg"></i> } </span> </a> <div style="width:100%"> <div class="step-label-bottom">@wizardStep.Title</div> </div> </li> counter++; } </ul> </div> </div> </section> </div>

 

Create: /content/css/wizard.css

 

 

Edit: /App_Start/BundleConfig.cs

Paste:

 

 

Edit your base controller and add:

 

 

Find the BaseModel for the Step’s view model:

Add the following property to the BaseModel:

 

Edit each affected page controller method

(e.g. public ActionResult Step1Page(int id))

Locate the viewmodel, and add:

Edit each affected view(cshtml)

Paste:

 

Edit _Layout{service}.cshtml

Output the stylesheet:

 

Render the Wizard, e.g.