Skip to main content

Show a Callout on the Map with an Activity

Some activities may need access to the map embedded in the VertiGIS Studio Mobile Application. The MapProviderBase class can be injected in an activity and used to access the Map and MapView for the application.

This article will walk you through accessing the map from an activity and displaying a callout at the map center point.

Prerequisites

Important

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

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

note

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

Set up the Activity

First, the basic activity needs to be setup and registered. Below is an example of an activity setup to take text to display in the map callout.

App1/App1/workflow/PlaceCalloutAtCenter.cs
using App1.Workflow;
using VertiGIS.Mobile.Composition;
using VertiGIS.Workflow.GIS.ArcGISRuntime;
using VertiGIS.Workflow.Runtime;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

[assembly: Export(typeof(PlaceCalloutAtCenter))]
namespace App1.Workflow
{
public class PlaceCalloutAtCenter : IActivityHandler
{
public static string Action { get; } = "uuid:<uuid>::PlaceCalloutAtCenter";

public async Task<IDictionary<string, object>> Execute(IDictionary<string, object> inputs, IActivityContext context)
{
var calloutText = (string)inputs["calloutText"];

return new Dictionary<string, object>();
}
}
}

Access the MapProviderBase

Accessing the map for the application uses the built-in dependency injection pattern to inject a MapProviderBase class which exposes the Map and MapView.

To inject the MapProviderBase, add a new Autofac factory property that injects a MapProviderBase into your custom activity.

App1/App1/workflow/PlaceCalloutAtCenter.cs
using App1.Workflow;
using VertiGIS.Mobile.Composition;
using VertiGIS.Workflow.GIS.ArcGISRuntime;
using VertiGIS.Workflow.Runtime;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

[assembly: Export(typeof(PlaceCalloutAtCenter))]
namespace App1.Workflow
{
public class PlaceCalloutAtCenter : IActivityHandler
{
public static string Action { get; } = "uuid:<uuid>::PlaceCalloutAtCenter";

[ProviderFactoryAttribute(typeof(MapProviderBase))]
public Func<MapProviderBase> MapProviderFactory { get; set; }

public async Task<IDictionary<string, object>> Execute(IDictionary<string, object> inputs, IActivityContext context)
{
var calloutText = (string)inputs["calloutText"];

return new Dictionary<string, object>();
}
}
}

Load the MapView

Next, we need to load the MapView from the MapProviderFactory.

App1/App1/workflow/PlaceCalloutAtCenter.cs
using App1.Workflow;
using Esri.ArcGISRuntime.Mapping;
using Esri.ArcGISRuntime.Xamarin.Forms;
using VertiGIS.Mobile.Composition;
using VertiGIS.Workflow.GIS.ArcGISRuntime;
using VertiGIS.Workflow.Runtime;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using VertiGIS.Mobile.Infrastructure.Workflow;

[assembly: Export(typeof(PlaceCalloutAtCenter))]
namespace App1.Workflow
{
public class PlaceCalloutAtCenter : IActivityHandler
{
public static string Action { get; } = "uuid:<uuid>::PlaceCalloutAtCenter";

[ProviderFactoryAttribute(typeof(MapProviderBase))]
public Func<MapProviderBase> MapProviderFactory { get; set; }

public async Task<IDictionary<string, object>> Execute(IDictionary<string, object> inputs, IActivityContext context)
{
var calloutText = (string)inputs["calloutText"];

// Get an instance of the MapProvider
var mapProvider = MapProviderFactory();
// Ensure the map has loaded
await mapProvider.Load();
// ArcGIS runtime Map
Map map = mapProvider.Map;
// ArcGIS runtime MapView
MapView mapView = (MapView)((WorkflowMapProvider)mapProvider).View;

return new Dictionary<string, object>();
}
}
}

Add a Callout at the Map Center

Finally, we can use the MapView to get the map center and add a callout with the user's text.

tip

Operations related to UI activities have to run in Xamarin's main thread, else they will throw an error.

App1/App1/workflow/PlaceCalloutAtCenter.cs
using App1.Workflow;
using VertiGIS.Mobile.Composition;
using Esri.ArcGISRuntime.Geometry;
using Esri.ArcGISRuntime.UI;
using Esri.ArcGISRuntime.Mapping;
using Esri.ArcGISRuntime.Xamarin.Forms;
using VertiGIS.Workflow.GIS.ArcGISRuntime;
using VertiGIS.Workflow.Runtime;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using VertiGIS.Mobile.Infrastructure.Workflow;

[assembly: Export(typeof(PlaceCalloutAtCenter))]
namespace App1.Workflow
{
public class PlaceCalloutAtCenter : IActivityHandler
{
public static string Action { get; } = "uuid:<uuid>::PlaceCalloutAtCenter";

[ProviderFactoryAttribute(typeof(MapProviderBase))]
public Func<MapProviderBase> MapProviderFactory { get; set; }

public async Task<IDictionary<string, object>> Execute(IDictionary<string, object> inputs, IActivityContext context)
{
var calloutText = (string)inputs["calloutText"];

// Get an instance of the MapProvider
dynamic mapProvider = MapProviderFactory();
// Ensure the map has loaded
await mapProvider.Load();
// ArcGIS runtime Map
Map map = mapProvider.Map;
// ArcGIS runtime MapView
MapView mapView = (MapView)((WorkflowMapProvider)mapProvider).View;

Xamarin.Essentials.MainThread.BeginInvokeOnMainThread(() =>
{
var currentEnvelope = (Envelope)mapView.GetCurrentViewpoint(Esri.ArcGISRuntime.Mapping.ViewpointType.BoundingGeometry).TargetGeometry;

mapView.ShowCalloutAt(currentEnvelope.GetCenter(), new CalloutDefinition("Hey!", $"Listen! {calloutText}"));
});

return new Dictionary<string, object>();
}
}
}

Test your Activity

Now you can build a workflow for VertiGIS Studio Mobile that uses your new activity!

tip

If you want your custom activity to show up with a friendly user interface in VertiGIS Studio Workflow Designer, check out Registering .NET Activities with VertiGIS Studio Workflow Designer.

The RunActivity activity can be used to execute your activity by the name defined in PlaceCalloutAtCenter.cs (for this example, uuid:<uuid>::PlaceCalloutAtCenter).

Next you need to run the workflow you just created in your VertiGIS Studio 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"
}
}
}
]
}
]
}