Exercise 3: Building a Workflow in Visual Studio 2010
In this exercise you will use Visual Studio to create a workflow that will use the timesheet data approved in the previous examples and convert it to a Word document. The generated timesheet document will be stored in a new document library that can be chosen when the workflow was associated.
Task 1 – Create a new Visual Studio 2010 Sequential Workflow
In this first task, you will create the sequential workflow item that will be the starting point for the timesheet generation workflow.
- Add a new Sequential Workflow item to the TimesheetApplication starter project
- Open VisualStudio 2010 and open the starter lab at %Office2010DeveloperTrainingKitPath%\Labs\ClientWorkflow\Source\[language]\Starter\TimesheetApplication\TimesheetApplication.sln
Locate the Solution Explorer and see the SharePoint items already existing in the solution
Figure 29(b)
TimesheetApplication Solution
Visual Studio 2010 allows the creation and management of SharePoint items, features, and solutions in Visual Studio and deployment with a single menu option
- Right click TimesheetApplication in the Solution Explorer and select Add -> New Item
- In the Add New Item dialog, select the VisualC#\Visual Basic -> SharePoint -> 2010 template category and choose the Sequential Workflow item
Set the name to TimesheetGeneration and click Add to create the new workflow item
Figure 30(b)
Add New Sequential Workflow
- Using the SharePoint Customization Wizard, configure the site used for debugging
- In the first page of the SharePoint Customization Wizard set the name to TimesheetGeneration
Verify the List Workflow radio button is selected and click Next
Figure 31
Set Workflow Name
Verify the check box indicating a workflow association should be created on deployment is cleared and click Finish
Figure 32
Set Workflow Association Options
An association will be created manually to test the Association page
Task 2 – Create the custom Association page
In this task, you will create a custom Association page that allows the user associating the workflow to the Timesheet list to choose a document library to store the generated timesheet.
- Add a new Association Form to the TimesheetGeneration workflow
- Right click TimesheetGeneration SharePoint item in the Solution Explorer and click Add -> New Item
- In the Add New Item dialog, select the VisualC#\Visual Basic -> SharePoint -> 2010 template category and choose the Workflow Association Form item
Set the name to AssociationForm and click Add to create the form
Figure 33
Add New Association Form
Verify that the new AssociationForm.aspx file exists inside the TimesheetGeneration SharePoint item
Figure 34(b)
Workflow SharePoint Item
- Define the layout of the page using custom ASPX markup
- Open the AssociationForm.aspx page’s markup by right clicking it in the Solution Explorer and selecting View Markup
- Locate the asp:Content node with an ID of Main
- Place the following markup inside the asp:Content node to define a UI with a drop down list containing all document libraries in the current site
Make sure the table is placed above the existing buttons
<table> <tr> <td>Archive Document Library</td> <td> <asp:DropDownList ID="ArchiveLibrary" runat="server" /> </td> </tr> </table>
- Implement the code behind that will populate and extract information from the ASPX page
- Open the page’s code by right clicking it in the Solution Explorer and selecting View Code
Add the follow code to the Page_Load method to check if this is the first load of the form
protected void Page_Load(object sender, EventArgs e)
FakePre-34a56b5258844d2f82fc204dffb56140-581e293a1012435c9f764671f49ebee1 bool initialLoad = false; if (ViewState["associationParams"] == null) initialLoad = true;FakePre-760e4bcd1242476b9f50a0e32345818c-bfd24795e9cf4fb78a633994d922d417FakePre-4bc1c446dc9b443684afb8950fc8537a-f71bf812259e4f63b2c925979ccd7d2b
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
Dim initialLoad As Boolean = False If ViewState("associationParams") Is Nothing Then initialLoad = True End IfFakePre-5d57c259bfd64768b90450c0a3ffffa8-fbb3056eacdb4a98ba404ec3461f5109FakePre-bbadade8ea59483c9b8defb4090038d3-ac11affa807642ee8324c928c0d25904
Since the Association form’s initial load is a postback, a special viewstate parameter is used to determine if this is the initial load.
Add the following code to Page_Load to load the DropDownList with all document libraries in the current site
InitializeParams(); // Optionally, add code here to pre-populate your form fields. if (initialLoad) { SPListCollection documentLibraries = Web.GetListsOfType(SPBaseType.DocumentLibrary); foreach (SPList documentLibrary in documentLibraries) ArchiveLibrary.Items.Add(documentLibrary.Title);
InitializeParams() ' Optionally, add code here to pre-populate your form fields. If initialLoad Then Dim documentLibraries As SPListCollection = Web.GetListsOfType(SPBaseType.DocumentLibrary) For Each documentLibrary As SPList In documentLibraries ArchiveLibrary.Items.Add(documentLibrary.Title) Next documentLibrary
Following the load of the drop down list, add the code to select the current archive document library
if (associationParams.AssociationGuid != Guid.Empty) { SPList list = Web.Lists[associationParams.TargetListGuid]; SPWorkflowAssociation association = list.WorkflowAssociations[associationParams.AssociationGuid]; ArchiveLibrary.SelectedValue = association.AssociationData; } }
If associationParams.AssociationGuid <> Guid.Empty Then Dim list As SPList = Web.Lists(associationParams.TargetListGuid) Dim association As SPWorkflowAssociation = list.WorkflowAssociations(associationParams.AssociationGuid) ArchiveLibrary.SelectedValue = association.AssociationData End If }
- Add the following code to GetAssociationData to retrieve the name of the currently selected item
private string GetAssociationData()
FakePre-89ba67bc09ab452ebcd6a71d48c86178-5a0e0f61cbad4fe69d04cd5dfb0a7ce2 return ArchiveLibrary.SelectedValue;FakePre-a95fc6e10b84431384bafa3d7cc9ebfa-aa78f479faf64caf8940fc08ccb8fd85
Private Function GetAssociationData() As String Return ArchiveLibrary.SelectedValue End Function
Task 3 – Implement the TimeSheet generation workflow
In this task, you will implement the workflow process and add the custom activities to generate and store the timesheet.
- Add a new Code activity to the workflow that will generate the timesheet document
- Open the workflow in the designer by right clicking TimesheetGeneration.cs(TimesheetGeneration.vb in case of VB) in the Solution Explorer and choosing View Designer
- Locate the Code activity in the Windows Workflow v3.0 section of the Toolbox and drag it onto the workflow following the existing application
Note: If the Toolbox is not visible, show it by clicking View -> Toolbox
Figure 35
New Code Activity
- Select the new code activity, right click it and select Properties
In the Properties window, set the (Name) property to GenerateDocument
Figure 36
Code Activity Properties
- Add the code behind to create and store the new timesheet document
- Open the code behind for the GenerateDocument activity by double clicking it
In the new GenerateDocument_ExecuteCode method, add the following code to generate the timesheet
private void GenerateDocument_ExecuteCode(object sender, EventArgs e)
FakePre-f9534c845e6547a7b4d70fec57d879c4-6a56f84513124b44a76af4dc42f034e1 Timesheet timesheet = new Timesheet(workflowProperties.Item);
Private Sub GenerateDocument_ExecuteCode(ByVal sender As Object, ByVal e As EventArgs) Dim timesheet_Renamed As New Timesheet(workflowProperties.Item)
Following the previous code, add the following code to lookup the archive document library and write the timesheet into it.
SPDocumentLibrary archiveLibrary = workflowProperties.Web.Lists[ workflowProperties.AssociationData] as SPDocumentLibrary; archiveLibrary.RootFolder.Files.Add( workflowProperties.Item.Title + ".docx", timesheet.WriteTimesheet());
}
Dim archiveLibrary As SPDocumentLibrary = TryCast(workflowProperties.Web.Lists(workflowProperties.AssociationData), SPDocumentLibrary) archiveLibrary.RootFolder.Files.Add(workflowProperties.Item.Title & ".docx", timesheet.WriteTimesheet()) }
The workflowProperties.AssociationData property is initialized by the OnWorkflowInitialized activity. The value is stored in the SPWorkflowAssociation object based on the association data stored in the Association form.
- Deploy the solution by right clicking TimesheetApplication in the Solution Explorer and clicking Deploy
Exercise 3 Verification
In order to verify that you have correctly performed all steps of exercise 3, proceed as follows:
Test the Workflow
Execute your workflow and verify it converts the timesheet list item into a new document in the selected document library.
- Associate the new Timesheet Generation workflow with the Timesheets
- In Internet Explorer, navigate to https://intranet.contoso.com/sites/ClientWorkflow/Lists/Timesheets
- In the List ribbon tab, click Workflow Settings -> Add a Workflow
In the Workflow list, select Timesheet Generation and enter a name of Timesheet Generation
Figure 37
Workflow Association Form
- Click Next to move to the custom association form.
In the custom association form, select Timesheet Archive in the drop down list and click Association Workflow to complete the association
Figure 38
Custom Association Form
- Execute the new workflow to generate a new Timesheet Word document
- In Internet Explorer, navigate to http://intranet.contoso.com/sites/ClientWorkflow/Lists/Timesheets
Select a timesheet in the list and click the Workflows button in its drop down menu
- In the Workflow page, click Timesheet Generation to start the process
When the workflow is completed navigate to https://intranet.contoso.com/sites/ClientWorkflow/TimesheetArchive and verify a new timesheet document has been created
Figure 40
Timesheet Archive Document Library
Click the document’s drop down menu to open the document in Word and verify it contains the timesheet data
Figure 41
Generated Timesheet Document