CREATE WORKFLOW WITH CUSTOM TASK FORM (ASPX PAGE) IN SHAREPOINT 2010
Article purpose:
When create new a requirement => will appear a register
form (ASPX Form), after register successful, workflow auto run and send Task
for any people, and that requirement when people receive it will open Task to
Approve on form (ASPX Form)
Steps implement
Create new content type for list Target
Create new List Definition for list Target
Create new module
Create new custom aspx form (application page) for List Target
Create new content type for list task
Tạo custom aspx form (application page) for List Task
Create new basic workflow
Create new Event Receiver to active workflow run when add content type item
Implement
Open visual studio | New Project | Visual C# | Sharepoint |
2010 | Empty Sharepoint Project | name í MSTechSharing_TaskFormASPX
Choose “Deploy as a farm solution”
Create new content type for list Target
Right click to project | New Item | Content type | name is
MSTechSharing_TaskFormASPX_ContentTypeTargetList
Choose Content Type Item
Structure of Element.xml file content type as follows
Create new List Definition for list Target
Right click to project | Add new item | List Definition From
Content Type | Name is MSTechSharing_TaskFormASPX_ListDefinition_TargetList
Choose content type inherit from content type
“MSTechSharing_TaskFormASPX_ContentTypeTargetList” had created above
Structure of List Definition as follows
change 100 number in Element.xml file of ListInstance1 if
you want to your List is custom list
Must change 100 number in Element file of
MSTechSharing_TaskFormASPX_ListDefinition_TargetList (image 10)
This is structure of Schema.xml in
MSTechSharing_TaskFormASPX_ListDefinition_TargetList list
In tag <FieldRefs> </ FieldRefs> insert Fields
as follows (option)
<!--Insert to here-->
<FieldRef ID="FA564E0F-0C70-4AB9-B863-0177E6DDD247" Name="Title" Hidden="TRUE" Required="FALSE"/>
<FieldRef ID="{D37DE7CA-1296-47CF-91EB-2C8D09D94C00}" Name="Description" />
<!--End Insert to here-->
Insert the segment code to register form aspx when display
you Add New Item
<!--Insert to here-->
<XmlDocuments>
<XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
<FormTemplates xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
<Display>ListForm</Display>
<Edit>ListForm</Edit>
<New>ListForm</New>
</FormTemplates>
</XmlDocument>
<XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url">
<FormUrls xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url" >
<New>Form/TargetList_AddNew.aspx</New>
</FormUrls>
</XmlDocument>
</XmlDocuments>
<!--End Insert to here-->
In tag <Fields>
</Fields> insert segment code as follows
<!--Insert to here-->
<Field Type="Text" ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" Name="Title" ReadOnly="TRUE" Required="FALSE" Hidden="TRUE"
SourceID="http://schemas.microsoft.com/sharepoint/v3" StaticName="Title"></Field>
<Field ID="{d37de7ca-1296-47cf-91eb-2c8d09d94c00}" Type="Text" Name="Description" DisplayName="Description" />
<!--End Insert to here-->
Tạo mới module
Right click to Project | Add new Item | Module | name is
Form then delete file Sample.txt
Create new custom aspx form (application page) for List Target
Right click to Project | Add new Item | Application Page |
name is TargetList_AddNew.aspx
Application Page structure as follows
Change DynamicMasterPageFile to MasterPageFile by delete
Dynamic character
<%@ Page
Language="C#"
AutoEventWireup="true"
CodeBehind="TargetList_AddNew.aspx.cs"
Inherits="MSTechSharing_TaskFormASPX.Layouts.MSTechSharing_TaskFormASPX.TargetList_AddNew" PageFile="~masterurl/default.master" %>
Copy segment code into PlaceHolderMain (image 20)
<table style="width: 900px;">
<tr>
<td class="column1">
Họ và tên
</td>
<td class="column2">
<asp:TextBox ID="TextBox_HoTen"
runat="server"
Width="309px"></asp:TextBox>
</td>
</tr>
</table>
Copy Target list to PlaceHolderAdditionalPageHead,
PlaceHolderPageTitle, PlaceHolderPageTitleInTitleArea
Using and change class inherit from LayoutsPageBase to WebPartPage
as follows:
using Microsoft.SharePoint.WebPartPages;
using Microsoft.SharePoint.Utilities;
Copy code Button_Submit_Click, Button_Cancel_Click,
CloseForm below Page_Load method
using System;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;
using Microsoft.SharePoint.Utilities;
namespace
MSTechSharing_TaskFormASPX.Layouts.MSTechSharing_TaskFormASPX
{
public partial class TargetList_AddNew
: WebPartPage
{
protected void
Page_Load(object sender, EventArgs e)
{
}
protected void
Button_Submit_Click(object sender, EventArgs e)
{
SPList spList = SPContext.Current.List;
SPListItem spListItem = spList.Items.Add();
spListItem["Title"] =
txtDescription.Text + "";
spListItem["Description"]
= txtDescription.Text + "";
spListItem.Update();
spList.Update();
CloseForm();
}
protected void
Button_Cancel_Click(object sender, EventArgs e)
{
CloseForm();
}
private void
CloseForm()
{
if ((SPContext.Current
!= null) && SPContext.Current.IsPopUI)
{
this.Context.Response.Write("<script type='text/javascript'>window.frameElement.commitPopup();</script>");
this.Context.Response.Flush();
this.Context.Response.End();
}
else
{
string str = this.Page.Request.QueryString["Source"];
if ((str != null)
&& (str.Length > 0))
{
SPUtility.Redirect(string.Empty, SPRedirectFlags.UseSource,
this.Context);
}
}
}
}
}
Cut
TargetList_AddNew.aspx into Form Module
You see the path auto insert to file Element.xml of Form
module
Deploy Project create new Item content type as follows
Result as follows:
Create new content type for list task
Right click to project | Add new item | Content type |
MSTechSharing_TaskFormASPX_ContentTypeTask
Choose Task Content Type
You see default number string of content type Task is
0x010800 you must change to 0x01080100
After change number then delete Inherits= “True” properties (image 30)
After number string was changed and Inherits= “True”
properties was deleted, result as follows
Below close tag </FieldRefs> insert code to know path
of Form Display and Edit of Task form
Create new custom aspx form (application page) for List Task
Right click to project | New Item | Application Page | Name
is CustomFormTaskList.aspx
Change DynamicMasterPageFile to MasterPageFile by delete
Dynamic character
Copy code into PlaceHolderMain
<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">
<!--Insert code to here-->
<table style="width: 500px;" class="lcttable">
<tr>
<td>
Description
</td>
<td>
<%=Description%>
</td>
</tr>
<tr>
<td>
</td>
<td>
<asp:Button ID="Button_Ok"
runat="server"
Text="OK"
Width="100px"
OnClick="Button_Ok_Click"
/>
<asp:Button ID="Button_Cancel"
runat="server"
Text="Cancel"
Width="100px"
OnClick="Button_Cancel_Click"
/>
</td>
</tr>
</table>
<!--End Insert code to here-->
</asp:Content>
Copy Custom Form Task List to PlaceHolderAdditionalPageHead,
PlaceHolderPageTitle, PlaceHolderPageTitleInTitleArea
<%@ Assembly
Name="$SharePoint.Project.AssemblyFullName$"
%>
<%@ Import
Namespace="Microsoft.SharePoint.ApplicationPages"
%>
<%@ Register
TagPrefix="SharePoint"
Namespace="Microsoft.SharePoint.WebControls"
Assembly="Microsoft.SharePoint,
Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
%>
<%@ Register
TagPrefix="Utilities"
Namespace="Microsoft.SharePoint.Utilities"
Assembly="Microsoft.SharePoint,
Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
%>
<%@ Register
TagPrefix="asp"
Namespace="System.Web.UI"
Assembly="System.Web.Extensions,
Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
<%@ Import
Namespace="Microsoft.SharePoint"
%>
<%@ Assembly
Name="Microsoft.Web.CommandUI,
Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
%>
<%@ Page
Language="C#"
AutoEventWireup="true"
CodeBehind="CustomFormTaskList.aspx.cs"
Inherits="MSTechSharing_TaskFormASPX.Layouts.MSTechSharing_TaskFormASPX.CustomFormTaskList"
MasterPageFile="~masterurl/default.master"
%>
<asp:Content ID="PageHead" ContentPlaceHolderID="PlaceHolderAdditionalPageHead" runat="server">
Custom
Form Task List
</asp:Content>
<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">
<!--Insert code to here-->
<table style="width: 500px;" class="lcttable">
<tr>
<td>
Description
</td>
<td>
<%=Description%>
</td>
</tr>
<tr>
<td>
</td>
<td>
<asp:Button ID="Button_Ok"
runat="server"
Text="OK"
Width="100px"
OnClick="Button_Ok_Click"
/>
<asp:Button ID="Button_Cancel"
runat="server"
Text="Cancel"
Width="100px"
OnClick="Button_Cancel_Click"
/>
</td>
</tr>
</table>
<!--End Insert code to here-->
</asp:Content>
<asp:Content ID="PageTitle" ContentPlaceHolderID="PlaceHolderPageTitle" runat="server">
Custom
Form Task List
</asp:Content>
<asp:Content ID="PageTitleInTitleArea" ContentPlaceHolderID="PlaceHolderPageTitleInTitleArea" runat="server">
Custom
Form Task List
</asp:Content>
Using and change class inherit from LayoutsPageBase -> WebPartPage
Copy code as follows
using System;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.WebPartPages;
namespace
MSTechSharing_TaskFormASPX.Layouts.MSTechSharing_TaskFormASPX
{
public partial class CustomFormTaskList
: WebPartPage
{
public string Description;
protected void
Page_Load(object sender, EventArgs e)
{
try
{
SPListItem spListItem = SPContext.Current.ListItem;
string urlLink = spListItem["WorkflowLink"].ToString().Split(',')[0];
int idItem = Convert.ToInt32(urlLink.Split('=')[1]);
SPSite ObjSite;
SPWeb ObjWeb;
SPSecurity.RunWithElevatedPrivileges(delegate
{
using (ObjSite = new SPSite(SPContext.Current.Site.ID))
{
using (ObjWeb = ObjSite.RootWeb)
{
SPList objList = ObjWeb.GetListFromUrl(urlLink);
SPListItem target = objList.GetItemById(idItem);
Description =
target["Description"] + "";
string action = Page.Request.QueryString["action"] + "";
if
(action == "display")
{
Button_Cancel.Visible = false;
Button_Ok.Visible = false;
}
}
}
});
}
catch
{
// Nothing
}
}
protected void
Button_Ok_Click(object sender, EventArgs e)
{
try
{
SPListItem spListItem = SPContext.Current.ListItem;
if (spListItem.ParentList.ContentTypes[SPBuiltInContentTypeId.SummaryTask] != null)
{
spListItem.ParentList.ContentTypes.Delete(SPBuiltInContentTypeId.SummaryTask);
}
if (spListItem.ParentList.ContentTypes[SPBuiltInContentTypeId.Task] != null)
{
spListItem.ParentList.ContentTypes.Delete(SPBuiltInContentTypeId.Task);
}
spListItem["PercentComplete"]
= 1F;
spListItem.Update();
CloseForm();
}
catch
{
// Nothing
}
}
protected void
Button_Cancel_Click(object sender, EventArgs e)
{
SPListItem spListItem = SPContext.Current.ListItem;
spListItem["PercentComplete"]
= 0;
spListItem.Update();
CloseForm();
}
private void
CloseForm()
{
if ((SPContext.Current
!= null) && SPContext.Current.IsPopUI)
{
this.Context.Response.Write("<script type='text/javascript'>window.frameElement.commitPopup();</script>");
this.Context.Response.Flush();
this.Context.Response.End();
}
else
{
string str = this.Page.Request.QueryString["Source"];
if ((str != null)
&& (str.Length > 0))
{
SPUtility.Redirect(string.Empty, SPRedirectFlags.UseSource,
this.Context);
}
}
}
}
}
Cut CustomFormTaskList.aspx from Layouts Folder to Form
module
Create new basic workflow
Right to Project | Add New Item | Sequential Workflow | Name
is MSTechSharing_TaskFormASPX_Workflow
Choose List Workflow (image 40)
Uncheck as below image
Design workflow as follow
Configurate properties for createTaskWithContentType1 (reference
how to create workflow sequential at
here
part How to create workflow approval)
Configure properties for onTaskChanged1
Configure properties for logToHistoryListActivity1
Double click to createTaskWithContentType1
Paste code to createTaskWithContentType1_MethodInvoking
(note: ID content type of list task is same)
private void
createTaskWithContentType1_MethodInvoking(object
sender, EventArgs e)
{
createTaskWithContentType1_TaskId1 = Guid.NewGuid();
createTaskWithContentType1_ContentTypeId1 = "0x0108010059177a2760644cd3b054dd3f929e0380";
createTaskWithContentType1_TaskProperties1.AssignedTo
= "win-67038mbkel7\\administrator";
createTaskWithContentType1_TaskProperties1.Title = "Custom From ASPX Task List ";
}
Double click to onTaskChanged1
paste code to onTaskChanged1_Invoked
private void
onTaskChanged1_Invoked(object sender, ExternalDataEventArgs e)
{
onTaskChanged1_AfterProperties1.PercentComplete = 1F;
}
//All Code
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Drawing;
using System.Linq;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Workflow;
using Microsoft.SharePoint.WorkflowActions;
namespace BasicWFASPXTaskForm.BasicWFASPXTaskForm_Workflow
{
public sealed partial class BasicWFASPXTaskForm_Workflow : SequentialWorkflowActivity
{
public BasicWFASPXTaskForm_Workflow()
{
InitializeComponent();
}
public Guid
workflowId = default(System.Guid);
public SPWorkflowActivationProperties
workflowProperties = new SPWorkflowActivationProperties();
public Guid
createTaskWithContentType1_TaskId1 = default(System.Guid);
public SPWorkflowTaskProperties
createTaskWithContentType1_TaskProperties1 = new
Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();
public String
createTaskWithContentType1_ContentTypeId1 = default(System.String);
public SPWorkflowTaskProperties
onTaskChanged1_AfterProperties1 = new
Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();
public SPWorkflowTaskProperties
onTaskChanged1_BeforeProperties1 = new
Microsoft.SharePoint.Workflow.SPWorkflowTaskProperties();
private void
createTaskWithContentType1_MethodInvoking(object
sender, EventArgs e)
{
createTaskWithContentType1_TaskId1 = Guid.NewGuid();
createTaskWithContentType1_ContentTypeId1 = "0x01080100349325c1e86c4e8c992a9a1c041fbcd1";
createTaskWithContentType1_TaskProperties1.AssignedTo = "win-67038mbkel7\\administrator";
createTaskWithContentType1_TaskProperties1.Title = "Custom ASPX From Task List";
}
private void
onTaskChanged1_Invoked(object sender, ExternalDataEventArgs e)
{
onTaskChanged1_AfterProperties1.PercentComplete = 1F;
}
}
}
//////////////////////////////////// ***End All Code
***////////////////////////////////////
Open file Element.xml of Workflow and change as follow (image 50)
Create new Event Receiver to call workflow run when add content type item
delete Feature2 when workflow was created (no require)
Open Feature1 change scope from web to site
Move feature workflow to right
Right click to Feature1 | Add Event Receiver
Using : using Microsoft.SharePoint.Workflow;
and declare 3 variable
private string
_workflowName = "MSTechSharing_TaskFormASPX -
MSTechSharing_TaskFormASPX_Workflow";
private string
_contentTypeName = "MSTechSharing_TaskFormASPX
- MSTechSharing_TaskFormASPX_ContentTypeTargetList";
private string
nameWorkflowOnContentType = "Wf
CustomASPXTaskForm";
////////////////////////////////////// *** All code ***
//////////////////////////////////////
using System;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Security;
using Microsoft.SharePoint.Workflow;
namespace MSTechSharing_TaskFormASPX.Features.Feature1
{
/// <summary>
/// This class handles
events raised during feature activation, deactivation, installation,
uninstallation, and upgrade.
/// </summary>
/// <remarks>
/// The GUID attached to
this class may be used during packaging and should not be modified.
/// </remarks>
[Guid("c52f6eae-fc7e-47a5-89e1-3b2b0fa32c2b")]
public class Feature1EventReceiver : SPFeatureReceiver
{
private string
_workflowName = "MSTechSharing_TaskFormASPX -
MSTechSharing_TaskFormASPX_Workflow";
private string
_contentTypeName = "MSTechSharing_TaskFormASPX
- MSTechSharing_TaskFormASPX_ContentTypeTargetList";
private string
nameWorkflowOnContentType = "Wf
CustomASPXTaskForm";
public override void FeatureActivated(SPFeatureReceiverProperties
properties)
{
using (SPSite site
= ((SPSite)properties.Feature.Parent))
{
using (SPWeb
web = site.OpenWeb())
{
SPContentType theCt =
web.ContentTypes[_contentTypeName];
SPWorkflowTemplate theWf = null;
foreach (SPWorkflowTemplate
tpl in web.WorkflowTemplates)
{
if (tpl.Name == _workflowName)
{
theWf = tpl;
}
}
SPWorkflowAssociation wfAssociation =
theCt.WorkflowAssociations.GetAssociationByName(nameWorkflowOnContentType,
web.Locale);
if (wfAssociation != null)
{
theCt.WorkflowAssociations.Remove(wfAssociation);
}
theCt.UpdateWorkflowAssociationsOnChildren(true,
true, true, false);
// Name of workflow on ContentType that is
associated to definition workflow
wfAssociation = SPWorkflowAssociation.CreateWebContentTypeAssociation(theWf,
nameWorkflowOnContentType, "Task
MSTechSharing_TaskFormASPX", "History
MSTechSharing_TaskFormASPX");
wfAssociation.AutoStartCreate = true;
wfAssociation.AutoStartChange = true;
if
(theCt.WorkflowAssociations.GetAssociationByName(wfAssociation.Name, web.Locale)
== null)
{
theCt.WorkflowAssociations.Add(wfAssociation);
}
else
{
theCt.WorkflowAssociations.Update(wfAssociation);
}
theCt.UpdateWorkflowAssociationsOnChildren(true,
true, true, false);
}
}
}
// Uncomment the method below to handle the event raised
before a feature is deactivated.
public override void
FeatureDeactivating(SPFeatureReceiverProperties
properties)
{
using (SPSite site
= ((SPSite)properties.Feature.Parent))
{
using (SPWeb
web = site.OpenWeb())
{
SPContentType theCt =
web.ContentTypes[_contentTypeName];
SPWorkflowAssociation wfAssociation =
theCt.WorkflowAssociations.GetAssociationByName(_workflowName, web.Locale);
if (wfAssociation != null)
{
theCt.WorkflowAssociations.Remove(wfAssociation);
}
theCt.UpdateWorkflowAssociationsOnChildren(true,
true, true, false);
}
}
}
// Uncomment
the method below to handle the event raised after a feature has been installed.
//public override void
FeatureInstalled(SPFeatureReceiverProperties properties)
//{
//}
// Uncomment the method below to handle the event raised
before a feature is uninstalled.
//public override void
FeatureUninstalling(SPFeatureReceiverProperties properties)
//{
//}
// Uncomment the method below to handle the event raised
when a feature is upgrading.
//public override void
FeatureUpgrading(SPFeatureReceiverProperties properties, string
upgradeActionName, System.Collections.Generic.IDictionary<string, string>
parameters)
//{
//}
}
}
////////////////////////////////////// *** End All code ***
//////////////////////////////////////
Deploy project, you see list definition was created as
follows
Create new item
Workflow run automatically
Edit Item
Appear ASPX form in list Task
After approve (OK) status of workflow is completed
Note:
Error can not Add solution => change name of content type
Error can not Actived solution => change Name WF, Name
content type in event receiver same with in xml file of workflow and content
type target list
Error failing in started => insert ContentType;# to <AssociationCategories>ContentType;#List</AssociationCategories>
Error can not display Form ASPX=> delete List contain
that Form then deploy