I’m working on team, updating a commercial web app in C#. We’re using Telerik’s RadControls. The application guides the user through a set of tasks in a wizard-like fashion, but also allows the user to jump back to previous steps and make modifications. Additionally, some steps have complex validation methods. For example, once you complete a task on step 5, steps 7, 8, and 9 become available. Also, if you change any settings on step 2, everything after that point has to be re-done, so all steps after step 3 must be disabled.
- There is a navigation bar on the left side of the screen (a Telerik
RadPanel) that lists all of the steps in sequential order. Depending
on where you are at in the process, some steps are available to the
user, and some are disabled. - There is a drop-down box at the top of the page (a Telerik
SplitButton on a RadToolBar) that also contains all of the steps - There are forward and backward buttons that let you move to the next
or previous step in the process.
Each of the “steps” have their own Page, so clicking on a link to “Step 1” will take you to step1.aspx
The navigation code is strewn all over the master page. There are methods that handle the step-enabling logic that are basically massive switch statements on the navigation panel’s selected index. I want to re-write all of this functionality and put it into one “NavigationManager” class that has a reference to all of the necessary controls (although I’m open to suggestions on that). I’m looking for a solution that will:
- Know where the user is in the process, and where the user is allowed to go so that it can enable and disable navigation items on every page load. Each steps should have a kind of validation process that enables it to decide where to send the user.
- Know how to enable and disable navigation items for each control. How do I link this up? The button indexes are unpredictably different for each navigation control.
- Know how the steps are related so that the user can click the “next” button and be taken to the next sequential step.
- Be maintainable – The current system is so convoluted that fixing one bug causes others.
- Be efficient – It shouldn’t take much time to process on each page load
I suppose that what I’m really having difficulty with is how to define all of these steps somewhere once, so that the system can make use of them. I thought about defining all of the steps in an enum, but I’m foreseeing lot’s of switch statements for enabling the step buttons on the navigation controls.
I’ve Googled every related keyword I could think of, and I can’t find anything helpful. I know that this not a unique issue. I see lots of examples of web apps with similar navigation systems, such as TurboTax.
So, my questions are:
- How do I define all of my steps in one spot so that the entire program knows how to deal with them?
- How do I use those definitions to determine which steps the user can access, and then enable the appropriate navigation items?
It looks like you need to know several things in your system.
The idea is to encapsulate the mapping of visibility dependencies to the status of each task in a central location, and then any other UI element such as navigation panel can use this info to render only those controls that satisfy criteria for visibility for any given step and set of tasks.
Reply from CKirb250:
Sorry, had to place my comment here because the formatting in the comment box sucks.
Yes, I do need a list of steps. Where should I put them? Should they be a simple
enum? Should they be laid out in XML format somwhere so that I can reference them with a key value, their name that should be shown to user, and what aspx page corresponds to that step?This is tracked in the database. In order to know the state of each step, the database is queried.
How could the complex rules be defined? I’m imagining a giant switch statement that says
if (currentStep == steps.Step1) { if (page.IsFilledOut) { enableSteps(1, 2, 3, 4, 5); } }.Here is a way to set this up in XML – each element should be defined as a class, and if tracked in a database (as is recommended) then you have some tables (Step, Task, VisibilityDependency, at least.) You can generate XML from DB (or just populate the classes directly from DB). I used XML as an easy example to just visualize what I am thinking of:
Now what I am thinking is your navigation control would poll your global context, writing some code for this now just to give you an idea of how I would do this.
Here is some code to represent this schema and a method to return all tasks that can be displayed on a page; no switch statements!
Let me know if this is enough to spin your own ideas for a clean way to refactor your code. I’ve developed and worked on many wizard style systems and I have seen first hand what you describe; namely, that it gets to be a mess real fast if not architected well from the onset. Good luck!