in

SharePoint Blogs

The Best Place for SharePoint-related Blogs

Robert J Wheeler

...a blog to remember...

Create Wizard Functionality With SharePoint Lists

Recently I was asked to create a wizard application using Windows SharePoint Services 3.0, but with a twist.  I was not going to be able to use compiled code on the site, I was not going to have the Survey template at my disposal, and I needed this to be created within a day.  To make matters more difficult, I needed to leverage off of existing lists which were created in the WSS site hosting the wizard.  The first thing I noticed was the number of wizards required (well and truly over 100).  There were 2 lists being used, one for configuration and help, and one for the questions and responses.    The customer had also created a custom edit pages for each of the wizards they needed.  Each page used inline code and accessed the lists using the current http context.  Needless to say this required a lot of cut and paste.  I needed to make it simpler, and here is how I did it.

How I Approached the Wizard
The first thing I decided to do was to remove the custom edit pages and make one central page within the Applications folder of the site.  This way I could have the lists to use a single source for generating the questions and gather the responses.  I also created a custom master page which I could add the placeholders required to dynamically load my Asp:Wizard control.

In my master page I added and Asp:ContentPlaceHolder - I called it WPH.  Next I created the wizard.aspx page and referenced my custom master page.  Now I was ready to add the inline code (since I was unable to use compiled code) to the page.

The Walkthrough

 

Setup the Site and Lists


Before you begin this walkthrough you should set up your lists so that when you run the page you have access to the questions and help.  To do this create a blank WSS site and add 2 custom lists.  Name the first list Wizard Questions and the second Wizard Help.

For ease of use and to limit the number of items we want to loop through to generate the wizard steps, create a view which has only the columns that contain the questions.  There are many hidden fields on a SharePoint list which add overhead during the build process.  If you want to see just how many fields there are, use the All Items view in the code below.

The second list is where the wizard configuration is kept.  Each line item has the name of the wizard, the field name of the question, and the help text to display for the user.  Although a view can be used here as well, we will implement a CAML query instead to match the column name and return only one value.  If you create a view you will need to modify the code further to return the list to query against.
Now that we have the site and the lists we can begin with the actual inline code.  Start by adding the 2 events that will be fired when the page is loaded and when the wizard steps are complete.  Add to the script block the following events.

protected void Page_Load(object sender, EventArgs e)
    {
    }

protected void wizard_FinishButtonClick(Object sender, WizardNavigationEventArgs e)
    {
    }

This will provide the necessary framework to generate the wizard and handle the event of the finish button.

The next step is to get the current item that fired the wizard page, which is wired up to the New/Edit actions of the list itself.  To get the current item and the wizard name I add the following to the Page_Load event.  This will give you the item as a SPListItem which we will use throughout the page.  Since the list contains the name of the wizard stored in the Wizard Name field, add additional lines to set the wizard name at the same time.

   // Get the current item from the context
   SPListItem item = (SPListItem)SPContext.Current.Item;
   // Get the wizard name from the content type field
   string wizardName = item["Wizard Name"].ToString();
   // Set the root to the site where the list is
   string strListRoot = http://localhost/sites/Wizard/;

Next add the wizard, but to control the process of the wizards turn off the side navigation.  Add the following lines after the site.

   // Programmatically create wizard control
   Wizard wizard = new Wizard();
   // Hide the wizard side bar
  
wizard.DisplaySideBar = false;

 
Wire up the events.  This is the only way that the wizard events can be used since we are programmatically adding the control to the page.
 
   // Add events to the page for the wizard buttons
   wizard.FinishButtonClick += new
        WizardNavigationEventHandler(wizard_FinishButtonClick);

Grab a reference to the site and to the web which are disposable when the code is run and complete.  This will help in cleaning up after our code runs and release the resources used.

   // Get a reference to the site
   using (SPSite site = new SPSite(strListRoot))
       {
           using (SPWeb web = site.OpenWeb())
            {

               ...
            }

       }
 
Once the structure is in place we add the code to iterate over the list items.  This is where we apply the view created earlier to return only the columns that have questions.  Add the following lines between the second using statement since they use the reference to the web object.
 
   //  Get a reference to the list for wizard responses
   SPList list = web.Lists["Wizard Questions"];
   //  Get a reference to the list for wizard configuration
   SPList help = web.Lists["Wizard Configuration"];
   //  Get a collection of items
   SPListItemCollection itemColl = list.Items;
   //  Get the view from the list
   SPView view = list.Views[wizardName];
   //  Get a collection of columns from the view
   SPViewFieldCollection viewFields = view.ViewFields;
 
We now have the references to the list items that will be used, collections of fields and other variables so we can now loop through and generate the wizard steps.  Add the following lines after the references to the list items and views.
 
   foreach (SPField field in list.Fields)
   {
       if (!field.Hidden)
       {
           if (viewFields.Exists(field.InternalName))
           {
               String currentField = String.Empty;
               currentField = field.InternalName.ToString();
                              WizardStepBase newStep = new WizardStep();
                              newStep.ID = field.Id.ToString();
                              newStep.Title = field.Description;
                              Label contextHelp = new Label();
                              Label question = new Label();
                              RadioButtonList radios = new RadioButtonList();
                              SPFieldChoice choiceField = (SPFieldChoice)field;
                              foreach (String choice in choiceField.Choices)
                              {
                                  radios.Items.Add(choice);
                              }
           }
        }
    }
 
At this point we have added the items to the radio list and have created the wizard steps.  Next we need to add the help from the other list.  Rather than iterate over the entire list of items we will issue a CAML query to select the item which matches the field that we are currently on.   Add the following code after the section above.
 
    question.Text = field.Description;
    SPQuery query = new SPQuery();
    query.Query = "<Where><Eq>" +
    "<FieldRef Name='FieldName'/><Value Type='Text'>" +
    currentField +
    "</Value></Eq></Where>";
    SPListItemCollection helpItems = help.GetItems(query);
    String helpText = String.Empty;
    SPListItem helpItem = (SPListItem)helpItems[0];
    helpText = helpItem["HelpText"].ToString();
    if (helpText != "")
    {
        contextHelp.Text = helpText;
    }
 
If the item can run through the wizard after the first collection, you can set the selected value of the radio button to the value stored in the item itself.
 
    if (item[currentField] != null)
    {
        radios.SelectedValue = item[currentField].ToString();
    }
 
Finally, we need to give the radio button an ID.  We will use the current field name which will help us identify the control when we do our final postback.  The idea here is to limit the number of variables and view state objects to store information.
 
    radios.ID = currentField;
    newStep.Controls.Add(prompt);
    newStep.Controls.Add(radio);
    newStep.Controls.Add(contextHelp);
    wizard.WizardSteps.Add(newStep);
 
We have now added the steps to the wizard control, so all that is left is to add the wizard control to the page.  This is done by referencing the master page and finding the placeholder to the controls.

    this.Master.FindControl("WPH").Controls.Add(wizard);

 
At this point we have the wizard steps added and the events tied up.  We just need to finish it off by adding the code to handle posting the responses to the list.  Similar to the page load code we add the same references and get the list item.  However, finding the radio options within the wizard steps requires a bit more effort.  There are actually many controls within the wizard step so we need to iterate over the collection and find the values.
 
To complete the finish button event we will add the following code.  It starts the same as the Page_Load event.
 
    SPListItem currentListItem = (SPListItem)SPContext.Current.Item;
    string wizardName = currentListItem["Wizard Name"].ToString();
    string strDashListRoot = "http://localhost/Wizard/";
 
    using (SPSite site = new SPSite(strDashListRoot))
    {
            using (SPWeb web = site.OpenWeb())
            {
                web.AllowUnsafeUpdates = true;
                web.Update();
                SPList list = web.Lists["Wizard Questions"];
                SPListItem item = (SPListItem)SPContext.Current.Item;
                SPView view = list.Views[wizardName];
                SPViewFieldCollection viewFields = view.ViewFields;
                String currentField = String.Empty;
 
Now we are ready to iterate over the fields and find the column name which we will use to help identify the radio options and get the results.
 
    foreach (SPField field in list.Fields)
    {
        if (!field.Hidden)
        {
            if (viewFields.Exists(field.InternalName))
            {
                currentField = field.InternalName.ToString();
                RadioButtonList radio = new RadioButtonList();
 
Next we need a collection of controls that the wizard step holds.  We added the radios options to the wizard step which is a control.
 
    ControlCollection controls = this.Master.FindControl("WPH").Controls;
 
Loop through the controls and find the one which as the same ID as the current field we have.
 
    foreach (Control ctl in controls)
        {
            Control ctl2 = ctl.FindControl(currentField);
            if (ctl2 != null)
            {
                radio = (RadioButtonList)ctl2;
                String value = radio.SelectedValue.ToString();
                if (value != null)
                {
                    item[currentField] = value;
                    item.Update();
                }
            }
        }
 
We will set the AllowUnsafeUpdates back to false since we have finished with the process up updating the list.
 
    web.AllowUnsafeUpdates = false;
    web.Update();
 
It is not necessary to run the page within SharePoint at this time since we are referencing the Microsoft.SharePoint dll.  But for the sake of this walkthrough we are.  When the page loads it will find the questions which are to be asked, match the help text and display the steps.
 
When it completes, the results will be stored in the list.  Each list item will have its own row within the list and can be re-initialised and run a second time allowing you to change the values.
 
Use SharePoint Designer to change the default page from NewItem.aspx and EditItem.aspx to the wizard page.  Now when users select the item the wizard will load and if there are values already, it will select those in the radio options.

Comments

 

Robert J Wheeler said:

Recently I developed a wizard using SharePoint lists. The challange was to use only WSS 3.0, no compiled

August 22, 2007 6:10 PM
 

24 Links Today (2007-08-23) said:

Pingback from  24 Links Today (2007-08-23)

August 23, 2007 10:23 AM
 

Christa Ayer said:

Useful article! Please contact me if you're interested in writing for Advisor Guide to Microsoft SharePoint.

THX!

Christa Ayer

christa_ayer @ advisormedia.net

August 24, 2007 10:38 AM
 

Blogger Loser » Blog Archive » Create Wizards in SharePoint said:

Pingback from  Blogger Loser  &raquo; Blog Archive   &raquo; Create Wizards in SharePoint

August 27, 2007 12:00 AM

Leave a Comment

(required )  
(optional )
(required )  
Add

Need SharePoint Training? Attend a SharePoint Bootcamp!

Posts (c) their respective authors. Everything else (c) 2007 SharePoint Experts