Workflow Activity Reference
In the VertiGIS Studio Workflow .NET SDK, activities are represented as simple classes with an Execute
method.
Use a unique prefix on the Action
property to avoid it conflicting with someone else's custom activities.
[assembly: Export(typeof(CustomActivity))]
namespace App1.Workflow
{
public class CustomActivity : IActivityHandler
{
public static string Action { get; } = "uuid:<uuid>::CustomActivity";
public Task<IDictionary<string, object?>> Execute(IDictionary<string, object?> inputs, IActivityContext context)
{
return Task.FromResult((IDictionary<string, object?>)new Dictionary<string, object?>(){
["result"] = "value"
});
}
}
}
Registering Activities
Every VertiGIS Studio Mobile application that implements custom workflow activities needs to implement an IActivityHandlerFactory
. The IActivityHandlerFactory
is responsible for registering the custom activities with VertiGIS Studio Mobile so they can be created by VertiGIS Studio Workflow at runtime.
The ActivityLoader
registers custom activities in its constructor. Only one instance of the loader is required per VertiGIS Studio Mobile Application, as it can register multiple activities.
Two key components of this snippet are the [assembly: Export(...)]
tag and the class extension ActivityLoader : IActivityHandlerFactory
. These two pieces register the ActivityLoader
with VertiGIS Studio Mobile and cause it to be initialized on startup.
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using VertiGIS.Mobile.Composition;
using VertiGIS.Workflow.Runtime;
using VertiGIS.Workflow.Runtime.Definition;
using VertiGIS.Workflow.Runtime.Execution;
using App1.Workflow;
[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<CustomActivity> customActivityFactory)
{
RegisteredActivities[CustomActivity.Action] = customActivityFactory;
}
/// <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);
}
}
}
}
Access VertiGIS Studio Mobile Functionality
You can access VertiGIS Studio Mobile functionality in custom workflow activities by using the built-in dependency injection pattern to inject shared VertiGIS Studio Mobile services such as the UIOperations
service.
First, add the class you want to inject to the constructor of the custom activity.
[assembly: Export(typeof(DisplayVertiGISStudioMobileAlert))]
namespace App1.Workflow
{
public class DisplayVertiGISStudioMobileAlert : IActivityHandler
{
private UIOperations _uiOperations;
public static string Action { get; } = "uuid:<uuid>::DisplayVertiGISStudioMobileAlert";
public DisplayVertiGISStudioMobileAlert(UIOperations uiOperations)
{
_uiOperations = uiOperations;
}
public Task<IDictionary<string, object?>> Execute(IDictionary<string, object?> inputs, IActivityContext context)
{
return Task.FromResult((IDictionary<string, object?>)new Dictionary<string, object?>());
}
}
}
Next, inject the activity into the IActivityHandlerFactory
for the application.
Since the DisplayVertiGISStudioMobileAlert
activity is injected into the IActivityHandlerFactory
with Autofac, its dependency on the UIOperations
class will be be resolved by Autofac.
public class ActivityLoader : IActivityHandlerFactory
{
...
public ActivityLoader(Func<DisplayVertiGISStudioMobileAlert> displayVertiGISStudioMobileAlertFactory)
{
RegisteredActivities[DisplayVertiGISStudioMobileAlert.Action] = displayVertiGISStudioMobileAlertFactory;
}
...
}
Finally, you can implement your activity using the referenced VertiGIS Studio Mobile class.
- Custom Activity
- IActivityHandlerFactory
using App1.Workflow;
using VertiGIS.Mobile.Composition;
using VertiGIS.Mobile.Infrastructure.Messaging;
using VertiGIS.Workflow.Runtime;
using System.Collections.Generic;
using System.Threading.Tasks;
[assembly: Export(typeof(DisplayVertiGISStudioMobileAlert))]
namespace App1.Workflow
{
public class DisplayVertiGISStudioMobileAlert : IActivityHandler
{
private UIOperations _uiOperations;
public static string Action { get; } = "uuid:<uuid>::DisplayVertiGISStudioMobileAlert";
public DisplayVertiGISStudioMobileAlert(UIOperations uiOperations)
{
_uiOperations = uiOperations;
}
public async Task<IDictionary<string, object?>> Execute(IDictionary<string, object?> inputs, IActivityContext context)
{
await _uiOperations.Alert.ExecuteAsync(new UIAlertArgs() { Title = "It's dangerous to go alone.", Message = "Take this!", ButtonText = "*take sword*" });
return new Dictionary<string, object?>();
}
}
}
using App1.Samples.Workflow.CustomActivity;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using VertiGIS.Mobile.Composition;
using VertiGIS.Workflow.Runtime;
using VertiGIS.Workflow.Runtime.Definition;
using VertiGIS.Workflow.Runtime.Execution;
using App1.Workflow;
[assembly: Export(typeof(ActivityLoader), SingleInstance = true, AsImplementedInterfaces = true)]
namespace App1.Samples.Workflow.CustomActivity
{
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<DisplayVertiGISStudioMobileAlert> displayVertiGISStudioMobileAlertFactory)
{
RegisteredActivities[DisplayVertiGISStudioMobileAlert.Action] = displayVertiGISStudioMobileAlertFactory;
}
/// <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);
}
}
}
}
Access the Application Map
The map of the host application can be accessed through dependency injection . The MapProviderBase
class which exposes the Map and MapView can be injected with the ProviderFactoryAttribute
.
For a complete example, check out the Show Callout on Map custom activity tutorial.
[assembly: Export(typeof(CustomActivity))]
namespace App1.Workflow
{
public class CustomActivity : IActivityHandler
{
[ProviderFactoryAttribute(typeof(MapProviderBase))]
public Func<MapProviderBase> MapProviderFactory { get; set; }
public static string Action { get; } = "uuid:<uuid>::CustomActivity";
public Task<IDictionary<string, object?>> Execute(IDictionary<string, object?> inputs, IActivityContext context)
{
var mapProvider = MapProviderFactory();
await mapProvider.Load();
var map = mapProvider.Map;
var mapView = (MapView)((WorkflowMapProvider)mapProvider).View;
// ...
return new Dictionary<string, object?>();
}
}
}