Posted 10/28/2013 by asura
We recently got a requirement where the client wanted to store more than just a comment when a workflow item is approved or denied. So we built a proof of concept.
Truthfully, if the client were to implement this, I would want to use item buckets to store the values (based on a template) and store the item’s GUID in place of the comments (GUID:{81FEEE94-5A2F-4629-A791-4F25E69C75B1}). This would need customization of the whole Work Box. We will reassess this when the client gives the go ahead.
As per the proof of concept, I ended up just storing the delimited string in the comments. It does not look that bad since it only has 3 fields but if we were to store multiple fields of different data types it would get messy.
A standard workflow item approval/rejection will prompt you with the box similar to what is shown below:
I modified it to the one shown below:
The fields you see in the dialog are for DEMO purposes only. The actual fields used in the proof of concept were from the client’s standard workflow process and had to meet their guidelines.
Step 1 – Override
To implement this we need to override the functionality in Workbox.xml. To do this, create the following folders under WebsitesitecoreshellOverride folder:
- Applications
Copy Workbox.xml from WebsitesitecoreshellApplicationsWorkbox
To
WebsitesitecoreshellOverrideApplicationsWorkbox
Step 2 – Code Behind
Use a refactor tool like the .NET Reflector or JetBrains dotPeek to decompile Sitecore.Client and grab code for Sitecore.Shell.Applications.WorkboxForm.
Add a WorkboxForm class in your BL or Sitecore Extensions project to mirror the Sitecore.Shell.Applications.Workbox.WorkboxForm class.
Step 3 – CodeBeside
Modify the Workbox.xml file in the override folder to replace the value in the CodeBeside tag.
Step 4 – Create Custom Dialog Layout
We will create a XAML interface using an XML Layout.
- Switch to Core
- Open Dev Center
- Create new file of type CML Layout
- Name the file Workflow Info
- Select the LayoutsDialogs location and click next
- Select file location as you choose (Layouts) and click next
- Click finish
Step 4 – XAML
Once the Layout file is created use the following code to define the interface elements.
Step 5 – Dialog CodeBeside
Create a new class in your BL or SitecoreExtensions project called WorkflowInfo. We are going to define two events as shown below:
using Sitecore.Web.UI.Pages; using Sitecore.Web.UI.Sheer; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Sitecored7.Business.Workflow { public class WorkflowInfo : DialogForm { protected Sitecore.Web.UI.HtmlControls.Edit CRB; protected Sitecore.Web.UI.HtmlControls.Edit Release; protected Sitecore.Web.UI.HtmlControls.Edit Comments; protected override void OnLoad(EventArgs e) { base.OnLoad(e); } protected override void OnOK(object sender, EventArgs args) { //Write the response value that will be available to the Workbox Form var xml = string.Format("CRB:{0};Release:{1};Comments:{2};", CRB.Value, Release.Value, Comments.Value); SheerResponse.SetDialogValue(xml); base.OnOK(sender, args); } } }
As you can see in the OnOK event, we format the values from the interface elements and pass it back to the caller.
Step 6 – Back to Core
While in Core db via Sitecore admin console, navigate tot sitecorecontentApplicationsDialogs and create an item of type Folder, name it Workflow Info.
Set the layout on this item to LayoutsDialogsWorkflow Info
Step 7 – Magic
In the WorkboxForm class in your code, locate the Comment method. Comment out the Enter a comment line as shown highlighted in the code below and replace it with the line 15 – 19.
/// /// Comments the specified args. ///
/// /// The arguments. /// public void Comment(ClientPipelineArgs args) { Assert.ArgumentNotNull(args, “args”); if (!args.IsPostBack) { //Context.ClientPage.ClientResponse.Input(“Enter a comment:”, string.Empty); //args.WaitForPostBack(); //get core db var db = Sitecore.Data.Database.GetDatabase(“core”); //get the dialog item we created under applications var item = db.GetItem(Sitecored7.Utils.Constants.ItemsID.WorkFlowInfoDialog); //get dialog link var url = new UrlString(LinkManager.GetItemUrl(item)); //display Modal and wait for the post back Sitecore.Context.ClientPage.ClientResponse.ShowModalDialog(url.ToString(), true); args.WaitForPostBack(); return; } if (args.Result.Length > 2000) { Context.ClientPage.ClientResponse.ShowError(new Exception(string.Format(“The comment is too long.nnYou have entered {0} characters.nA comment cannot contain more than 2000 characters.”, args.Result.Length))); Context.ClientPage.ClientResponse.Input(“Enter a comment:”, string.Empty); args.WaitForPostBack(); return; } if (args.Result != null && args.Result != “null” && args.Result != “undefined”) { IWorkflowProvider workflowProvider = Context.ContentDatabase.WorkflowProvider; if (workflowProvider != null) { IWorkflow workflow = workflowProvider.GetWorkflow(Context.ClientPage.ServerProperties[“workflowid”] as string); if (workflow != null) { ItemRecords items = Context.ContentDatabase.Items; object item = Context.ClientPage.ServerProperties[“id”]; object empty = item; if (item == null) { empty = string.Empty; } Item item1 = items[empty.ToString(), Language.Parse(Context.ClientPage.ServerProperties[“language”] as string), Sitecore.Data.Version.Parse(Context.ClientPage.ServerProperties[“version”] as string)]; if (item1 != null) { try { workflow.Execute(Context.ClientPage.ServerProperties[“command”] as string, item1, args.Result, true, new object[0]); } catch (WorkflowStateMissingException workflowStateMissingException) { SheerResponse.Alert(“One or more items could not be processed because their workflow state does not specify the next step.”, new string[0]); } UrlString urlString = new UrlString(WebUtil.GetRawUrl()); urlString[“reload”] = “1”; Context.ClientPage.ClientResponse.SetLocation(urlString.ToString()); } } } } }
And that is it. If you have any questions or need the source, email me at Akshay dot sura at nttdata dot com.