Implement an Loading Indicator Form Element

Implementing a custom form element allows you to augment the existing form elements that come with Geocortex Workflow. This article will walk you through creating a form element that displays a loading indicator.

Prerequisites

important

Extending Geocortex Workflow for Mobile requires development and deployment of a custom Geocortex Mobile Application using the Geocortex Mobile SDK

Follow the instructions in the Geocortex Mobile SDK page to set up the environment for extending Workflow for Geocortex Mobile.

note

A working knowledge of C# and .NET Standard is recommended before extending Workflow for Geocortex Mobile

Overview

Implementing a custom form element in Geocortex Mobile consists of three steps:

  1. Creating the custom form element and implementing the UI.
  2. Creating an activity which will register this form component with Geocortex Workflow.
  3. Registering the activity with Geocortex Workflow and running it before using the custom form element.

Set up the Custom Form Element Skeleton

  1. Create a new file LoadingIndicator.cs in the platform agnostic project of the Geocortex Mobile Quickstart.
  2. Add a new skeleton form element that implements FormComponent.
App1/App1/workflow/LoadingIndicator.cs
using Geocortex.Workflow.Forms.Xamarin.Components;
using Xamarin.Forms;
namespace App1.Workflow
{
public class LoadingIndicator : FormComponent
{
private readonly View _view;
public LoadingIndicator(Geocortex.Workflow.Runtime.Definition.Forms.Element element, string name)
: base(element, name)
{
_view = new Label() { Text = "I'm a custom form component!" };
Add(new GenericComponent(_view));
}
public override void Render()
{
base.Render();
_view.IsEnabled = IsEnabled;
}
}
}

Set up a Form Element Registration Activity

  1. Create a new file FormElementRegistrationActivity.cs in the platform agnostic project of the Geocortex Mobile Quickstart.
  2. Add a new form registration activity that implements RegisterCustomFormElementBase.
  3. Register the LoadingIndicator form element in the Execute method of the activity.
tip

Only one form element registration activity is needed per app, as it can register multiple custom form elements. Learn more about implementing custom activities.

App1/App1/workflow/FormElementRegistrationActivity.cs
using Geocortex.Workflow.Runtime;
using Geocortex.Workflow.Runtime.Activities.App;
using System.Collections.Generic;
using System.Threading.Tasks;
[assembly: Export(typeof(FormElementRegistrationActivity))]
namespace App1.Workflow
{
class FormElementRegistrationActivity : RegisterCustomFormElementBase
{
public static string Action { get; } = "your:unique:namespace::FormElementRegistrationActivity";
public override Task<IDictionary<string, object>> Execute(IDictionary<string, object> inputs, IActivityContext context)
{
IDictionary<string, object> result = new Dictionary<string, object>();
Register("LoadingIndicator", typeof(LoadingIndicator), context);
return Task.FromResult(result);
}
}
}

Register the Form Element Registration Activity

Register the RegisterCustomFormElementBase class in the IActivityHandlerFactory for the application.

note

Learn more about activity registration in the activity reference.

App1/App1/workflow/ActivityLoader.cs
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using App1.Workflow;
using VertiGIS.Mobile.Composition;
using Geocortex.Workflow.Runtime;
using Geocortex.Workflow.Runtime.Definition;
using Geocortex.Workflow.Runtime.Execution;
[assembly: Export(typeof(ActivityLoader), SingleInstance = true, AsImplementedInterfaces = true)]
namespace App1.Workflow
{
public class ActivityLoader : IActivityHandlerFactory
{
/// <summary>
/// Gets a mapping of action names to implementations of <see cref="IActivityHandler"/>s.
/// </summary>
private Dictionary<string, Func<IActivityHandler>> RegisteredActivities { get; } = new Dictionary<string, Func<IActivityHandler>>();
public ActivityLoader(Func<FormElementRegistrationActivity> formElementRegistrationActivityFactory)
{
RegisteredActivities[FormElementRegistrationActivity.Action] = formElementRegistrationActivityFactory;
}
/// <summary>
/// Creates an <see cref="IActivityHandler"/>.
/// </summary>
/// <param name="action">The name of the action to create.</param>
/// <param name="token">The cancellation token.</param>
/// <param name="inspector">The <see cref="ProgramInspector"/> for the program.</param>
/// <returns>The activity handler for the given action.</returns>
public Task<IActivityHandler> Create(string action, CancellationToken token, ProgramInspector inspector = null)
{
if (action == null || token.IsCancellationRequested)
{
return Task.FromResult<IActivityHandler>(null);
}
if (RegisteredActivities.TryGetValue(action, out Func<IActivityHandler> handlerType))
{
return Task.FromResult(handlerType());
}
else
{
return Task.FromResult<IActivityHandler>(null);
}
}
}
}

Add the Loading Indicator

Next we can add the loading indicator to the form element.

App1/App1/workflow/LoadingIndicator.cs
using VertiGIS.Mobile.Infrastructure.UI;
using Geocortex.Workflow.Forms.Xamarin.Components;
namespace App1.Workflow
{
public class LoadingIndicator : FormComponent
{
private readonly EnhancedActivityIndicator _view;
public LoadingIndicator(Geocortex.Workflow.Runtime.Definition.Forms.Element element, string name)
: base(element, name)
{
_view = new EnhancedActivityIndicator()
{
IsRunning = true,
HeightRequest = 75,
WidthRequest = 75,
Margin = 10
};
Add(new GenericComponent(_view));
}
}
}

Test your Activity

Now you can build a workflow for Geocortex Mobile that uses your new custom form element! It is essential that this custom activity be run before the custom form element is used. It is best practice to run the form element registration activity at the start of a workflow.

note

You can download this demo workflow that registers and displays the custom form element and import it into the Geocortex Workflow Designer.

Next you need to run the workflow you just created in your Geocortex Mobile SDK project.

You can do this by configuring the layout and app config to run a workflow. You will need to copy the ID of the the workflow you created into the app.json


App1/App1/app.json
{
"schemaVersion": "1.0",
"items": [
{
"$type": "layout",
"id": "desktop-layout",
"url": "resource://layout-large.xml",
"tags": ["large"]
},
{
"$type": "workflow",
"id": "custom-workflow",
"title": "Custom Workflow",
"target": "#taskbar",
"portalItem": "<your-workflow-id>"
},
{
"$type": "menu",
"id": "iwtm",
"items": [
{
"title": "Run Custom Workflow",
"isEnabled": true,
"iconId": "workflow",
"action": {
"name": "workflow.run",
"arguments": {
"id": "custom-workflow"
}
}
}
]
}
]
}

Relevant SDK Sample

Check out the relevant Geocortex Mobile SDK Sample: