Chapter 6. Displaying Information

So far, we've created maps and scenes, added layers, learned about geometry and symbology, and so on, but now we need to learn about displaying and interacting with the map or scene. Adding information such as graphics has already been discussed, but what if you want to see the mouse's coordinates in latitude/longitude? What if you have lots of layers and want to have overlays (map tips) for each one of them that are customized for the layer? How do you show a legend, so users can discern what is on the map? Lastly, how do you show your location on the map or scene? All of these are questions that production-level apps need to address so that users can quickly understand what is being presented and where they are. In this chapter, we will discuss the following topics:

  • MVVM mouse events
  • Labeling
  • Legend
  • Scale bar
  • Overlays
  • Showing locations

MVVM mouse events

Being able to interact with the layers in the map is a very important capability that your users will expect. Otherwise, the map is just a pretty picture. To provide this capability in a non-MVVM app would simply require adding a click event to the code-behind file of MainWindow.cs. Another feature that your user might expect is the ability to see coordinates on the map as they move the mouse. But how do we accomplish this with MVVM in such a way that we can move our code from MainWindow.cs to another place?

Well, you already know the answer. We create a UserControl task with ViewModel and have it display the coordinates in the XAML code of UserControl. Let's implement this:

  1. Create a new ArcGIS Runtime project. In this example, we're going to name it Chapter6. Copy the following folders: Behavior, Models, Services, and ViewModels. Install MVVM Light and Json.Net, and add a reference to System.Windows.Interactivity (4.5). When you install MVVM Light, a ViewModel directory will be created. Delete it. Update App.xaml with a reference to the Chapter6.ViewModels folder. Update all other references and the using statements. Copy the XAML code from MainWindow.xaml in Chapter3a to the MainWindows.xaml file in your new app. Make sure the app builds.
  2. Create a new folder and name it UserControls. Add a new UserControl (WPF) item to this app. Name it CoordinateDisplayUserControl.xaml.
  3. Create a new ViewModel class in the ViewModels folder and name it CoordinateDisplayViewModel.cs.
  4. Add the following using statements to CoordinateDisplayViewModel.cs:
    using GalaSoft.MvvmLight.Messaging;
    
    using Esri.ArcGISRuntime.Controls;
    using Esri.ArcGISRuntime.Geometry;
    using System;
  5. In the constructor, add the following lines. When you create the MouseMove event handler, press Tab twice to create it:
    Messenger.Default.Register<Esri.ArcGISRuntime.Controls.MapView>(this, (mapView) =>
    {
        this.mapView = mapView;
    
        this.mapView.MouseMove += mapView_MouseMove;
    }); 
  6. In the MouseMove event handler (mapView_mouseMove), add the following lines:
    if (this.mapView.Extent == null)
        return;
    System.Windows.Point screenPoint = e.GetPosition(this.mapView);
    MapPoint mapPoint = this.mapView.ScreenToLocation(screenPoint);
    if (this.mapView.WrapAround)
        mapPoint = GeometryEngine.NormalizeCentralMeridian(mapPoint) as MapPoint;
    
    this.Latitude = Math.Round(mapPoint.Y, 4);
    this.Longitude = Math.Round(mapPoint.X, 4);

    As you can see, we are taking the Screen coordinate and converting it to MapPoint using ScreenToLocation. If WrapAround is turned on, we use the GeometryEngine class to normalize the MapPoint class. Finally, we get the coordinates and store them in two properties so that we can bind to them.

  7. Add the following two properties to this class:
    public double Latitude
    {
        set 
        {
            this.latitude = value;
            RaisePropertyChanged("Latitude");
        }
        get { return this.latitude; }        
    }
    public double Longitude
    {
        set
        {
            this.longitude = value;
            RaisePropertyChanged("Longitude");
        }
        get { return this.longitude; } 
    }
  8. Add the new ViewModel class to the locator (ViewModelLocator.cs):
    SimpleIoc.Default.Register<CoordinateDisplayViewModel>();
  9. Open up CoordinateDisplayUserContro.xaml and enter the following code:
    <UserControl x:Class="Chapter6.UserControls.CoordinateDisplayUserControl"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
        xmlns:vm="clr-namespace:Chapter6.ViewModels"
        mc:Ignorable="d" 
        d:DesignHeight="300" d:DesignWidth="500">
    
        <UserControl.Resources>
            <vm:CoordinateDisplayViewModel x:Key="Locator" 
                d:IsDataSource="True"/>
        </UserControl.Resources>
    
        <Grid DataContext="{Binding CoordinateDisplayViewModel, 
            Source={StaticResource Locator}}">
            <StackPanel Orientation="Horizontal">
                <Border  Background="Transparent" BorderBrush="Black" 
                        BorderThickness="1"
                    HorizontalAlignment="Left" VerticalAlignment="Top"
                    Margin="30" Padding="20">
                    <Border.Effect>
                        <DropShadowEffect/>
                    </Border.Effect>
                    <StackPanel >
                        <StackPanel>
                            <StackPanel Orientation="Horizontal">
                                <TextBlock x:Name="Latitude" 
                                    Foreground="White"
                                    HorizontalAlignment="Left" 
                                    VerticalAlignment="Center" 
                                    Text="Latitude: " Width="80"  
                                        TextWrapping="Wrap" 
                                        FontWeight="Bold" />
                                <TextBlock x:Name="LatitudeValue" 
                                    Foreground="White"
                                    HorizontalAlignment="Left" 
                                    VerticalAlignment="Center" 
                                    TextAlignment="Right"
                                    Text="{Binding Latitude, Mode=TwoWay, 
                                    UpdateSourceTrigger=PropertyChanged, 
                                    Source={StaticResource Locator}}" 
                                    Width="80" FontWeight="Bold" />
                            </StackPanel>
                            <StackPanel Orientation="Horizontal">
                                <TextBlock x:Name="Longitude" 
                                    Foreground="White"
                                    HorizontalAlignment="Left" 
                                    VerticalAlignment="Center" 
                                    Text="Longitude: " 
                                    TextWrapping="Wrap" 
                                    FontWeight="Bold" />
                                <TextBlock x:Name="LongitudeValue" 
                                    Foreground="White"
                                    HorizontalAlignment="Left" 
                                    VerticalAlignment="Bottom" 
                                    TextAlignment="Right"
                                    Text="{Binding Longitude,
                                        Mode=TwoWay,
                                    UpdateSourceTrigger=PropertyChanged, 
                                    Source={StaticResource Locator}}" 
                                    Width="95" FontWeight="Bold" />
                            </StackPanel>
                        </StackPanel>
                    </StackPanel>
                </Border>
            </StackPanel>
        </Grid>
    </UserControl>

    Note that the resource of UserControl has been set to the locator and that the Grid tag has been set to CoordinateDisplayViewModel. Other than that, the two TextBlock properties are binding to the ViewModel class' properties (Latitude and Longitude).

  10. Add the new user control to the MainWindow.xaml file by first adding a using statement to MainWindow.xaml like this:
    xmlns:uc="clr-namespace:Chapter6.UserControls"
  11. Then, add the user control after the closing </MapView> tag like this:
    <uc:CoordinateDisplayUserControl VerticalAlignment="Top"></uc:CoordinateDisplayUserControl>
  12. Run the app. As you move the mouse over the map, you will see the coordinates update based on the mouse's position, as we can see here:
MVVM mouse events

Coordinates based on the mouse's position

If you recall, in Chapter 1, Introduction to ArcGIS Runtime, we did something similar with the map scale but that was with the code-behind file. This time, we did it with a more MVVM-friendly approach. Of course, we could refactor this code to pass off the coordinates to a factory service, but for the sake of brevity we left this out.

While we used a UserControl task with a ViewModel class to solve this issue, we could have used other approaches too. We could have used Behavior, TargetedTriggerAction, or ChangePropertyAction. Look them up in Microsoft's documentation, give them a try, and see which one you prefer.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.128.105