TTilton-esristaff

Go from zero to app by leveraging the ArcGIS platform - part 4

Blog Post created by TTilton-esristaff Employee on Dec 9, 2016

This is part four of a multiple part blog series that walks through using the ArcGIS platform to create an ArcGIS Runtime SDK for .NET app. In summary ...

  • Part one provided a high-level overview of the ArcGIS platform and described some of the tools relevant to the ArcGIS Runtime SDK developer.
  • Part two walked through the process of getting an ArcGIS for Developers account and using it to create an Application portal item with important properties for implementing security for an app.
  • Part three walked through the process of using ArcGIS Online to author a new map, save it as a portal item, and set sharing properties so it can be accessed by everyone.

If you want to follow along without reading the previous posts, that's fine. You'll simply need the ArcGIS Runtime SDK for .NET and the ID of a publically available web map on ArcGIS Online that contains bookmarks (such as the US Wildfire Activity Web Map, ID = df8bcc10430f48878b01c96e907a1fc3).

 

This time, you'll finally fire up Visual Studio with ArcGIS Runtime SDK for .NET and create a simple Windows Presentation Framework (WPF) app to display the web map you created previously!

 

Part 4 - Slap a map in your app

The basic process for displaying a web map in your ArcGIS Runtime SDK app is very simple: connect to the portal hosting the web map (ArcGIS Online, in our case, but could be another ArcGIS Portal instance), create a Map based on the web map (using the ID, for example), and then load the Map into a MapView control in the app.

There are things that can complicate this process, of course, such as permission to access the web map (portal item) and all the data that it contains. We'll circle back to security in a later post, when we step through implementing OAuth 2.0 for the app.

 

Create a simple app from a template

  1. If you haven't already downloaded and installed ArcGIS Runtime SDK for .NET, you can find everything you need from the ArcGIS Runtime SDK for .NET home page. Make sure your development machine meets the system requirements, then follow the install instructions to get started. Remember, you'll need an ArcGIS for Developers account to download the SDK.
  2. Open a supported version of Visual Studio and create a new project. Under the Windows > Classic Desktop project templates, select ArcGIS Runtime Application (WPF). The template adds the ArcGIS Runtime API NuGet package, as well as XML namespace references and XAML to define a simple map view containing a single basemap layer.
  3. Run the project. The app should launch and display a streets base map.

 

A word about MVVM

You may have heard the buzzword (buzz-acronym?!) "MVVM" mentioned in the context of WPF, UWP, Silverlight, or even JavaScript development. MVVM stands for Model-View-ViewModel and is a useful design pattern for organizing your code. It facilitates code sharing and maintenance by segregating objects in your code according to their role: Model for data or data transfer objects, View for user interface elements and code, and ViewModel for the business logic. Data binding can play a large role in this pattern as well, helping to bridge the gap between the UI (View) and business logic (ViewModel). There's lots of good info on the web about this popular design pattern, this post on Code Project provides a good overview.

I highly recommend using the MVVM design pattern for your ArcGIS Runtime SDK for .NET apps. For proofs of concept or really small apps it may be overkill, but for most apps I think you'll benefit from using it. And guess what? If you created your Visual Studio project from one of the ArcGIS Runtime SDK for .NET templates, you're using MVVM!

In your WPF project, MainWindow.xaml is the View. It contains a MapView control that displays a map. This is where you would add any other controls or code for interacting with the user. MapViewModel.cs contains a ViewModel class (MapViewModel) consumed by the View. This is where the Map is created and exposed to the View (using data binding to display it in the MapView). Any business logic required by your app (that is not directly related to the user-interface) goes here.

Don't worry if this is a little confusing right now ... once you start working with these components it'll make more sense.

 

Where does the map come from?

If you haven't seen an MVVM app before, it can sometimes be confusing to see how things are wired up. If you run your project, for example, you'll see a map show up even though there doesn't appear to be much in MainWindow.xaml to make that happen.

Here's the XAML that defines the MapView:

<esri:MapView Map="{Binding Map, Source={StaticResource MapViewModel}}" />

OK, so data binding is used to set the MapView.Map property. The source of the binding is a StaticResource called MapViewModel.

You'll find this resource defined in the Window's resources like this:

<local:MapViewModel x:Key="MapViewModel" />

A little more detective work tells you that the local XML namespace is defined to point to the current project (the name of your project will vary).

xmlns:local="clr-namespace:MyWpfApp1"

So ... MapViewModel is a class in the current project. Another look at the binding for the MapView reveals that it is bound to a property on MapViewModel called "Map". If you open MapViewModel.cs, you'll find the definition of the MapViewModel class and the Map property:

private Map _map = new Map(Basemap.CreateStreetsVector());

/// <summary>
/// Gets or sets the map
/// </summary>
public Map Map
{
    get { return _map; }
    set { _map = value; OnPropertyChanged(); }
}

 

Let's modify the code in the ViewModel to create the Map from a portal item (webmap) instead.

 

Add code to open the webmap from the portal

You will add code that replaces the default basemap in the app with a web map stored with your ArcGIS Online account (or one shared publically by someone else).

  1. Open the MapViewModel.cs file.
  2. Add the following using statement at the top of the module:
    using Esri.ArcGISRuntime.Portal;
  3. Create a new asynchronous function, called LoadWebMap, to get the web map from ArcGIS Online using its ID and display it in the map view:
    private async void LoadWebMap(string webMapId)
    {
        // Connect to ArcGIS Online
        ArcGISPortal arcgisOnline = await ArcGISPortal.CreateAsync();

        // Open the webmap using it's item ID
        PortalItem webMapItem = await PortalItem.CreateAsync(arcgisOnline, webMapId);

        // Create a new Map from the portal item
        Map webMap = new Map(webMapItem);

        // Load the Map so it's properties are immediately available
        await webMap.LoadAsync();

        // Set the MapViewModel.Map property with the new Map
        this.Map = webMap;
    }
  4. Call the LoadWebMap function in the class constructor. Replace "<put-your-webmap-id-here>" with the actual ID of your webmap (unless, by strange coincidence, this is the actual ID of your webmap ).
  5. public MapViewModel()
    {
        LoadWebMap("<put-your-webmap-id-here>");
    }
  6. Run the project again. This time, the app should launch and display your web map. US Wildlife Activity Map

 

Looks a little different? If you're using the map we created in the previous post, you probably noticed that the crime index layer doesn't draw and only your basemap (and initial extent) carry over from the web map you saved. If you're using the US Wildfire Activity Map (shown above), you'll notice the AccuWeather layer is missing. The missing layers are ArcGIS Online premium content, and require an ArcGIS Online account to view. If you're interested in tackling the security implementation required to access this layer, stay tuned for the next post. For now, let's continue to work with the web map by displaying the available bookmarks.

 

Add a bookmark list

You will add a list (combo box) to the user interface that shows the bookmarks saved with the webmap. When the user selects one, the map view will update to show the selected area.

  1. Start by adding a MapBookmarks property to MapViewModel. This property will look similar to the existing Map property: it gets or sets a private copy of the value, and raises OnPropertyChanged when it's set so the View databindings are updated as expected. 
    private BookmarkCollection _bookmarks;

    public BookmarkCollection MapBookmarks
    {
        get { return _bookmarks; }
        set { _bookmarks = value; OnPropertyChanged(); }
    }

     

  2. Add a line to the end of the LoadWebMap function that sets the MapBookmarks property by reading the webmap's bookmarks. 
    this.MapBookmarks = webMap.Bookmarks;
  3. Open the XAML for the View (MainWindow.xaml). Let's make some changes to the UI to accomodate a new bookmarks list at the top. Replace the current <Grid> element in the page with the following XAML. Note that the new ComboBox uses data binding to show the bookmarks from the ViewModel.
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <ComboBox Grid.Row="0"
            Height="25" Width="200"
            ItemsSource="{Binding MapBookmarks, Source={StaticResource MapViewModel}}"
            DisplayMemberPath="Name"
            SelectionChanged="ComboBox_SelectionChanged"/>

        <esri:MapView x:Name="MyMapView" Grid.Row="1"
                Map="{Binding Map, Source={StaticResource MapViewModel}}" />

    </Grid>

     

  4. Open the code-behind for the View (MainWindow.xaml.cs). Add the following code to handle selections in the ComboBox.
    private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        // Get the first selected item (should be exactly one)
        var bookmark = e.AddedItems[0] as Esri.ArcGISRuntime.Mapping.Bookmark;

        // If no bookmark selected, exit
        if (bookmark == null) { return; }

        // Set the viewpoint for the map view using the bookmark's viewpoint
        MyMapView.SetViewpointAsync(bookmark.Viewpoint);
    }

     

  5. Test your app. When your map loads, you should also have a list of bookmarks in the combo box above the map (assuming some have been saved with the web map). Choose bookmarks to change the area shown on the map.

 

OK, that's cool, but wait a second! Wasn't our map-related logic supposed to be in the MapViewModel and not in the View? Um, yeah ... but I can explain. The ComboBox.SelectionChanged event is fired from the user interface, so it makes sense that the event handler is here. Also, the MapView control is a user interface component (thus the word "View" in the name), so it's OK to interact with it in the view code. Yes, there are some people who would say this is not a strict enough implementation of MVVM, and situations like this are a bit of a gray area. You could, for example, pass a reference to the MapView into the MapViewModel constructor. You would then be able call into the ViewModel to change the viewpoint (passing a new viewpoint in). In the end, remember the goal is code reuse and maintainability.

 

Look for the next post in this series, where I'll show you how to implement OAuth authorization for accessing secured content.

Outcomes