SDK Custom Control

SDK Custom control is another method of enhancing WEBCON BPS in a way that makes the user interface better suited for the users’ needs. This plugin will enable the creation of a control, which can be placed on the BPS form as if it were a normal form field. However, in contrast to form field extensions, data shown in a Custom control does not have to be stored on the workflow instance. This data can be stored pretty much anywhere. While this does grant more freedom, the drawback is that data saving and loading isn’t automatic, and must be implemented manually by the person designing the control.

The example given below portrays the creation of a control which represents a time period confined by two dates ‘from’ and ‘to’. There is a default “Date and Time” form field available in the system that is used to enter one date on the form, the Custom control will instead allow two dates and times to be entered, therefore defining a time period.

Adding SDK Custom control to the project

To create a Custom control, first create a public class in the extensions project that inherits from the relevant base SDK class – WFExtensionsControl, it will be responsible for the control’s behavior. Additionally, create an ASCX file containing the structure and design of the control.

The easiest way of creating these two interwoven components is to use preexisting extension templates. They are available in an install pack. Select item type BPS Custom Control.
Custom control - choose item type

The extension class code will be compiled into the extensions library (DLL). In order for the extension to work correctly, the ASCX file should direct to this library and class. Additionally, during deployment the ASCX file must be placed into the correct SharePoint catalog (Layouts/WEBCON).
When using the extensions project template for SharePoint e.g. “SharePoint 2013 – BPS Extensions”, it is enough to add the Custom control to the Layouts/CustomControls folder in the project. During deployment, the entire contents of this folder will be placed in a SharePoint folder Layouts/WEBCON/CustomControls.
Custom control - Solution Explorer
The project will automatically map all files in Layouts sub-catalogs to corresponding “LAYOUTS\WEBCON” sub-catalogs. In order to confirm where files will be placed after deployment, find and expand the “Package” catalog, open the Package.package file, and go to the “Manifest” tab. Once there, under the “TemplateFiles” you will find files that will be loaded and where they will be allocated.
Preview of packaged manifest:

If the custom control is created in different way than by using the provided template, make sure that the ASCX file is placed in the correct “LAYOUTS” sub-catalog during deployment.

Custom control configuration

Custom Control SDK has the same configuration mechanism as the one available to the SDK action. In this example, the configuration properties will be used to define form fields into which data from the control will be saved. As mentioned in the introduction, saving data from Custom Controls in the system must be implemented manually – for this example, data will be saved into technical form fields defined in the configuration.
The easiest way to achieve this is, is to create text fields in the configuration. Then in BPS Designer Studio, simply enter the database column names that correspond to the desired form fields into the created text fields.

Custom control - configuration properties

Control design

Our aim is to create a control, which will be used to enter a time period spanning from one date to the other. Therefore, in the ASCX file we create two date controls with relevant labels, including a label responsible for displaying the form field name, analogously to standard form fields. ASCX file markup below:

This example applies to BPS versions 8.3 and earlier. Starting with BPS 2016.1, the structure of a HTML control has to be altered slightly – it should be encapsulated into additional <TABLE></TABLE> markers at the beginning and end. After these changes the code should look like below:

Deployment and plugin configuration

In order to verify the ASCX file, this plugin may be viewed on the BPS form.

To do this, deploy the project (right click the project name and select Deploy). Once the project is located in SharePoint, register the extension in BPS Designer Studio. Registering a Custom control is similar to registering a Custom action. In the Plugins tab, add a new plugin beneath the “Custom control (SDK)” node, and then configure the plugin class and ASCX file address.

This is done by clicking the Choose button, and the in the “Beginning of URL to ASCX file” enter the address where the ASCX file is located. If the project was created from the template, the address will be “/_layouts/15/WEBCON/CustomControls/”.
Custom Control - register plugin
Clicking the Show button should also bring up all other custom controls installed in this folder.
Provide a name for the plugin and save it.
In order to use the newly configured plugin, first add a new form field to a process and then select Custom Control (SDK) as its type. The “Customization of form field controls (SDK)” in the bottom right Settings section should become available – select the recently created plugin from the drop-down menu.
Custom Control - Field configuration
If the plugin was deployed correctly, the configuration properties that were discussed earlier can be found in the “Advanced configuration” window.

After mapping the configuration properties to appropriate storage form fields, the custom control form field can be added onto a form, and its visibility can be defined like that of any other regular form field.
Custom Control - Field Matrix
After saving the process configuration, the Custom Control field should be visible on the SharePoint form.
SDK Custom Control - first preview

Form field label and requiredness settings

Because the Custom control plugin can be used to create controls that have any design and layout, it does not intrinsically support setting form fields as required. The option to toggle form fields as required/not required must be implemented separately.

By default, the fields matrix in Designer Studio defines the behavior of each form field on each step – the available behavior options are: Visible, Read-only and Required. Toggling the last of these options causes the form field to check if a value is entered into it – if it is empty, the workflow instance will not be able to progress to the next step. Form fields that are ‘Required’ are denoted on the BPS form by a red asterisk (*) next to their respective labels.
Custom Control - Errors in form
For Custom controls, we must manually ensure that a label and asterisk is displayed. The IsRequired flag that is inherited from the WFExtensionControl class may prove helpful in this. It defines whether the form field is marked as required on the field matrix. Whether or not a red asterisk is displayed by the label is decided based on the value of this flag.

Correctly displaying the label, while also including the requiredness setting, can be handled with a rewritten method from the base class: OnLoad(EventArgs e). It is a standard method used across ASP.NET sites, available to all classes that inherit from Control found in the System.Web library. Similarly to OnLoad, we also have access to other methods of the Control class, like OnInit, OnPreRender, DataBind or RenderControl, which means that it is possible to freely adjust what happens on each stage of an ASP.NET Page Life Cycle.

An overwritten OnLoad method should look something like this:

FieldName is a property of the WFExtensionControl base class which stores the form field name defined in Designer Studio.
Overwriting OnLoad in a such a will cause two things to happen:
1) The name label defined in Designer Studio will appear beside the Custom control on the BPS form.
2) Setting the custom control form field as ‘Required’ through the field matrix will also cause a red asterisk to appear next to its label

With the visual aspects sorted, it is now time to implement a mechanism for validating whether the form field has a value entered into it. The way in which this validation is carried out depends on the structure and expected behavior of the control.
For our example, we expect both dates (‘from’ and ‘to’) to be filled out, and it would also make sense to ensure that ‘Date to’ doesn’t occur before ‘Date from’.
For validation, we can use one of two available methods of the base class: Validate() or CheckSaveRestrictions(). The two vary in purpose, and also the timing in which they are activated.
1) CheckSaveRestrictions is supposed to verify whether data entered is in the correct format, so that it may be saved into the database. It is activated both when using a transition path, and when progress on a workflow instance form is saved.
2) Validate method is supposed to verify the logical correctness of the data, and also if data has been entered if it is required. The Validate method is only run when using a transition path for which the ‘Validate’ option has been toggled on.

For this example, we will carry out our validation using the second option (the Validate method) because we want to prevent users from using transition paths when the data is invalid, but at the same time they should be able to save the workflow instance at will, even if the required data isn’t filled out. The ValidationParams class includes fields which can deny access to transition paths (IsValid) and also display messages to the user (ErrorMessage).

In order to verify whether the implemented solution actually works, rebuild and redeploy the project.
Next, on the field matrix in Designer Studio, set the control form field as required, and attempt to use the transition path without filling out the two dates in the control. You should receive a message about the error – and access to the next step should be denied.
Custom Control - empty values
Custom Control - incorrect values

Saving and loading data

The next development step for our Custom Control is to implement a mechanism for saving data that has been entered into it, and also for loading any existing data.
As mentioned in the introduction, Custom control can handle pretty much any way and location for storing data. There are two main schools of thought – saving data from the control into one or multiple form fields, or saving the data outside the workflow instance altogether (e.g. in a separate dedicated table of the database).
In order to make both of these scenarios easier to implement, the base class WFExtensionControl provides two methods that can be overwritten: OnBeforeElementSave and OnAfterElementSave.
If we want to save data to another from field of the same workflow instance, it is best to utilize OnBeforeElementSave. The chosen form fields can be freely modified within it, and the changes will be saved to the database along with the entire workflow instance.
If we want to save data in an external table (for example), it is better to utilize the OnAfterElementSave method. This method provides access to the ID’s of new instances (newly created instances don’t have allocated ID’s until they are saved, therefore in the OnBeforeElementSave method the ID is empty), once we have obtained this instance ID, we can associate it with the relevant table entry.

For our example, we want to take the two dates entered into the Custom Control and save them into two separate form fields. Therefore, we need to set the values in the OnBeforeElemntSave method to the ones entered into the Custom control. The base class provides the ElementCurrent property, which contains all form fields of the workflow instance. We can set our new values there directly.

ElementCurrent represents the current state of the form – after being saved, any changes are carried over onto the database.
At this point, we have successfully implemented a method of saving data to the database, the next step is to handle displaying any existing data on the BPS form – currently, saved data is not displayed in the custom control.
Filling controls with existing data can be handled by the previously overridden OnLoad method:

Read-only and administrator modes

The ‘Editable’ state of our sample Custom Control is now fully implemented. However, in the field matrix, a form field can also be set as visible but in a read-only state. In such a scenario, the Custom Control should display its contents on the form, but the option to edit the values should be disabled.
To handle this setting, we can expand the OnLoad method to also check the current mode:

This configuration will cause our Custom Control form field to be inactive when it is set as ‘Read-only’ on the field matrix.
SDK Custom Control - view mode
If you choose to enter admin mode, the IsAdminMode flag will be toggled on, which also changes the IsReadOnly flag – it will no longer reflect the settings of the field matrix, but instead simply check whether the control is editable at all.
SDK Custom Control - Admin view