Month: June 2012

Migrating to ArcGIS for Windows Mobile 3.0

This post has some tips for people wanting to migrate custom tasks and extensions written for the ArcGIS Runtime SDK for Windows Mobile. Before reading you should also check the article on the Esri resource center for migrating your applications to ArcGIS Mobile 3.0 as it contains some additional information that may be of help.

With the release of the 3.0 SDK there have been a number of changes to the way that custom extensions work and are deployed. Lets start with changes to the code for creating a custom task and project extension.

For the project center definition, previously you would have declared your task as

CustomTask : UserControl, IProjectTask

in 3.0 this becomes

CustomTask : ProjectTaskControl

The ProjectTaskControl type is simpler to work with. You can still set properties on it and an Icon but instead of using XML serialisation it now uses JSON. A sample base class for a task may be

public abstract class TaskBase : ProjectTaskControl
{
    readonly string _taskName;

    protected TaskBase(string taskName)
    {
        _taskName = taskName;
    }

    /// <summary>
    /// Gets/sets Description for your capability
    /// </summary>
    public override string Description
    {
        get { return base.Description; }
        set
        {
            base.Description = value;
            RaisepropertyChangedEvent("Description");
            IsDirty = true;
        }
    }

    /// <summary>
    /// Gets/sets DisplayName for your capability
    /// </summary>
    public override string DisplayName
    {
        get { return base.DisplayName; }
        set
        {
            base.DisplayName = value;
            RaisepropertyChangedEvent("DisplayName");
            IsDirty = true;
        }
    }

    public override ImageSource Icon
    {
        get
        {
            var uri = new Uri(string.Format("pack://application:,,,/SampleTasks;Component/Assets/{0}.png", _taskName));
            return new BitmapImage(uri);
        }
    }

    /// <summary>
    /// Generates an object from its JSON representation.
    /// </summary>
    public override void ReadJson(IDictionary<string, object> readData)
    {
        if (!readData.ContainsKey("Attributes"))
            return;
        IDictionary<string, object> values = readData["Attributes"] as Dictionary<string, object>;
        DisplayName = values["name"] as string;
        Description = values["description"] as string;
    }

    /// <summary>
    /// Converts an object into its JSON representation.
    /// </summary>
    public override void WriteJson(IDictionary<string, object> writeData)
    {
        IDictionary<string, object> values = new Dictionary<string, object>();
        writeData.Add("Attributes", values);
        values.Add("name", DisplayName);
        values.Add("description", Description);
    }
}

and used as

public sealed partial class CustomTask : TaskBase
{
    public SearchTask() : base("CustomTask")
    {
        InitializeComponent();

        DisplayName = "My custom task";
        Description = "blah blah blah.";
    }
}

For the implementation of the Task in the windows or windows mobile dll respectively the type is not changed though you must include the JSON serialisation. Without this you won’t see your task in the deployed application.

/// <summary>
/// Generates an object from its JSON representation
/// </summary>
public override void ReadJson(IDictionary<string, object> readData)
{
    if (!readData.ContainsKey("Attributes"))
        return;
    IDictionary<string, object> values = readData["Attributes"] as Dictionary<string, object>;
    Name = values["name"] as string;
    Description = values["description"] as string;
}

/// <summary>
/// Converts an object into its JSON representation.
/// </summary>
public override void WriteJson(IDictionary<string, object> writeData)
{
    IDictionary<string, object> values = new Dictionary<string, object>();
    writeData.Add("Attributes", values);
    values.Add("name", Name);
    values.Add("description", Description);
}

Writing a project extension has seen a similar change required so now instead of

public partial class CustomExtension : UserControl, IProjectExtension

you would use

public sealed partial class CustomExtension : ProjectExtensionControl

The other important change is to how extensions are deployed. Now when you build your projects you set the path to be

c:\ProgramData\ESRI\MobileProjectCenter\Extensions for the project center dll

c:\ProgramData\ESRI\MobileProjectCenter\Extensions\Win32 for the windows application dll and

c:\ProgramData\ESRI\MobileProjectCenter\Extensions\WinCE for the windows mobile dll

These dlls are automatically packaged with a mobile project when you reference them in the mobile project center and will be copied to a subfolder of the project. This means that if you want to debug your code you need either change the output path of your library to match your project location or manually copy the built dll each time you make code changes so that you are using the latest version. You could also add a build event to do this. If you forget this step then you will see a message like

debugarcgismobileerror

Now you can add and deploy your code there may be some breaking changes in the API that you need to correct, here are some that I have encountered.

When using a sketch tool you now need to call Activate on it

var sketchTool = new EnvelopeSketchTool();
sketchTool.SketchCompleted += SketchToolOnSketchCompleted;
sketchTool.AttachToSketchGraphicLayer(_graphicsLayer);
sketchTool.Activate();

Setting layer visibility has moved to the MobileCacheMapLayerDefinition

internal static void ToggleLayerVisibility(string layerName)
{
    if (string.IsNullOrEmpty(layerName)) return;

    var layer = MobileApplication.Current.Project.EnumerateFeatureSourceInfos().FirstOrDefault(lyr => string.Equals(lyr.Name, layerName, StringComparison.InvariantCultureIgnoreCase));

    if (layer == null) return;

    layer.MobileCacheMapLayerDefinition.Visibility = !layer.MobileCacheMapLayerDefinition.Visibility;
}

When checking for a layer you now use FeatureSourceInfo

MobileApplication.Current.Project.EnumerateFeatureSourceInfos()

Hopefully you find these tips useful for helping update your own code. Let me know of any other useful information that I’ve missed.