Is there a better way to handle the progression through a wizard dialog?
I'm working on an existing wizard dialog which is implemented as a tabbed page control (with the tabs hidden). The steps of the wizard are defined in an enumerated type. When the user clicks a navigation button the current step is run through a switch stat开发者_如何学运维ement. Each branch of the switch is filled with additional branching logic (if/then/else) which saves the state of various user choices and assigns the next step (which isn't necessarily sequential and doesn't necessarily coincide with the tab page displayed to the user).
When the current step is modified it triggers an additional switch statement which updates the UI (change tab page, enable/disable controls, etc.)
As implemented the wizard is very sensitive to changes and requires a lot of debugging. I can't help but feel there is a better way to design it. Any suggestions?
I haven't got enough rep to add a comment so i'll have to post this as an answer which it isn't! From a previous stackoverflow post:
Methods of simplifying ugly nested if-else trees in C#
I just thought it might be relevant.
At this point in time my recommendation would be to build a small proof of concept (poc) to show that you can migrate the wizard in its current form to a more well designed system. Looking at it from a development point of view, I would suggest building the poc to match what the user sees in terms of names and elements. Additionally you will need to record the state of the object as it is passed around to each of the pages, in case the user back tracks or does something else. Another area that might help is to implement a rules engine such as DROOLS, or JBoss rules as it goes last I checked. There exists an algorithm that I can't recall at the time that will really help with performance as well. So to recap:
1) Create a small poc
2) Use objects that have state
3) Look for a good rules engine
4) Get approval to do all of these things.
I should add I realize you were burned before on the whole re-write thing, but this is only a module not the entire enterprise.
I recently implemented a design in our application to solve a similar problem. Our application works with workflows that require a variable combination of steps to complete.
As a general starting rule, I decided that the steps themselves don't store information. They are not allowed to talk to each other either. They have pointers to Model objects that hold the information. I don't follow either the MVC or MVP patterns, but I do keep the Model separted from the UI fairly strictly.
Each workflow step has an OnEnter(bool forward)
and OnExit(bool forward)
method that they are required to implement. In these, you query the Model to update your controls or vice versa.
Moving from one step to the other is done by an StateEngine
It keeps a stack around of all the steps that were completed, and when the back button is pressed, the current state is Exit
ed and the previous is Enter
ed. The engine has a notion of the default order, so most steps just ask the StateEngine
to move to the next step, whatever it is, but if you ask it to move to a specific one, it will do that.
Before this design, a major maintenance pain was stepping back in the workflow, that was almost automatically fixed in this design. The design did not solve world hunger but it keeps the wizard code managable.
I've made tons of wizards in my career, with many different languages. Usually what worked better for me was to have some kind of parent container and each step in a different class/component. The trigger mechanism (next-prev type buttons) sends a message to the manager to replace the content in the container.
Right now I'm doing yet another wizard, and this time I'm using a WPF component from Actipro and it looks good. Simple and effective.
精彩评论