Export (0) Print
Expand All
Expand Minimize

Creating Workflow Association Pages for Windows SharePoint Services 3.0

Windows SharePoint Services 3

Summary:  With a workflow association page, users can provide values for workflow settings in Windows SharePoint Services 3.0. Learn how to use an ASPX page to create an association between a custom workflow template and a container or a content type.

Visual How To

Applies to:  Windows SharePoint Services 3.0

Patrick Tisseghem, U2U

February 2008

Overview

A custom workflow template for Windows SharePoint Services 3.0 can be accompanied by various pages that enable administrators and users to provide values for the workflow settings. A workflow association page is one of those pages. It is displayed whenever administrators create an association between the workflow template and a container (list or document library) or a content type. This Visual How To explains and demonstrates the steps for creating this interaction by using an ASPX page.

Code It

To learn how create an ASPX page that you can use as a workflow association page, watch the video and study the following steps and code.

Code-behind an ASPX Workflow Association Page

A custom ASPX association page for a workflow is an application page that is deployed in the C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS folder. The code-behind class inherits from the Microsoft.SharePoint.WebControls.LayoutsPageBase class. You can embed all the code directly in the ASPX page, but a better approach is to encapsulate the code in a separate class. You can then associate the ASPX with the code-behind class by using the Assembly directive and the Page directive with the Inherits attribute pointing to the code-behind class within the .NET assembly.

<%@ Assembly Name="RegistrationsWorkflow, Version=1.0.0.0, 
  Culture=neutral, PublicKeyToken=5f88da336c1c0e26" %>
<%@ Page Language="C#" MasterPageFile="~/_layouts/application.master" 
  EnableSessionState="true" ValidateRequest="False" 
  Inherits="U2U.Workflows.RegistrationsAssociation" %>

User Interface Controls within the ASPX Workflow Association Page

Controls to be displayed to the administrators in the browser must be dropped inside the content placeholder that has the ID PlaceHolderMain. You can use various controls; this sample works with a simple page that contains two sections: InputFormSection and ButtonSection.

<wssuc:InputFormSection Title="Discount Input" Description=
 "Specify the two discount percentages to be used in the workflow."
 runat="server">
 <template_inputformcontrols>
  <wssuc:InputFormControl runat="server" 
   LabelText="Discount percentages:">
     <Template_Control>
       <div>Enter discount for less than 10 tickets:
         <SharePoint:InputFormTextBox CssClass="ms-input" 
          ID="textBoxDiscount1" runat="server" Text="10"/>
        </div>
        <div>Enter discount for more than 10 tickets: 
          <SharePoint:InputFormTextBox CssClass="ms-input" 
           ID="textBoxDiscount2" runat="server" Text="20"/> 
        </div>
      </Template_Control>
   </wssuc:InputFormControl>
 </template_inputformcontrols>
</wssuc:InputFormSection>

<wssuc:ButtonSection runat="server" ShowStandardCancelButton="false">
 <template_buttons>
   <asp:PlaceHolder runat="server">
    <asp:Button UseSubmitBehavior="false" runat="server" 
       class="ms-ButtonHeightWidth" OnClick="cmdSubmit_OnClick" 
       Text="OK" id="BtnSubmit" /> &nbsp;
    <asp:Button UseSubmitBehavior="false" runat="server" 
       class="ms-ButtonHeightWidth" OnClick="cmdCancel_OnClick" 
       Text="Cancel" id="cmdCancel" causesvalidation=false />
     </asp:PlaceHolder>
   </template_buttons>
  </wssuc:ButtonSection>

Working with the UI Controls in the Code-Behind Class

Handling the events and working with the UI controls in your code-behind class requires you to declare a variable for each control by using the same name and type.

protected InputFormTextBox textBoxDiscount1;
protected InputFormTextBox textBoxDiscount2; 

Preparing the Association

Administrators use the Add a Workflow page (AddWrkfl.aspx) to select workflow templates they want to associate. In the page, they also enter various parameters settings for the workflow (such as the decision to reuse an existing task list or have one created, the choice for a history list, and the start mode for the workflow instances). All these settings need to be processed within your custom association page.

protected override void OnLoad(EventArgs e)   {
  string paramWorkflowName = Request.Params["WorkflowName"];
  string paramWorkflowDefinition = 
       Request.Params["WorkflowDefinition"];
  string paramList = Request.Params["List"];
  string paramCType = Request.Params["ctype"];
  string paramUpdateLists = Request.Params["UpdateLists"];
  string paramTaskList = Request.Params["TaskList"];
  string paramHistoryList = Request.Params["HistoryList"];
  string paramAllowManual = Request.Params["AllowManual"]; 
  string paramAutoStartCreate = Request.Params["AutoStartCreate"]; 
  string paramAutoStartChange = Request.Params["AutoStartChange"];
  string paramManualPermManageListRequired = 
       Request.Params["ManualPermManageListRequired"];
  string paramGuidAssoc = Request.Params["GuidAssoc"];
  WorkflowAssociationName = paramWorkflowName;
  WorkflowTemplateId = new Guid(paramWorkflowDefinition);
  WorkflowTemplate = Web.WorkflowTemplates[WorkflowTemplateId];
  if (!string.IsNullOrEmpty(paramGuidAssoc)) {
     WorkflowAssociationExists = true;
     WorkflowAssociationId = new Guid(paramGuidAssoc);
   }
   UpdateContentTypesOnLists = (paramUpdateLists == "TRUE");
   if (!string.IsNullOrEmpty(paramList))  {
     ListId = new Guid(paramList);
     List = Web.Lists[ListId];
   }
   if (string.IsNullOrEmpty(paramCType))  {
     AssociationType = AssociationTypeEnum.List;
     if (WorkflowAssociationExists)  {
     WorkflowAssociation = 
         List.WorkflowAssociations[WorkflowAssociationId];
     }
   }
   else  {
     if (List == null)  {
        AssociationType = AssociationTypeEnum.ContentType; 
        CTypeId = new SPContentTypeId(paramCType);
        CType = Web.AvailableContentTypes[CTypeId];
        if (WorkflowAssociationExists)  {
           WorkflowAssociation = 
                CType.WorkflowAssociations[WorkflowAssociationId];
        }
      }
      else   {
         AssociationType = AssociationTypeEnum.ContentTypeOnList;
         CType = List.ContentTypes[new SPContentTypeId(paramCType)];
         if (WorkflowAssociationExists)  {
            WorkflowAssociation = 
                 CType.WorkflowAssociations[WorkflowAssociationId];
         }
      }
   }
   if (paramTaskList[0] == 'z')  {
      NewTaskListRequired = true;
      NewTaskListName = paramTaskList.Substring(1);
   }
   else  {
      if (AssociationType == AssociationTypeEnum.ContentType) {
         TaskList = Web.Lists[paramTaskList];
      }
      else  {
          TaskList = Web.Lists[new Guid(paramTaskList)];
      }
    }
    if (paramHistoryList[0] == 'z')  {
       NewHistoryListRequired = true;
       NewHistoryListName = paramHistoryList.Substring(1);
    }
    else  {
       if (AssociationType == AssociationTypeEnum.ContentType) {
          HistoryList = Web.Lists[paramHistoryList];
       }
       else  {
          HistoryList = Web.Lists[new Guid(paramHistoryList)];
       }
    }
    if (WorkflowAssociationExists)  {
       PageTitle = "Update Workflow Association";
       PageTitleInArea = "Update Workflow Association '" + 
            WorkflowAssociationName + "'";
       PageDescription = 
          "Click OK to update the workflow associated named " + 
          WorkflowAssociationName;
    }
    else  {
       PageTitle = "Create Workflow Association"; 
       PageTitleInArea = "Create Workflow Association '" + 
           WorkflowAssociationName + "'";
       PageDescription = 
           "Click OK to create a new workflow association named " + 
           WorkflowAssociationName;
    }
}

Preparing the Association Data for Processing

Data that is entered in the association form must be stored as a string. The string must be passed to the workflow engine so that the engine can make the data available for further processing within your workflow code. A best practice is to serialize and deserialize the data by using a generated .NET class that is based on an XSD schema defining the data. The following two methods of your code-behind class handle the reading and writing:

protected void PopulateFormDataFromString(string AssociationData) {
   XmlSerializer serializer = 
      new XmlSerializer(typeof(RegistrationsWorkflowData));          
   XmlTextReader reader = 
      new XmlTextReader(new StringReader(AssociationData));
   RegistrationsWorkflowData formData = 
      (RegistrationsWorkflowData)serializer.Deserialize(reader);
   textBoxDiscount1.Text = formData.Discount1;
   textBoxDiscount2.Text = formData.Discount2;
}
protected string SerializeFormDataToString()  {
   RegistrationsWorkflowData formData = _
      new RegistrationsWorkflowData();
   formData.Discount1 = textBoxDiscount1.Text;
   formData.Discount2 = textBoxDiscount2.Text;
   using (MemoryStream stream = new MemoryStream())  {
      XmlSerializer serializer = _
         new XmlSerializer(typeof(RegistrationsWorkflowData));
      serializer.Serialize(stream, formData);
      stream.Position = 0;
      byte[] bytes = new byte[stream.Length];
      stream.Read(bytes, 0, bytes.Length);
      return Encoding.UTF8.GetString(bytes);
   }
}

Handling the Submit

The final piece of code to discuss is the event handler that submits the form data. It must create or connect to the task list and history list and create an SPWorkflowAssociation instance, passing the appropriate parameter values. The instance must then be added to the SPWorkflowAssociationCollection object of either SPList or SPContentType.

public void cmdSubmit_OnClick(object sender, EventArgs e)  {
   string RedirectUrl = "";
   if (NewTaskListRequired) {
     Guid TaskListId = Web.Lists.Add(NewTaskListName, "Workflow Tasks", 
       SPListTemplateType.Tasks);
     TaskList = Web.Lists[TaskListId];
   }
   if (NewHistoryListRequired)  {
     Guid HistoryListId = Web.Lists.Add(NewHistoryListName, 
        "Workflow History", SPListTemplateType.WorkflowHistory);
     HistoryList = Web.Lists[HistoryListId];
   }
   switch (AssociationType)
     case AssociationTypeEnum.List:
        if (WorkflowAssociationExists)  {
         UpdateAssociation(WorkflowAssociation, TaskList, HistoryList); 
         List.UpdateWorkflowAssociation(WorkflowAssociation);
        }
        else  {
         WorkflowAssociation =
           SPWorkflowAssociation.CreateListAssociation
             (WorkflowTemplate, WorkflowAssociationName, TaskList,
              HistoryList);
           UpdateAssociation(WorkflowAssociation, TaskList, 
              HistoryList);
           List.AddWorkflowAssociation(WorkflowAssociation);
        }
        RedirectUrl = "WrkSetng.aspx?List=" + ListId.ToString();
        break;
      case AssociationTypeEnum.ContentType:
        if (WorkflowAssociationExists)  {
          WorkflowAssociation = 
              CType.WorkflowAssociations[WorkflowAssociationId];
              UpdateAssociation(WorkflowAssociation, 
                                TaskList, HistoryList);
              CType.UpdateWorkflowAssociation(WorkflowAssociation);
              if (UpdateContentTypesOnLists) {
                CType.UpdateWorkflowAssociationsOnChildren
                      (true, true, true);
              }
         }
         else  {
           WorkflowAssociation =     
               SPWorkflowAssociation.CreateSiteContentTypeAssociation
               (WorkflowTemplate, WorkflowAssociationName,  
                TaskList.Title, HistoryList.Title);
           UpdateAssociation(WorkflowAssociation, TaskList, 
                             HistoryList);
           CType.AddWorkflowAssociation(WorkflowAssociation); 
           if (UpdateContentTypesOnLists)  {
            CType.UpdateWorkflowAssociationsOnChildren
               (true, true, true);
           }
         }
         RedirectUrl = "WrkSetng.aspx?ctype=" + CTypeId.ToString();
         break;
       case AssociationTypeEnum.ContentTypeOnList:
         if (WorkflowAssociationExists) {
           WorkflowAssociation = 
               CType.WorkflowAssociations[WorkflowAssociationId]; 
           UpdateAssociation(WorkflowAssociation, TaskList, 
                             HistoryList);
           CType.UpdateWorkflowAssociation(WorkflowAssociation);
         }
         else  {
           WorkflowAssociation = 
              SPWorkflowAssociation.CreateListContentTypeAssociation
              (WorkflowTemplate, WorkflowAssociationName, TaskList, 
               HistoryList);
           UpdateAssociation(WorkflowAssociation, TaskList, 
                             HistoryList); 
           CType.AddWorkflowAssociation(WorkflowAssociation);
         }
         RedirectUrl = "WrkSetng.aspx?List=" + 
             ListId.ToString() + "&ctype=" + CTypeId.ToString();    
         break;
     }
     SPUtility.Redirect(RedirectUrl, 
       SPRedirectFlags.RelativeToLayoutsPage, HttpContext.Current);
 }

Custom Association Page Registration in Workflow Feature

Now let's examine the definition within the element manifest file of the workflow Feature. You indicate to SharePoint that it should include your custom association ASPX page by adding the AssociationUrl attribute to the Workflow element, with the value of the attribute pointing to the URL of the page.

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
   <Workflow Name="Registration Workflow"
    Description="This workflow calculates the total amount for a 
    registration done by a company"
    Id="{7EC50015-B1A5-406b-A385-43AF8B296916}"
    CodeBesideClass="U2U.Workflows.WFDiscount"  
    CodeBesideAssembly="RegistrationsWorkflow, Version=1.0.0.0, 
    Culture=neutral, PublicKeyToken=5f88da336c1c0e26"
    AssociationUrl=
     "_Layouts/Registrations/RegistrationsAssociation.aspx" >
    <Categories/>
    <MetaData />
  </Workflow>
</Elements>
Read It

With a workflow association page, users can provide values for workflow settings in Windows SharePoint Services 3.0. This Visual How To showed you how to use an ASPX page to create an association between a custom workflow template and a container or a content type.

See It

Creating a Workflow Association Page

Watch the Video

Length: 11:26 | Size: 10.5 MB | Type: WMV

Explore It
Show:
© 2014 Microsoft