Create Custom Wizards
- Last UpdatedJun 10, 2024
- 9 minute read
AVEVA Work Tasks provides a set of interfaces and their supporting classes and members that can be implemented in the class of a custom activity to create a custom wizard. The following procedure creates an Email Wizard that is available in the Process Designer in the menu bar as well as under the Wizard category in the activities tool box.
PROCEDURE
Dll REFERENCE
System
System.Data
System.XML
System.DirectoryServices
Workflow.NET.NET2
NAMESPACE USED
System
System.Collections.Generic
System.Text
Skelta.Wizards.Core.Interfaces
Workflow.NET
Skelta.Core
System.ComponentModel
Skelta.Wizards.Core
System.XML
The following steps and code illustrate the creation of a custom email wizard. The custom email wizard is listed in the AVEVA Work Tasks Wizards window.
Step 1:
-
Create a new project of type class library and name as CustomWizards.
-
Add a reference to Skelta.Wizards.Core.dll and Workflow.NET.NET2.dll.
-
Add a new class file called EmailWizard.cs. This class file should implement the interface IWizard and ISkeltaAddInProvider.
-
Implement the functions as follows.
using System;
using System.Collections.Generic;
using System.Text;
using Skelta.Wizards.Core.Interfaces;
using Workflow.NET;
using Skelta.Core;
using System.ComponentModel;
using Skelta.Wizards.Core;
using System.Xml;
namespace CustomWizards
{
public class EmailWizard : IWizard ,ISkeltaAddInProvider
{
///Constructor defining the outputs of the wizard and setting the title and description
///properties of the wizard
public EmailWizard()
{
_Outputs.Add("Sent");
_Outputs.Add("Not Sent");
_Description ="EmailWizard Description";
_Title = "Email Wizard";
}
#region IWizard Members
///Implementing the Category property of the interface
private string _Category;
public string Category
{
get { return _Category; }
}
//Implementing the Description property of the interface
private string _Description = string.Empty;
public string Description
{
get { return _Description; }
set { _Description = value; }
}
///Implementing the Display Name property of the interface
private string _DisplayName = string.Empty;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public string DisplayName
{
get { return _DisplayName; }
set { _DisplayName = value; }
}
//Implementing the Favorites property of the interface
private Dictionary<string, string> _Favourites = new Dictionary<string, string>();
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public Dictionary<string, string> Favourites
{
get { return _Favourites; }
set { _Favourites = value; }
}
///Implementing the GetDiagram method of the interface for creating Actions and Links and dumping the same into process designer
public void GetDiagram(Diagram diagram, Workflow.NET.Action previousAction, string output)
{
Workflow.NET.Action startAction = diagram.Actions["Start"];
if (previousAction == null)
{
previousAction = startAction;
output = string.Empty;
}
string email1ActivityName = string.Empty;
while (true)
{
email1ActivityName = ActivityNamingContainer.Instance.GetName("Email");
if (!diagram.Actions.ContainsKey(email1ActivityName))
break;
}
Workflow.NET.Action emailAction = Utilities.CreateAction(diagram,
previousAction.ProcessDefinition.ActionsDefinition, "Email", email1ActivityName, "Email",
previousAction, string.Empty);
emailAction.Description = "Email";
//setting the properties of the Email Activity i.e. From,To etc
(emailAction.Properties["From"] as Property).Value = new
Workflow.NET.Config(diagram.ApplicationName, diagram.WorkflowName).FromEmailAddress;
(emailAction.Properties["To"] as Property).Value = Utilities.GetResourceFilter(diagram.ActionsDefinition, this._To);
(emailAction.Properties["Subject"] as Property).Value = this._Subject;
(emailAction.Properties["Body"] as Property).Value = this._Body;
Utilities.CreateLink(diagram, previousAction, emailAction, "Reminder");
CreateChildDiagrams(diagram, emailAction);
}
///Implementing the CreateChildDiagrams method of the interface
///Creating the diagram from the outputs of an action
protected void CreateChildDiagrams(Workflow.NET.Diagram diagram, Workflow.NET.Action previousAction)
{
foreach (string key in _Outputs)
{
WizardActionTypes wizardActionType = _OutputActions[key].ActionType;
switch (wizardActionType)
{
case WizardActionTypes.LinkToWizard:
_OutputActions[key].NextWizard.GetDiagram(diagram, previousAction, key);
break;
case WizardActionTypes.LinkToTemplate:
_OutputActions[key].NextTemplate.GetDiagram(diagram, previousAction, key);
break;
case WizardActionTypes.LinkToActivity:
Utilities.CreateLink(diagram, previousAction.Name,
_OutputActions[key].NextActivity, key);
break;
case WizardActionTypes.NoLink:
break;
}
}
}
///Implementing the GetWebUIServerControl method of the interface
///To get the name of the UI control of the wizard
public string GetWebUIServerControl
{
get { return "EmailWizardUI.ascx"; }
}
///Implementing the ImageName property of the interface
private string _ImageName;
public string ImageName
{
get { return _ImageName; }
}
///Implementing the IsNewUIInstance property of the interface
///Checks whether this is a new instance of the wizard
private bool _IsNewUIInstance = true;
public bool IsNewUIInstance
{
get
{
return _IsNewUIInstance;
}
set
{
_IsNewUIInstance = value;
}
}
///Implementing the IsStartupWizard property of the interface
///Checks whether the wizard is a startupwizard ie one that is ///used only for provisioning variables
private bool _IsStartupWizard = true;
public bool IsStartupWizard
{
get { return _IsStartupWizard; }
}
///Implementing the Name property of the interface
public string Name
{
get { return "EmailWizard"; }
}
///Implementing the OutputActions property of the interface
///Each wizard has a collection of output actions
/// eg LinkToWizard , LinkToTemplate which is specified in the ///Linking page
Dictionary<string, WizardAction> _OutputActions = new Dictionary<string, WizardAction>();
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public Dictionary<string, WizardAction> OutputActions
{
get { return _OutputActions; }
}
///Implementing the Outputs property of the interface
///Each wizard has a collection of outputs eg in the case
///of Email Wizard the outputs are "Sent" and "Not Sent"
private List<string> _Outputs = new List<string>();
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public List<string> Outputs
{
get { return _Outputs; }
}
///Implementing the ParentId property of the interface
///Each wizard may or may not have a parent wizard which referred ///it . This property returns the id of that parent wizard
private Guid _ParentId;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public Guid ParentId
{
get { return _ParentId; }
set { _ParentId = value; }
}
///Implementing the SelectedIndex property of the interface
///Returns the selected index of the selected output of the ///wizard
private int _SelectedIndex = -1;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public int SelectedIndex
{
get
{
return _SelectedIndex;
}
set
{
_SelectedIndex = value;
}
}
///Implementing the SelectedOutput property of the interface
///Returns the selected output of the wizard
public string SelectedOutput
{
get { return _Outputs[_SelectedIndex]; }
}
///Implementing the TemplateUniqueId property of the interface
///Returns the id of the template of which this wizard is linked ///to
private Guid _templateUniqueId;
public Guid TemplateUniqueId
{
get { return _templateUniqueId; }
set { _templateUniqueId = value; }
}
///Implementing the Title property of the interface
///Returns the title of the wizard
private string _Title = string.Empty;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public string Title
{
get { return _Title; }
set { _Title = value; }
}
///Implementing the UniqueId property of the interface
private Guid _uniqueId;
public Guid UniqueId
{
get { return _uniqueId; }
set { _uniqueId = value; }
}
#endregion
#region ISkeltaAddInProvider Members
///Implementing the Id property of the interface
private Guid _Id;
public Guid Id
{
get { return _Id; }
}
///Implementing the InitializeProvider property of the interface
///Takes the appropriate row from the SKAddInProviders table
///and gets the "SettingsXml" column value
public void InitializeProvider(string settings, Guid id)
{
this._Settings = settings;
this._Id = id;
if (_Settings != string.Empty)
{
//Setting Favourites from xml
XmlDocument xmldoc = new XmlDocument();
xmldoc.LoadXml(_Settings);
/*This is the XML SCHEMA for 'Settings' Field in the table 'SKAddInProviders'
<Wizard>
<Category>
</Category>
<ImageName>
</ImageName>
<IsStartupWizard>
</IsStartupWizard>
<Favourties>
<FavouriteElement>
<FavouriteElement>
</Favourites>
</wizard> */
XmlNodeList _category1 = xmldoc.GetElementsByTagName("Category");
XmlNodeList _imagename1 = xmldoc.GetElementsByTagName("ImageName");
XmlNodeList _isstartupwizard1 = xmldoc.GetElementsByTagName("IsStartupWizard");
XmlNodeList _favourties1 = xmldoc.GetElementsByTagName("FavouriteElement");
if (_category1[0] != null)
_Category = _category1[0].InnerText;
if (_imagename1[0] != null)
_ImageName = _imagename1[0].InnerText;
if (_isstartupwizard1[0] != null)
_IsStartupWizard = Convert.ToBoolean(_isstartupwizard1[0].InnerText);
for (int i = 0; i < _favourties1.Count; i++)
_Favourites.Add("FavouriteElement_" + i, _favourties1[i].InnerText);
}
}
///Implementing the Settings property of the interface
///Manages the "SettingsXml" column value got from ///SKAddInProviders table
private string _Settings;
public string Settings
{
get { return _Settings; }
}
#endregion
///"To" Property defined for Email Wizard
private string _To = string.Empty;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public string To
{
get
{
return _To;
}
set
{
_To = value;
}
}
///"From" Property defined for Email Wizard
private string _From = string.Empty;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public string From
{
get
{
return _From;
}
set
{
_From = value;
}
}
///"Subject" Property defined for Email Wizard
private string _Subject = string.Empty;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public string Subject
{
get
{
return _Subject;
}
set
{
_Subject = value;
}
}
///"Body" Property defined for Email Wizard
private string _Body = string.Empty;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public string Body
{
get
{
return _Body;
}
set
{
_Body = value;
}
}
}
}
Note: If you wish to create a property whose value changes dynamically across wizards like the above Subject, Body etc then that property should be prefixed with the below piece of code "[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]" Otherwise if you prefer to use hard coded values, then prefix that property with the below piece of code to hide that property accordingly "[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]" . The above note is applicable during serialization and deserialization of data inside the Wizard Manager.
Step 2:
Build CustomWizards.dll and add the dll into the [AVEVA Work Tasks Installed Path]\AVEVA\Work Tasks\Bin folder
Step 3:
-
Create a new ASP Web application CustomWizardUI and add user control page called EmailWizardUI.ascx which is your UI for the email wizard.
-
Use the <asp:Wizard> control to define your wizard steps.
-
Hide the wizard navigation buttons.
//EmailWizardUI.ascx
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="EmailWizardUI.ascx.cs" Inherits="CustomWizardUI.EmailWizardUI" %>
<link href="styles/template-wizard.css" rel="stylesheet" type="text/css" />
<asp:Wizard ID="AspWizard" runat="server" ActiveStepIndex="0" Width="100%" DisplaySideBar="False" Height="100%">
<WizardSteps>
<asp:WizardStep ID="WizardStep1" runat="server" Title="Step 1" >
<table width="100%" align="center" cellpadding="0" cellspacing="0" border="0" >
<tr>
<td align="center" valign="top">
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td height="38" align="left" background="images/title-bar-bg.png">
<img src="images/visual-screen-title.png" width="39" height="38" hspace="4" align="absMiddle" />
<span class="runtext2-white">
Email Wizard
</span>
</td>
</tr>
<tr>
<td bgcolor="#378381" background="images/welcome-email-bg2.png" valign="top" align="left"
style="height: 131px">
<img src="images/icon-email-now.png" hspace="10" vspace="2" />
<span style="font-family:Segoe UI, Trebuchet MS; font-size:15pt; color:White;">Welcome to Email
Wizard</span>
</td>
</tr>
<tr>
<td align="center" valign="middle" bgcolor="#f0f0f0">
<br/><br/>
<table width="90%" border="0" cellpadding="4" cellspacing="2" bgcolor="#b9d1ea">
<tr>
<td align="left" valign="middle" bgcolor="#ffffff" class="runtext1">
<blockquote>Email Wizard Description goes here </blockquote>
<input type="hidden" id="Hidden1" runat="server" />
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</asp:WizardStep>
<asp:WizardStep ID="WizardStep2" runat="server" Title="Step 1" >
<table width="100%" align="center" cellpadding="0" cellspacing="0" border="0" >
<tr>
<td align="center" valign="top">
<table width="100%" border="0" cellspacing="0" cellpadding="0">
<tr>
<td>
<asp:Label ID="tolabel" runat="server" ></asp:Label>
</td>
<td>
<asp:TextBox ID="toTb" runat="server" ></asp:TextBox>
</td>
</tr>
<tr>
<td>
<asp:Label ID="fromlabel" runat="server" ></asp:Label>
</td>
<td>
<asp:TextBox ID="fromTb" runat="server" ></asp:TextBox>
</td>
</tr>
<tr>
<td>
<asp:Label ID="subjectLabel" runat="server" ></asp:Label>
</td>
<td>
<asp:TextBox ID="subjectTb" runat="server" ></asp:TextBox>
</td>
</tr>
<tr>
<td>
<asp:Label ID="bodyLabel" runat="server" ></asp:Label>
</td>
<td>
<asp:TextBox ID="bodyTb" runat="server" ></asp:TextBox>
</td>
</tr>
</table>
</td>
</tr>
</table>
</asp:WizardStep>
</WizardSteps>
<StepNextButtonStyle CssClass="hide" />
<StartNextButtonStyle CssClass="hide" />
<FinishCompleteButtonStyle CssClass="hide" />
<FinishPreviousButtonStyle CssClass="hide" />
<CancelButtonStyle CssClass="hide" />
<StepPreviousButtonStyle CssClass="hide" />
</asp:Wizard>
// End of EmailWizardUI.ascx
-
Apply the stylesheet template-wizard.css to the page. This exists in \BPMUITemplates\Default\Wizards\styles folder.
-
Paste the file to the \BPMUITemplates\Default\Wizards\ folder.
Step 4:
-
Create the code behind for your user control. Your user control can use either code behind or library. Either way, it needs to inherit from IWizardUI interface and System.Web.UI.UserControl.
-
If you have used a class file as code behind, copy the same to \BPMUITemplates\Default\Wizards\ folder or use as a library CustomWizardUI.EmailWizardUI.
-
Add the reference of the CustomWizards.dll
-
Write the necessary code for the wizard action.
// EmailWizardUI.ascx.cs
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using Skelta.Wizards.Core;
using Skelta.Wizards.Core.Interfaces;
using Workflow.NET;
using CustomWizards;
namespace CustomWizardUI
{
public partial class EmailWizardUI : System.Web.UI.UserControl, IWizardUI
{
private bool isValid = true;
protected void Page_Load(object sender, EventArgs e)
{
tolabel.Text = "To";
fromlabel.Text = "From";
subjectLabel.Text = "Subject";
bodyLabel.Text = "Body";
}
///Returns the Email Wizard from pre entered values
private IWizard GetWizard()
{
EmailWizard emailwizard = null;
if (IsPostBack)
{
emailwizard = (_WizardData as EmailWizard);
if (Request.Form[toTb.UniqueID] != null)
emailwizard.To = Request.Form[toTb.UniqueID];
if (Request.Form[fromTb.UniqueID] != null)
emailwizard.From = Request.Form[fromTb.UniqueID];
if (Request.Form[subjectTb.UniqueID] != null)
emailwizard.Subject = Request.Form[subjectTb.UniqueID];
if (Request.Form[bodyTb.UniqueID] != null)
emailwizard.Body = Request.Form[bodyTb.UniqueID];
}
return emailwizard;
}
///Sets the Email Wizard with user entered values
public void SetWizard(IWizard wizardData)
{
EmailWizard spEventWizard = wizardData as EmailWizard;
toTb.Text = spEventWizard.To;
fromTb.Text = spEventWizard.From;
subjectTb.Text = spEventWizard.Subject;
bodyTb.Text = spEventWizard.Body;
}
#region IWizardUI Members
///Sets or gets the wizard
private IWizard _WizardData;
public IWizard WizardData
{
get
{
if (_WizardData == null)
return null;
return GetWizard();
}
set
{
_WizardData = value;
SetWizard(_WizardData);
}
}
///Returns the total number of pages in the wizard UI
public int TotalPages
{
get { return AspWizard.WizardSteps.Count; }
}
///Sets or gets the current page of the wizard UI
public int CurrentPage
{
get
{
return AspWizard.ActiveStepIndex;
}
set
{
AspWizard.ActiveStepIndex = value;
}
}
///Sets or gets the Direction whether the user clicked "Next" ///or "Previous"
private NavaigationType _Direction = NavaigationType.Next;
public NavaigationType Direction
{
get
{
return _Direction;
}
set
{
_Direction = value;
}
}
///Sets or gets the ValidationStatus whether the
///wizard pages are valid or not
private bool _validationstatus;
public bool ValidationStatus
{
get
{
return isValid;
}
set
{
isValid = value;
}
}
#endregion
}
}
// end of EmailWizardUI.ascx.cs
Note: ValidationStatus property is helpful if you wish to validate the current page before moving on to the next one. If the page is not valid, this property can be set to false and vice versa.
Step 5:
Open your repository database and add a row to the table SKAddInProviders. The sql command is given below.
INSERT INTO [SKAddInProviders]([Type],[Name],[Description],[ClassName],[Assembly],[Settings],[IsGacAssembly],[LastUpdatedDatetime]) VALUES ('Wizard',<your wizard name>,<your wizard description>,<your project name(which contains EmailWizard.cs)>,<location of your project dll (which contains EmailWizard.cs)> , <xml string specifying the category of the wizard and the favorites, image and whether the wizard is a start up wizard or not> ,0,getdate())
For example, the SQL Command for the above Email Wizard would be:
INSERT INTO [SKAddInProviders]([Type],[Name],[Description],[ClassName],[Assembly],[Settings],[IsGacAssembly],[LastUpdatedDatetime]) VALUES ('Wizard','EmailWizard','Email Wizard Description', 'CustomWizards.EmailWizard','bin\CustomWizards.dll','<wizard><Category>Human Activities</Category><ImageName>Images\Email.png</ImageName><IsStartupWizard>false</IsStartupWizard><Favourites><FavouriteElement>ApprovalWizard</FavouriteElement></Favourites></wizard>',0,getdate())
The example row that is added for the Email Wizard. You can add any wizard of your own. You just need to specify which category it will belong to in the Settings column. In this case, the Wizard comes under the Human Activities category. Favorites of a wizard can also be specified in the Favourites tag. Whether the wizard is just used for provisioning i.e. IsStartupWizard can also be set in the IsStartupWizard tag.
Step 6:
-
Do not forget to paste the EmailWizardUI.ascx and EmailWizardUI.ascx.cs(code behind) files into BPMUITemplates\Default\Wizards folder.
-
Add the necessary resource files into the Locales folder and the required styles into BPMUITemplates\Default\Wizards\styles folder and images into the BPMUITemplates\Default\Wizards\Images folder.
Step 7:
Copy the above created CustomWizards.dll into the bin folder of the Enterprise Console i.e.[AVEVA Work Tasks Installed Path]\AVEVA\Work Tasks\Web\EnterpriseConsole\bin
Your wizard is now ready.