In Skelta BPM.Net 2009 they introduced dynamic form, we can design our required dynamic forms and attach with workflow in form of Invoke Form activity, it is very nice feature from Skelta but it has own fence. Here we have two types of forms one is workflow initiator form and another one is normal action forms, even we have two types based on whether the form created on Skelta List(Form mapper to table) or not.
This section explains about how to render an action form (custom ASPX web form for Invoke Form Activity) on an ASPX web form and submit the work item. In my previous article I explained about how to render a workflow initiator form, refer it if you already not.
Let’s Get StartedIn order to achieve our goal we need to do following process steps,
- Get metadata information for Action Form
- Get Form Input variable value
- Get the Form Definition
- Render the Form Renderer
- Submit the work item
Normally action forms are triggered from Skelta work list with a secured parameter, this parameter contains all required metadata about current work item, and form but this parameter encrypted to share it across pages, so we have to decrypt params before using it, here Skelta provides a adapter class to help us on this process, the adapter class is WebWorkItemAdapter.
Code snippet for processing secured parameter.
WebWorkItemAdapter webAdapter = new WebWorkItemAdapter(); webAdapter.ProcessWebChannelRequest();
Now we decrypted and initialized the WebWorkItemAdapter object from that we can get the instance for current work item and form name other details, the following code snippet help us to get the work item and form.
this.workitem = webAdapter.CurrentWorkItem; //Get the Form Name with FormID from current invoke form activity this.strName = this.workitem.CurrentActivity.Properties["FormDetails"].Value.ToString(); //Modify this code according your user provider //Initilaize the user context object with desired user provider Skelta.Entity.UserContext usrContext = new Skelta.Entity.UserContext(intUserId.ToString(),new ApplicationObject(this.webAdapter.ApplicationName), "sqlprovider", "", "", false); //parse the form details string[] strArray = this.strName.Split(new char[] { '?' }); //get the from name this.FormName = strArray[0]; //Get the id of form this.id = new Guid(strArray[2].ToString());Get Input Instance XML Value:
Action Form not like Workflow Initiator Form because action form can have the initial state and we must fill the required values before rendering it but in case of workflow initiator not required, but some cases it requires. Before filling values into form we need to get input xml variable name and its value, we can use following code snippet for getting input xml variable name and value.
this.inputvalue = this.workitem.CurrentActivity.Properties["InputInstanceXML"].Value.ToString(); this.inputxml = this.workitem.CurrentContext.XmlVariables[this.inputvalue].RawXml.ToString();
Once we got the value for input xml variable we can assign it to form renderer, refer the following code to assign value to xml variable.
this.fmrViewForm.FormDefinition.FormInstanceXml = this.inputxml;Form Definition:
Before rendering the given form on Form Renderer we need to get form definition object otherwise form render can’t render the given form. We can get form definition object by using below code snippet.
ListDefinition lstDef = ListDefinition.GetList(this.appObject, this.listParams.ListName); this.frmItem = new Skelta.Repository.List.ListItem(lstDef, this.listParams.ListItemId, this.listParams.VersionStamp); ListTableForm frmTable = (ListTableForm)this.frmItem.ListForm.FindById("_sys_fmdef_new"); string strDef = Convert.ToString(((ListTextDataItem)frmTable.Records[0].FindControlByID("_sys_def_xml")).Value); if (string.IsNullOrEmpty(strDef)) { //Show error message or thorw exception here if you required throw new Exception("Blank Form Definition"); Response.End(); } BaseForm frmBase = BaseForm.LoadDefinitionXml(strDef); frmBase.TopLevelForm.FormAssociatedItemID = this.frmItem.Id.ToString(); return frmBase;
First we need to get the Skelta List definition for Forms List (Skelta is a generic master list to access all created Skelta elements for a repository each Skelta elements have their own list definition based on this definition Skelta List will display the master list). Based on this Forms List definition we can get ListItem object for given Form, by digging this list item we can get Form definition raw xml from _sys_def_xml system property. Finally convert this raw xml to BaseForm instance; this is Skelta API representation for Form Renderer.
Consolidated code snippet for Form Definition as follows,
///Form Rendering:/// Get Form definition for given Skelta form /// ///Form Definition object private BaseForm GetFormDefinitionXml() { try { bool isFlag = false; ListDefinition lstDef = ListDefinition.GetList(this.appObject, this.listParams.ListName); this.frmItem = new Skelta.Repository.List.ListItem(lstDef, this.listParams.ListItemId, this.listParams.VersionStamp); ListTableForm frmTable = (ListTableForm)this.frmItem.ListForm.FindById("_sys_fmdef_new"); string strDef = Convert.ToString(((ListTextDataItem)frmTable.Records[0].FindControlByID("_sys_def_xml")).Value); if (string.IsNullOrEmpty(strDef)) { //Show error message or thorw exception here if you required throw new Exception("Blank Form Definition"); Response.End(); } BaseForm frmBase = BaseForm.LoadDefinitionXml(strDef); frmBase.TopLevelForm.FormAssociatedItemID = this.frmItem.Id.ToString(); return frmBase; } catch { return null; } }
Now we are ready for rendering action form on web form but before rendering from we need to update the form parameters like execution id, execution details id, current context and current activity, we can update these information with following code snippet.
this.UpdateFormParameters(this.adapter.CurrentWorkItem.ExecutionId, this.adapter.CurrentWorkItem.ExecutionDetailsId, this.adapter.CurrentWorkItem.CurrentContext, this.adapter.CurrentWorkItem.CurrentActivity);
Refer the following snippet to render the action form on a web form.
////// Handle Page Initialize event /// /// event argument</param> protected override void OnInit(EventArgs e) { try { try { if (Session["UserInfo"] != null) usrInfo = Session["UserInfo"] as DotNetNuke.Entities.Users.UserInfo; //System.Diagnostics.Debugger.Break(); //usrContext = new Skelta.Entity.UserContext(usrInfo.UserID.ToString(), new Skelta.Core.ApplicationObject(ConfigurationSettings.AppSettings["KIBApplicationName"]), "sqlprovider", "", "", false); this.adapter.ProcessWebChannelRequest(); this.adapter.CurrentWorkItem.GetFormInstanceData(this.adapter.ChannelName, this.adapter.FormName, out this.formuri, out this.formstate); this.listParams.ProcessWebChannelRequest(); this.workitem = this.listParams.CurrentWorkItem; this.strname = this.workitem.CurrentActivity.Properties["FormDetails"].Value.ToString(); Skelta.Entity.UserContext usrContext = new Skelta.Entity.UserContext(usrInfo.UserID.ToString(),new ApplicationObject(this.adapter.ApplicationName), "sqlprovider", "", "", false); if (!string.IsNullOrEmpty(this.workitem.Subject)) { this.strsubject = this.workitem.Subject.ToString(); } string[] strArray = this.strname.Split(new char[] { '?' }); this.FormName = strArray[0]; this.strFormName = this.FormName; this.version = strArray[1]; this.strid = strArray[2].ToString(); this.id = new Guid(strArray[2].ToString()); this.actionname = strArray[3].ToString(); this.inputvalue = this.workitem.CurrentActivity.Properties["InputInstanceXML"].Value.ToString(); this.outputvalue = this.workitem.CurrentActivity.Properties["OutputInstanceXML"].Value.ToString(); this.fmrViewForm = new FormRenderer(); if (this.formstate == "") { if (this.inputvalue != "") { this.inputxml = this.workitem.CurrentContext.XmlVariables[this.inputvalue].RawXml.ToString(); } if (this.outputvalue != "") { this.outputxml = this.workitem.CurrentContext.XmlVariables[this.outputvalue].RawXml.ToString(); } } this.IsSaveAsDraft = this.workitem.CurrentActivity.Properties["SaveAsDraft"].Value.ToString(); } catch (Exception exception) { //this.workitem.CurrentContext.log.LogError(exception, "Error while getting properties", !string.IsNullOrEmpty(this.adapter.ApplicationName) ? this.adapter.ApplicationName : ""); } if (!string.IsNullOrEmpty(this.strname) || (this.formstate != "")) { if (this.IsSaveAsDraft.ToLowerInvariant() == "yes") { this.fmrViewForm.ShowSaveAsDraftLink = true; } this.fmrViewForm.FormDefinition = this.GetFormDefinitionXml(); if (!this.iFormNotFound) { this.fmrViewForm.FormDefinition.FormAssociatedItemID = this.id.ToString(); if (!base.IsPostBack) { if ((this.inputxml == "") || (this.outputxml == "")) { if (this.formstate != "") { this.fmrViewForm.FormDefinition.FormInstanceXml = this.formstate; } else if (this.inputxml != "") { this.fmrViewForm.FormDefinition.FormInstanceXml = this.inputxml; } else if (this.GetFormInstanceXml() != null) { this.fmrViewForm.FormDefinition.FormInstanceXml = this.GetFormInstanceXml(); } } else if (this.outputxml == "") { this.fmrViewForm.FormDefinition.FormInstanceXml = this.inputxml; } else if (this.inputxml != "") { this.fmrViewForm.FormDefinition.FormInstanceXml = this.inputxml; } else { this.fmrViewForm.FormDefinition.FormInstanceXml = this.outputxml; } if ((this.inputvalue == "") && (this.formstate == "")) { this.fmrViewForm.FormDefinition.FormInstanceXml = ""; } } try { this.UpdateFormParameters(this.adapter.CurrentWorkItem.ExecutionId, this.adapter.CurrentWorkItem.ExecutionDetailsId, this.adapter.CurrentWorkItem.CurrentContext, this.adapter.CurrentWorkItem.CurrentActivity); } catch { } //this.lblFormRender.Visible = false; this.fmrViewForm.HeaderHidden = true; this.fmrViewForm.InDesignMode = false; this.fmrViewForm.OnSaveClick += new SaveClickDelegate(this.fmrViewForm_OnSaveClick); this.pnlFormRender.Controls.Add(fmrViewForm); } } } catch { } }
So far we filled the value to form and render the form on given web form, now it is waiting for user inputs.
When user clicks on submit button we need to transfer the form data to workflow, normally here we will pass the current from state. Incase if you want to submit some extra values than from instance xml you can it. Refer the following code snippet for form submission.
////// Handle the Form Submit event /// /// event publisher</param> /// event argument</param> protected void fmrViewForm_OnSaveClick(object sender, SaveClickEventArgs e) { //Its optional, if you are using CurrentActor xml variable then you uncomment following lines of code //try //{ // XmlVariable xmlCurrentActor = this.workitem.CurrentContext.XmlVariables["CurrentActor"]; // if (xmlCurrentActor != null) // { // xmlCurrentActor.RawXml = usrInfo.GetSkeltaUserContextXml(); // xmlCurrentActor.Save(); // } //} //catch { } this.webAdapter.ProcessWebChannelRequest(); string channelName = this.webAdapter.ChannelName; string formName = this.webAdapter.FormName; if (e.IsFromSaveAsDraftLink) { this.webAdapter.CurrentWorkItem.SetStateForFormInstance(channelName, formName, this.fmrViewForm.FormDefinition.FormInstanceXml); e.ResponseScripts.Add("alert('" + this.sklResMgr.GlobalResourceSet.GetString("FormSaveDraftContentAlert") + "');"); if (this.webAdapter.CurrentWorkItem.CurrentActivity.Properties.Contains("CloseOnSaveAsDraft") && (this.webAdapter.CurrentWorkItem.CurrentActivity.Properties["CloseOnSaveAsDraft"].Value.ToString().ToLowerInvariant() == "yes")) { e.ResponseScripts.Add("window.parent.close();"); } } else { try { bool flag = false; if (this.webAdapter.CurrentWorkItem.Status != "CO") { string currentStatus = ""; if (this.webAdapter.CurrentWorkItem.Actor == null) { Actor actor = new Actor(new ApplicationObject(this.webAdapter.CurrentWorkItem.Application.ApplicationName), this.webAdapter.LoggedInActor.Id); WorkItem item = this.webAdapter.CurrentWorkItem.PickItem(actor); currentStatus = e.ButtonText; string formInstanceXml = this.fmrViewForm.FormDefinition.FormInstanceXml; string comments = "Acted on " + currentStatus + " button."; SynchronousActionData syncData = new SynchronousActionData(false, this.Context, true); item.Submit(this.webAdapter.ChannelName, currentStatus, "", comments, syncData, ref formInstanceXml); item.SetStateForFormInstance(channelName, formName, formInstanceXml); this.workitem = item; } else { currentStatus = e.ButtonText; string formInstanceStateXml = this.fmrViewForm.FormDefinition.FormInstanceXml; string str7 = "Acted on " + currentStatus + " button."; SynchronousActionData data2 = new SynchronousActionData(false, this.Context, true); this.webAdapter.CurrentWorkItem.Submit(this.webAdapter.ChannelName, currentStatus, "", str7, data2, ref formInstanceStateXml); this.webAdapter.CurrentWorkItem.SetStateForFormInstance(channelName, formName, formInstanceStateXml); } } else { e.ResponseScripts.Add("alert('" + this.sklResMgr.GlobalResourceSet.GetString("FormAlreadySavedAlert") + "');"); flag = true; } if (this.fmrViewForm.FormDefinition.FindControlByName("hidWinParent") != null) { e.ResponseScripts.Add("if( window.parent.opener.external != null ) window.parent.opener.external.CallParentEvent('" + e.ButtonText + "', '');"); } if ((base.Request["type"] != null) && (base.Request["type"].ToString().ToLowerInvariant().Trim() == "mail")) { if (!flag) { if (this.webAdapter.CurrentWorkItem.CurrentActivity.Properties.Contains("CloseOnFormSubmit")) { if (this.webAdapter.CurrentWorkItem.CurrentActivity.Properties["CloseOnFormSubmit"].Value.ToString().ToLowerInvariant() == "yes") { e.ResponseScripts.Add("window.parent.close();"); } else { e.ResponseScripts.Add("alert('" + this.sklResMgr.GlobalResourceSet.GetString("FormSavedAlert") + "');"); } } else { e.ResponseScripts.Add("alert('" + this.sklResMgr.GlobalResourceSet.GetString("FormSavedAlert") + "');"); } } } else { if (!flag) { e.ResponseScripts.Add("alert('Form submitted successfully.');"); } e.ResponseScripts.Add("CloseInvokeFormWorkItemWindow()"); } } catch (Exception exception) { Log logger = new Log(); logger.LogError(exception, "Error", !string.IsNullOrEmpty(this.listParams.ApplicationName) ? this.listParams.ApplicationName : ""); if (exception.Message.ToLowerInvariant().Trim() == "could not connect to the workflow engine. make sure that the workflow engine is running.") { this.webAdapter.CurrentWorkItem.SetStateForFormInstance(channelName, formName, this.fmrViewForm.FormDefinition.FormInstanceXml); e.ResponseScripts.Add("alert('" + this.sklResMgr.GlobalResourceSet.GetString("Engine_StoppedWithSaveAsDraft") + "');"); } else { e.ResponseScripts.Add("alert('" + exception.Message + "');"); } logger.Close(); logger.Dispose(); } (sender as FormRenderer).SaveCurrentFormAttachmentsWithDetails(this.workitem.ExecutionId, this.workitem.CurrentContext.WorkflowName, this.workitem.HWSActivity.Id, null); } }
Here we have two types submission one is normal ,it is simply submit the work item another one is it will submit the work item and it will retrieve some values form engine. You can use either one. Recently I created the Starter Kit for Skelta called as Smart Skelta Starter Kit for 2008, you can download it from http://smartskelta.codeplex.com. In this kit you can able to find out Action form from Item templates of Web Site.
Conclusion:So far we learned how to render a action form and initiating the associated workflow. I hope this article given some idea about custom action form web form. Send your valuable feedbacks to eshock.vasan@gmail.com.
Labels
Popular Posts
About
About
Follow us
Popular Posts
-
In this article I am going to explain how to dynamically display all available process templates (Skelta forms which associated with a workf...
-
The main feature of any workflow engine is tracking the histories of transactions for its process flows, normally all workflow engines will ...
-
Skelta provides the feature to initiate a workflow from a Skelta form by associating it. In Skelta Enterprise Console they given the provisi...
-
Recently I created one control library in C#.Net for Windows application. In this section we going to see how to use it. Smart Hot key handl...
-
Visual Studio providing a feature called Custom Template to create our own project templates(Web,Windows etc,.) and Item templates(Web Form,...
-
In Skelta BPM.Net 2009 they introduced dynamic form, we can design our required dynamic forms and attach with workflow in form of Invoke For...