Show a Callout on the Map with an Activity

Some activities may need access to the map embedded in the Geocortex 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 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 the .NET platform is recommended before extending Workflow for Geocortex 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 Geocortex.Workflow.GIS;
using Geocortex.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; } = "your:unique:namespace::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 Geocortex.Workflow.GIS;
using Geocortex.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; } = "your:unique:namespace::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 Geocortex.Workflow.GIS;
using Geocortex.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; } = "your:unique:namespace::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 = mapProvider.GetType().GetProperty("MapView").GetValue(mapProvider, null) as MapView;
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 Geocortex.Workflow.GIS;
using Geocortex.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; } = "your:unique:namespace::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 = mapProvider.GetType().GetProperty("MapView").GetValue(mapProvider, null) as MapView;
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 Geocortex Mobile that uses your new activity!

tip

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

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

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"
}
}
}
]
}
]
}