Visually Located

XAML and GIS

Creating a behavior to control the new StatusBar (SystemTray) in Windows Phone 8.1 XAML apps

In a recent post I described creating a behavior to control the new StatusBarProgressIndicator. This is because the new progress indicator can only be accessed via code. A behavior allows us to control it via XAML. Just like the progress indicator, the new StatusBar (known as the SystemTray in Windows Phone Silverlight apps) can also only be accessed via code. I still prefer a behavior for getting this type of functionality into a page over using a custom control. It just makes sense. Before you begin, add a reference to the Behaviors SDK (XAML)

image

We’ll start off creating a new StatusBarBehavior class and inherits from DependencyObject and implements the IBehavior interface.

public class StatusBarBehavior : DependencyObject, IBehavior
{
    public void Attach(DependencyObject associatedObject)
    {        
    }
 
    public void Detach()
    {
    }
 
    public DependencyObject AssociatedObject { get; private set; }
}

For this behavior, we will not need to hook into the associated dependency object. However, it’s important to note that we could get and store the StatusBar object within the Attach method. We’ll want to add dependency properties to the behavior that will control the visibility, foreground and background colors and the opacity of the status bar. When creating a behavior to wrap existing functionality it is important that the default values of your properties match the default values of the functionality you are wrapping. This is because we want our PropertyChangedCallback methods to be called when the value is changed and function accordingly. Each of the properties we implement will need to account for these default values.

We’ll first look at changing the visibility. In the SystemTray from Windows Phone Silverlight apps, you would control visibility with the IsVisible property. We’ll keep that name as it’s familiar, and can easily be used with binding in a view model. The StatusBar defaults to being visible, so the default value needs to be true

public bool IsVisible
{
    get { return (bool)GetValue(IsVisibleProperty); }
    set { SetValue(IsVisibleProperty, value); }
}
 
public static readonly DependencyProperty IsVisibleProperty =
    DependencyProperty.Register("IsVisible",
    typeof(bool),
    typeof(StatusBarBehavior),
    new PropertyMetadata(true, OnIsVisibleChanged));
 
private static void OnIsVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    bool isvisible = (bool)e.NewValue;
    if (isvisible)
    {
        StatusBar.GetForCurrentView().ShowAsync();
    }
    else
    {
        StatusBar.GetForCurrentView().HideAsync();
    }
}

This should look very similar from the behavior to control the progress indicator. Next we’ll create a property for the opacity of the background. Unlike in Windows Phone Silverlight Apps, the opacity defaults to 0. Our property should also default to 0.

public double BackgroundOpacity
{
    get { return (double)GetValue(BackgroundOpacityProperty); }
    set { SetValue(BackgroundOpacityProperty, value); }
}
 
public static readonly DependencyProperty BackgroundOpacityProperty =
    DependencyProperty.Register("BackgroundOpacity",
    typeof(double), 
    typeof(StatusBarBehavior), 
    new PropertyMetadata(0d, OnOpacityChanged));
 
private static void OnOpacityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    StatusBar.GetForCurrentView().BackgroundOpacity = (double)e.NewValue;         
}
Alright, we’re cruising right along, this is easy. Next we’ll tackle the background and foreground colors. This is where it starts to get a little weird. The StatusBar implements the background and foreground with

Nullable<Color>. When we created the ProgressBehavior, we found that when we tried to create a dependency property in our behavior that it had some issues. We have issues again, but now they are different. Based on the last post, create the ForegroundColor property as you think you would with a nullable Color property.

public Color? ForegroundColor
{
    get { return (Color?)GetValue(ForegroundColorProperty); }
    set { SetValue(ForegroundColorProperty, value); }
}
 
public static readonly DependencyProperty ForegroundColorProperty =
    DependencyProperty.Register("ForegroundColor", 
    typeof(object), 
    typeof(StatusBarBehavior), 
    new PropertyMetadata(null, OnForegroundColorChanged));
 
private static void OnForegroundColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    StatusBar.GetForCurrentView().ForegroundColor = (Color) e.NewValue;
}

While this may work for binding, this fails in XAML. Trying this out as is:

<i:Interaction.Behaviors>
    <local:StatusBarBehavior ForegroundColor="Blue"/>
</i:Interaction.Behaviors>

Gives us the following error:

XamlCompiler error WMC0056: Cannot assign to nullable type on property ForegroundColor

So, we will not be able to use the Nullable<Color> for the foreground and background color. That’s fine because I doubt anyone would bind to a null value. Let’s correct that ForegroundColor property

public Color ForegroundColor
{
    get { return (Color)GetValue(ForegroundColorProperty); }
    set { SetValue(ForegroundColorProperty, value); }
}
 
public static readonly DependencyProperty ForegroundColorProperty =
    DependencyProperty.Register("ForegroundColor", 
    typeof(Color), 
    typeof(StatusBarBehavior), 
    new PropertyMetadata(null, OnForegroundColorChanged));

Notice that we can set the default value to null (weird). The BackgroundColor will require a little extra work. Because the BackgroundOpacity defaults to 0, setting the BackgroundColor will do nothing unless the opacity is changed as well. We could take two approaches with the behavior, either force the use of the opacity property, or set the opacity if the background is set. I like the latter option. If the background is set, then obviously they want to see it!

public Color BackgroundColor
{
    get { return (Color)GetValue(BackgroundColorProperty); }
    set { SetValue(BackgroundColorProperty, value); }
}
 
public static readonly DependencyProperty BackgroundColorProperty =
    DependencyProperty.Register("BackgroundColor", 
    typeof(Color), 
    typeof(StatusBarBehavior), 
    new PropertyMetadata(null, OnBackgroundChanged));
 
private static void OnBackgroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var behavior = (StatusBarBehavior) d;
    StatusBar.GetForCurrentView().BackgroundColor = behavior.BackgroundColor;
 
    // if they have not set the opacity, we need to so the new color is shown
    if (behavior.BackgroundOpacity == 0)
    {
        behavior.BackgroundOpacity = 1;
    }
}

Now we have a complete behavior that is very similar to the Windows Phone Silverlight SystemTray.

<Page
    ...
    xmlns:i="using:Microsoft.Xaml.Interactivity">
    <i:Interaction.Behaviors>
        <local:StatusBarBehavior IsVisible="True" 
                                 BackgroundColor="#FF0000"
                                 ForegroundColor="Blue"/>
    </i:Interaction.Behaviors>
    <Grid>
        <!-- Content -->
    <Grid>
</Page>

Download a sample to play with the behavior, or just download the behavior.

Differences between the new StatusBar in Windows Phone XAML Apps and the SystemTray

With the release of Windows Phone 8.1 SDK comes a new StatusBar. The StatusBar replaces the SystemTray from Windows Phone Silverlight Apps. Unlike the SystemTray, the StausBar can only be accessed via code and some functionality has changed. This post will go in depth on how to access the the StatusBar and what the differences are.

Just like the new StatusBarProgressIndicator, you can only access the StatusBar via code with the GetForCurrentView method.

StatusBar statusBar = Windows.UI.ViewManagement.StatusBar.GetForCurrentView();

Once you have the StatusBar, you have access to the same capabilities as you did before, with a few changes. The table below shows

SystemTray StatusBar Comments
System.Windows.Media.Color ForegroundColor Windows.UI.Color? ForegroundColor  
System.Windows.Media.Color BackgroundColor Windows.UI.Color? BackgroundColor  
bool IsVisible IAsyncAction HideAsync()
IAsyncAction ShowAsync()
Two methods replace the single DependencyProperty
double Opacity double BackgroundOpacity Does not shift content up when value is less than 1
  event Hiding New!
  event Showing New!

 

The biggest different in the table above is not the new events, it’s not the change from IsVisible to the new methods. The biggest difference is the change is functionality in setting the opacity. In Windows Phone Silverlight Apps, when you set the Opacity to a value less that 1, the page content shifts up into the space of the tray. Now when you set the BackgroundOpacity the page content does not shift up. I like this change as it makes the opacity property of all other XAML controls. So how do you shift content up into the status bar area? This functionality is still available, and like the rest of the StatusBar, is only accessible in code. The ApplicationView class provides this functionality with the SetDesiredBoundsMode method.

Windows.UI.ViewManagement.ApplicationView.GetForCurrentView()
    .SetDesiredBoundsMode(ApplicationViewBoundsMode.UseCoreWindow);

The BackgroundOpacity also defaults to 0 which means that only setting the BackgroundColor will not change the background. You must also set the opacity to the desired value.

var statusBar = StatusBar.GetForCurrentView();
statusBar.BackgroundOpacity = 1;
statusBar.BackgroundColor = Colors.Red;

Just like the new StatusBarProgressIndicator, the StatusBar lost the IsVisible property in favor of two async methods to set visibility.

StatusBar statusBar = Windows.UI.ViewManagement.StatusBar.GetForCurrentView();
// Hide the status bar
await statusBar.HideAsync();
 
//Show the status bar
await statusBar.ShowAsync();

The status bar does have two new events for when the status bar is shown or hidden!

The rest of the StatusBar is very similar to the SystemTray. You even have access to the new StatusBarProgressIndicator.

StatusBar statusBar = Windows.UI.ViewManagement.StatusBar.GetForCurrentView();
StatusBarProgressIndicator progress = statusBar.ProgressIndicator;
If you are not a fan with accessing the StatusBar in code only, you can create a behavior for accessing it in XAML.

Using a behavior to control the ProgressIndicator in Windows Phone 8.1 XAML Apps

In the last post I talked about showing a ProgressIndicator in a Windows Phone 8.1 XAML App. I mentioned that with the new API you can only show the ProgressIndicator through code. This means that you cannot show the progress indicator using binding, you cannot set a Loading property, or something similar to show/hide the indicator. I’m not a fan of this solution. I like using XAML and keeping my view models simple. I saw three possible solutions to overcome this and show/hide/modify the progress indicator in xaml. The first is to create a control, use a third party progress indicator, or to use a behavior. I didn’t fully like the first or second solutions as it would require you to put the control inside the content of a page. This just didn’t seem right.

<Page>
    <Grid>
        <custom:ProgressIndicator/>
        <!-- content for page -->
    </Grid>
</Page>

Creating a behavior allows you to place the progress indicator in the same place as you had it when building Windows Phone apps with Silverlight.

<Page>
    <i:Interaction.Behaviors>
        <local:ProgressBehavior IsVisible="{Binding Loading}" Text="Loading"/>
    </i:Interaction.Behaviors>
    <Grid>
        <!-- content for page -->
    </Grid>
</Page>

We’ll build a Behavior that will allow us to set properties in XAML, just like we had in Silverlight apps. To use behaviors in your project, you must add a reference to the Behaviors SDK (XAML).

image

Add a new class to the project called ProgressBehavior and implement the IBehavior interface.

public class ProgressBehavior : DependencyObject, IBehavior
{
    public DependencyObject AssociatedObject { get; private set; }
 
    public void Attach(DependencyObject associatedObject)
    {
    }
 
    public void Detach()
    {
    }
}

The interface is simple, and for this behavior we will not need to do anything with the methods or property. Instead we’ll add a few dependency properties. I don’t want to completely replicate the Silverlight ProgressIndicator with this behavior so we won’t be implementing all four properties that it had. We will provide a way to set the value, show and hide the indicator and set the text. First we’ll add a dependency property for the text. When creating dependency properties, it’s best to use the ‘propdp’ built-in shortcut. Type propdp and then the tab button. Your property will be stubbed out and allow you to fill in the needed values.

public int MyProperty
{
    get { return (int)GetValue(MyPropertyProperty); }
    set { SetValue(MyPropertyProperty, value); }
}
 
// Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyPropertyProperty =
    DependencyProperty.Register("MyProperty", typeof(int), typeof(ownerclass), new PropertyMetadata(0));

First type the type of the property, the Text property will be a string. Then hit tab and give the property a name, hit tab and fill out the rest of the properties (ownerclass will be ProgressBehavior).

public string Text
{
    get { return (string)GetValue(TextProperty); }
    set { SetValue(TextProperty, value); }
}
 
public static readonly DependencyProperty TextProperty =
    DependencyProperty.Register("Text",
    typeof(string),
    typeof(ProgressBehavior),
    new PropertyMetadata(null, OnTextChanged));

Notice on the last line, I added OnTextChanged to the constructor to PropertyMetadata. This specifies a method to call when the property changes. When the text changes we’ll set the text of the progress indicator.

private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    ProgressBehavior behavior = (ProgressBehavior)d;
    StatusBar.GetForCurrentView().ProgressIndicator.Text = behavior.Text;
}

Next we’ll create a dependency property to toggle the visibility. I like the IsVisible property from the Silverlight Phone SDK because there is no need for converters like a BooleanToVisibilityConverter. We will again need to interact with the progress indicator when the IsVisible value changes.

public bool IsVisible
{
    get { return (bool)GetValue(IsVisibleProperty); }
    set { SetValue(IsVisibleProperty, value); }
}
 
public static readonly DependencyProperty IsVisibleProperty =
    DependencyProperty.Register("IsVisible",
    typeof(bool),
    typeof(ProgressBehavior),
    new PropertyMetadata(false, OnIsVisibleChanged));
 
private static void OnIsVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    bool isvisible = (bool)e.NewValue;
    if (isvisible)
    {
        StatusBar.GetForCurrentView().ProgressIndicator.ShowAsync();
    }
    else
    {
        StatusBar.GetForCurrentView().ProgressIndicator.HideAsync();
    }
}

The last dependency property will control the ProgressValue of the indicator as well as if the indicator is indeterminate. This property is not as straight forward as you would think. Following the pattern from before, we would declare the property as such.

public double? Value
{
    get { return (double?)GetValue(ValueProperty); }
    set { SetValue(ValueProperty, value); }
}
 
public static readonly DependencyProperty ValueProperty =
    DependencyProperty.Register("Value",
    typeof(double?),
    typeof(ProgressBehavior),
    new PropertyMetadata(null, OnValueChanged));
 
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    double? val = (double?)e.NewValue;
    StatusBar.GetForCurrentView().ProgressIndicator.ProgressValue = val;
}

Now it would seem that our behavior is complete. We’ve declared the Text, IsVisible, and Value properties. The behavior will modify the StatusBarProgressIndicator when values change. Yup, we’re all done. However, when we try to change the value of the indicator, nothing happens. Well, not nothing, we do get the following error in the output window while debugging

Error: Converter failed to convert value of type 'Double' to type 'IReference`1<Double>'; BindingExpression: Path='LoadingValue' DataItem='ProgressBehaviorSample.ViewModel, ProgressBehaviorSample, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'; target element is 'ProgressBehaviorSample.ProgressBehavior' (Name='null'); target property is 'Value' (type 'IReference`1<Double>').

I could go into detail about this, but Dan Rigby already did that. The short of it the nullable double in .NET does not convert nicely to IReference in Windows Runtime. We can fix that by changing the second parameter of the DependencyProperty.Register in our Value dependency property from double? to object. Our property still remains double?.

public static readonly DependencyProperty ValueProperty =
    DependencyProperty.Register("Value",
    typeof(object),
    typeof(ProgressBehavior),
    new PropertyMetadata(null, OnValueChanged));

Now that we have that fixed the property, our behavior is complete and can be used like such.

<i:Interaction.Behaviors>
    <local:ProgressBehavior IsVisible="{Binding Loading}"
                            Text="Loading"/>
         <!-- feel free to put a value in as well :) -->
</i:Interaction.Behaviors>

Take this behavior for a spin with a complete working sample or just download the behavior. This sample is a little weird because it uses a viewmodel that has properties that you would normally not use. But they are there for the purpose of being able to change the indicator values in the app.

Showing the system ProgressIndicator in a Windows Phone 8.1 XAML app

If you have built a Windows Phone app before, you probably used the ProgressIndicator to indicate to the user that something was being done. The ProgressIndicator could show indeterminate dots floating from left to right to indicate that you have no idea how long the operation will take to complete. Or it would show a progress bar that would tell the user how much progress has been made. You could show the ProgressIndicator in code, but most likely used xaml.

<shell:SystemTray.ProgressIndicator>
    <shell:ProgressIndicator IsIndeterminate="True" Text="Loading" 
                             IsVisible="{Binding Loading}" />
</shell:SystemTray.ProgressIndicator>

The new Windows Phone 8.1 Apps for XAML also includes the ability to show progress with a ProgressIndicator, now called StatusBarProgressIndicator. Unlike Phone apps built with Silverlight, the new Phone 8.1 SDK does not include a way to interact with the StatusBarProgressIndicator in XAML. You must use the StatusBar static class to work with the StatusBarProgressIndicator.

StatusBarProgressIndicator progressbar = StatusBar.GetForCurrentView().ProgressIndicator;

The table below shows the differences between the ProgressIndicator  and the StatusBarProgressIndicator.

ProgressIndicator StatusBarProgressIndicator Comments
string Text string Text  
double Value double? ProgressValue When the value is null, shows indeterminate dots
bool IsVisible IAsyncAction ShowAsync()
IAsyncAction HideAsync()
Two methods replace the single DependencyProperty
bool IsIndeterminate   replaced with the nullable double ProgressValue

 

As you can see, the API for the ProgressIndicator has changed a lot. Where the Silverlight API has four dependency properties, the new API has two. The IsVisible property has been replaced with two async methods. With these changes, if you want to show progress, you’ll have to do it in code.

StatusBarProgressIndicator progressbar = StatusBar.GetForCurrentView().ProgressIndicator;
progressbar.Text = "Loading";
progressbar.ShowAsync();

This stinks if you want to control the loading state from a view model. But the API is accessible from a static class, so you can access the StatusBarProgressIndicator from a view model, provided your view model is not in a portable class library.

You can download a sample that shows controlling the StatusBarProgressIndicator.

Progress

Overall this kind of stinks.There must be a better way, right? Read Part 2: Using a behavior to control the ProgressIndicator in Windows Phone 8.1 XAML Apps.

Transitioning your app from the Panorama control to the Hub control

At //build today Microsoft announced the new Universal Apps that will allow you to build desktop, tablet and phone apps using the same code. These are different than PCLs as they allow for platform functionality (I won’t get into differences between PCLs and Shared Projects here). These new apps will be based on the XAML platform that Windows tablet apps are built on. So this means that you can build Windows Phone apps with new XAML elements that are available in Windows [tablet] Apps like the GridView, ListView, Hub and more. This also means that Silverlight Windows Phone controls will not be available. One of these missing controls is the Panorama control. We’ll look at how we can take an existing Panorama app, and convert it to a Hub app. Migrating to the Hub control from the Panorama control is very easy.

To start, I’ll create a new Windows Phone [Silverlight] Panorama app. I’ll call in PanoramaConversion.

image

Next I’ll add a new project to the solution.

image

For this project I’ll create a new Windows Phone (not Silverlight) Blank App. I’ll call this one ConvertedPanoramaApp.

image

Open MainPage.xaml from the PanoramaConversion project. Select all of the xaml for the Panorama control. To make it easy, you can collapse the element, move your mouse to the left and select the entire section. Copy this xaml element and then paste it into the Grid element in the MainPage from the ConvertedPanoramaApp project.

image

Notice all of the blue squiggly lines? We’ll need to fix these. Most of the errors can be fixed with find/replace. We’ll perform the following find/replace operations

  • replace phone:PanoramaItem with HubSection
  • replace phone:Panorama with Hub
  • replace Title with Header – The Hub control has a Header property while the Panorama control had a Title property.
  • replace Orientation="Horizontal" with Width=”Auto” – The HubSection does not have an Orientation property, instead it defines the Width of the control to be 360. Setting the Width to Auto allows it to scroll horizontally.

Because we copied the app as-is. It contains a few LongListSelector controls. This control is not available in Windows Phone XAML apps so we’ll have to replace the use of it with the ListView control. The Panorama App project template has simple uses for the LLS, so it won’t be hard to replace.

  • replace phone:LongListSelector with ListView
  • replace ListHeaderTemplate with HeaderTemplate

You’ll notice we still have a lot of problems with the xaml.

image

This is because the PanoramaItem is a ContentControl while the HubSection is just a Control. This means that the PanoramaItem allows for direct content within the element. However, the HubSection does define a ContentProperty attribute. This class attribute defines that something can go within the control element. The HubSection defines that a ControlTemplate can be used as it’s “Content”. So we’ll need to wrap the content of the HubSection with a DataTemplate.

<HubSection Header="third item" Width="Auto">
    <DataTemplate>
        <!--Double wide Panorama with large image placeholders-->
        <Grid>
            <StackPanel Margin="0,4,16,0" Orientation="Vertical" VerticalAlignment="Top">
                <StackPanel HorizontalAlignment="Left" Orientation="Horizontal">
                    <Border Background="#FFFFC700" Height="173" Width="173" Margin="12,0,0,0"/>
                    <Border Background="#FFFFC700" Height="173" Width="173" Margin="12,0,0,0"/>
                    <Border Background="#FFFFC700" Height="173" Width="173" Margin="12,0,0,0"/>
                    <Border Background="#FFFFC700" Height="173" Width="173" Margin="12,0,0,0"/>
                </StackPanel>
                <StackPanel HorizontalAlignment="Left" Orientation="Horizontal" Margin="0,12,0,0">
                    <Border Background="#FFFFC700" Height="173" Width="173" Margin="12,0,0,0"/>
                    <Border Background="#FFFFC700" Height="173" Width="173" Margin="12,0,0,0"/>
                    <Border Background="#FFFFC700" Height="173" Width="173" Margin="12,0,0,0"/>
                    <Border Background="#FFFFC700" Height="173" Width="173" Margin="12,0,0,0"/>
                </StackPanel>
            </StackPanel>
        </Grid>
    </DataTemplate>
</HubSection>

Next we’ll bring the existing background image into the new project. In the Solution Explorer window, drag and drop the PanoramaBackground.png file to the Assets folder in the new project.

image

Once that is copied over, change the Hub Background ImageBrush source to /Assets/PanoramaBackground.png (remove the /PanoramaConversion;component portion). You’ll notice that now the designer is rendering our Hub control

image

You’ll notice the text for the HubSection headers is much smaller than it was in the PanoramaItem. You can make the choice to scale this by using the HeaderTemplate of the HubSection.

<HubSection.HeaderTemplate>
    <DataTemplate>
        <TextBlock Text="{Binding}" FontSize="40"/>
    </DataTemplate>
</HubSection.HeaderTemplate>

image

Usually best to put this into a resource that can be used across all HubSections. The last thing for our conversion is to remove or replace the use of the Phone [Silverlight] specific resources like PhoneTextExtraLargeStyle and PhoneFontSizeLarge. There are replacements, so we can make the following changes.

  • PhoneFontSizeLarge – TextStyleLargeFontSize
  • StaticResource PhoneTextSubtleStyle – ThemeResource ListViewItemSubheaderTextBlockStyle
  • StaticResource PhoneTextExtraLargeStyle – ThemeResource ListViewItemTextBlockStyle

We’ll still need to bring over the sample data from the original app, but I’ll let you do this Smile.

You should also be aware that the Hub control will occupy the space of the StatusBar by default. You'll want to take this into account and ensure that the content from the StatusBar does not interfere with the content from your app. 


You can download a sample project here.

Working with location in an ArcGIS Runtime map app

This is the forth blog in a series of posts reviewing the new ArcGIS Runtime (beta) mapping SDK. The new SDK will be a great companion for any Windows developer wanting to add map functionality to their apps. In part 3, we looked at the MapView control within the SDK. One of the dependency properties that I left off in that post is the LocationDisplay property. This post will go into that property extensively. Working with location is probably my favorite part of the new ArcGIS Runtime mapping SDK because it is just so damn simple. In most mapping SDKs (eg: Nokia, Bing) you must do the work of hooking up to location changes, and updating the map. In the ArcGIS Runtime mapping SDK, it’s handled for you if you opt in for this functionality. Start off by downloading the sample application (if you have not done so already).

The LocationDisplay property of the MapView provides access to the LocationDisplay class. This class provides access to all the properties that make working with location in the SDK pure awesomesauce. Turning on location tracking, and the display of location on the map is as simple as setting IsEnabled to true! Let me say that again, setting one property to true, enabled GPS location within your app, places a symbol on the map indicating the current location, tracks location changes, and updates the symbol when location changes. Let’s take a look at the xaml needed to make this happen. Open up the xaml of any of the pages in the app. I’ll open the ArcGISTiledLayerPage.

<esri:MapView Grid.Row="1">
    <esri:MapView.Map>
        <esri:Map>
            <layers:ArcGISTiledMapServiceLayer ServiceUri="http://services.arcgisonline.com/arcgis/rest/services/World_Street_Map/MapServer"/>
        </esri:Map>
    </esri:MapView.Map>
    <esri:MapView.LocationDisplay>
        <location:LocationDisplay IsEnabled="True"/>
    </esri:MapView.LocationDisplay>
</esri:MapView>

Enable the Location capability in your app (open Package.appxmanifest, Capabilities tab) and start the application. Select the map that you edited and it will prompt you to use location,

image

Allow location, and you’ll see your location on the map!

image

Unfortunately our location not centered on the map. If you want to track location, and center the map on the user, you’ll want to change the AutoPanMode. The AutoPanMode enumeration is a little confusing because the default value of the enum is Off, despite having a member named Default. I agree that you do not want the default value to center the map, but the wording is confusing. I’d like to see those change to Default, and On rather than Off and Default.

<location:LocationDisplay IsEnabled="True" AutoPanMode="Default" />

With our enum set to Default, the map now centers on the device! The location will update when you move and the map will re-center as well!

image

The AutoPanMode has two other values that make working with location even more awesome! Setting AutoPanMode to Navigation will change the map Rotation so that the top of the map faces the direction the user is facing. This is great for building routing apps where you want the road or path the user is driving, walking on to always face the direction the user is moving. This value will keep the map centered horizontally, but will show the location toward the bottom of the screen.

image

Setting AutoPanMode to CompassNavigation will always orient the map north. With these two AutoPanMode values of the LocationDisplay, you don’t even need to worry about the Rotation property from the last blog! How awesome is that?

image

Changing the symbology of the location marker is very simple. You can change the look of the CourseSymbol, HeadingSymbol (no doc link) or the DefaultSymbol. The CourseSymbol defines a symbol to use while location is actively changing. Great when using AutoPanMode.Navigation. The HeadingSymbol defines a symbol to be used when using AutoPanMode.CompassNavigation. And the DefaultSymbol defines the symbol to use when location is not changing.

<esri:MapView.LocationDisplay>
    <location:LocationDisplay IsEnabled="True" AutoPanMode="Default">
        <location:LocationDisplay.DefaultSymbol>
            <symbols:SimpleMarkerSymbol Style="Diamond"/>
        </location:LocationDisplay.DefaultSymbol>
    </location:LocationDisplay>
</esri:MapView.LocationDisplay>
image

 

The awesomeness doesn't stop there. What happens when you need to test, or demo location functionalioty? Should you start walking outside? Enventually, sure. But the LocationDisplay also allows you to set a LocationProvider that should be used. This simple interface allows you to define when location changes, when the device orientation is changed, or the speed of travel has changed (or all of them at once). Many times you want to test location, but you are at your desktop. Plugging in a quick little ILocationProvider allows you to do your testing.

Note: Location works great on all three platforms, but compass orientation only works for Windows Store and Windows Phone apps because they have built in APIs for compass.

These features should compel you to use the ArcGIS Runtime SDK for your next mapping app. In the next post I’ll cover map pins within the SDK.

Working with the MapView control in the ArcGIS Runtime

This is the third in a series of posts covering the new ArcGIS Runtime SDK. In part 2, I discussed the basic mapping layers within the ArcGIS Runtime. Now that we know how to add a map and layers to your app, let’s see what we can do with the map! As I mentioned in the first post, the new ArcGIS Runtime has a MapView, rather than a Map that you put in your app. The MapView has a Map property that must be set, but all of the functionality lies in the MapView. We’ll start out with some of the key dependency properties. We’ll then look at the map events, and finish with the few methods.

Dependncy Properties

The new MapView control has 11 dependency properties (with one additional attached dependency property). In this blog we’ll focus on seven of them. Not to worry about the other four. One we have already covered (Map), one will be covered in the next blog and two more when discussing GIS focused work. In this blog I’ll cover the following dependency properties.

MapGrid

The MapGrid is a new addition from the older .NET SDKs. I must say that this one is really cool. This allows you to display a map grid on the map. If you want to build an app with map, and not a GIS focused app, you may be wondering why this is useful. You could create your own MapGrid and have them be borders in a map. Maybe you are creating a multi-player game with a map. Each player has different zones they are responsible for.

The SDK comes with four map grids. The LatLonMapGrid shows latitude and, longitude on the map. The MgrsMapGrid displays the Military Grid Reference System. The UsngMapGrid shows the United States National Grid reference system. Finally, the UtmMapGrid shows the Universal Transverse Mercator coordinate system.

<esri:MapView>
    <esri:MapView.Map>
        <esri:Map>
            <layers:ArcGISTiledMapServiceLayer ServiceUri="http://services.arcgisonline.com/arcgis/rest/services/World_Street_Map/MapServer"/>
        </esri:Map>
    </esri:MapView.Map>
    <esri:MapView.MapGrid>
        <esri:LatLonMapGrid/>
    </esri:MapView.MapGrid>
</esri:MapView>
MaximumExtent

The MaximumExtent property allows you to control how far out the map should be allowed to zoom. This property only controls zoom, it does not allow you to restrict where the user can pan the map. This property must be set using the spatial reference that the map uses. It would be great if you could specify an extent using lat/lon but have a map with a coordinate system of Web Mercator. The following example sets the maximum extent of the map to be the lat/lon borders of Colorado.

<esri:MapView>
    <esri:MapView.Map>
        <esri:Map>
            <layers:ArcGISTiledMapServiceLayer ServiceUri="http://services.arcgisonline.com/arcgis/rest/services/ESRI_StreetMap_World_2D/MapServer"/>
        </esri:Map>
    </esri:MapView.Map>
    <esri:MapView.MaximumExtent>
        <geom:Envelope YMax="41.0014594" YMin="37.9358477" XMin="-111.09373110000001" XMax="-101.893834999999970000">
            <geom:Envelope.SpatialReference>
                <geom:SpatialReference Wkid="4326"/>
            </geom:Envelope.SpatialReference>
        </geom:Envelope>
    </esri:MapView.MaximumExtent>
</esri:MapView>
Min and MaxScale

The MinScale and the MaxScale properties control how far out or in, respectively, the map is allowed to zoom. A MaxScale of 1,000 will allow the map to be zoomed in to about a neighborhood level. A value of 10,000 no closer than a town, and 100,000 about the Denver metro area. The MinScale works the same way, but allowing the map to be zoomed out. When using the MinScale, ensure the map has an initial extent set so the user is not lost in the ocean.

From the documentation

A scale is usually referred to as 1:X, where X is the scale specified here. This value is the relative scale to the real world, where on inch on the screen is X inches in the real world. Note that this is only an approximation and is dependent on the map's projection that can add some distortion, as well as the system's reported DPI setting which doesn't necessarily match the actual DPI of the screen.

Rotation

The Rotation property allows you to… you guessed it, rotate the map. This is really useful when you want to orientate the map with the compass on the device or allow for a manual rotation of the map using an orientation control within the app.

ShowMagnifierOnTapAndHold

ShowMagnifierOnTapAndHold allows a magnifier to appear when you tap and hold the map. This property only works when using a finger to tap a touch device. I’ve been told the intent of this property is to better aid editing work flows. This property could be used for much more and make a mapping experience a lot better.

WrapAround

This is a handy property that allows to specify if the map can be continually panned east or west and have the map continue. Think of the WrapAround property as the ability a globe to spin continuously.

Events

The MapView control has four events that you’ll want to familiarize yourself with. The ExtextChanged event notifies you when the map is zoomed or panned. The MapView has three other events for touch or click manipulation. These events are MapViewDoubleTapped, MapViewHolding, and MapViewTapped.

Methods

The MapView has two utility methods and methods to zoom and center the map. Use the LocationToScreen and ScreenToLocation methods to convert between map points to screen points. These methods are handy within events. The MapView four methods for zooming and 15 methods for centering the map! Three methods are synchronous and 12 are asynchronous. To be fair, there are two methods, SetView  with two overloads and SetViewAsync with 11 overloads. Working with map APIs, you usually have one, at most two ways of centering a map. Oddly enough, the MapView does not have a MapCenter dependency property to center the map with binding.

I’ll continue the next post discussing location within an ArcGIS Runtime map app.

Working with Basic Mapping Layers in the ArcGIS Runtime Map

This is a second in a series of posts covering the new ArcGIS Runtime (beta). In the last post we walked through creating a simple map app. In this post we’ll start to cover the different layers your map can have. A Layer can be map images like what you would see in Google or Bing Maps. Or a Layer can represent the physical location of items. Layers can be toggled on and off through the IsVisible property. You can also adjust the transparency of a layer with the Opacity property.

The ArcGIS Runtime SDK comes with 12 different types of map layers that you can use in your app! Some of these I’ll cover in detail in this blog, some I’ll just barely cover, and some will have whole blogs dedicated to them. I like to group the layers into two basic categories. The layers for “basic mapping” and layers for “GIS users”. I consider basic mapping to be any app in the store that uses a map in any way. Some examples would be Four Square, or Disney Expedition.  Layers for GIS users are needed for the types of applications that I write for Schneider Electric. Applications that have a heavy workflow around GIS data or using Esri services need “GIS Layers”. Most of the apps that you write should be fine with the Basic Mapping layers.

This blog post will cover the Basic Mapping layers. Another post will cover the GIS User layers

Basic Mapping

ArcGISTiledMapServiceLayer

Of all the “ArcGIS” layers, this is the only one that makes it into the Basic Mapping section. All of the layers prefixed with ArcGIS work specifically with ArcGIS Server services. They know what URIs to go to for map images for an area or other information about the content of the layers. The ArcGISTiledMapServiceLayer makes it into the Basic Mapping category because Esri offers many great up-to-date tiled maps for free. That’s right, you can use any of the MapServer services located at http://services.arcgisonline.com/ArcGIS/rest/services. If we ignore the folders (which contain even more services), Esri offers 12 tiled services.

image_thumb

All of these services use either a standard WGS84 projection or a Web Mercator projection.

UPDATE: I was told that all of the WGS84 services have been deprecated in favor of the Web Mercator services. So you should not use the ESRI_Imagery_World_2D service. Instead use the World_Imagery service.

Using the ArcGISTilesMapServiceLayer in your app is really simple. Click on a link for one of the services that you would like to use in your app. I will pick “World_Street_Map”. Copy the URL of the service from your browser. For me it will be http://services.arcgisonline.com/arcgis/rest/services/World_Street_Map/MapServer. This URL will be the ServiceUri for the layer. The following XAML will allow you to use the Layer in your map app.

<esri:MapView>
    <esri:MapView.Map>
        <esri:Map>
            <layers:ArcGISTiledMapServiceLayer 
                   ServiceUri="http://services.arcgisonline.com/arcgis/rest/services/World_Street_Map/MapServer"/>
        </esri:Map>
    </esri:MapView.Map>
</esri:MapView>

It’s that easy to start using free maps with the ArcGIS Runtime SDK and the ArcGISTiledMapSerivceLayer!

image

BingLayer

The ArcGIS Runtime comes with out-of-the-box support for Bing map images! The BingLayer requires a key from the Bing maps portal. When working with the BingLayer, you can specify if you want an aerial, aerial with labels, or a road map through the MapStyle property. The default map style is Road. I won’t get into a lot of detail about the Bing maps portal, but keep in mind that you will have to pay for the usage of the map data if requests are over 50,000 in 24 hours. To use the BingLayer in your app, use the following XAML.

<esri:MapView>
    <esri:MapView.Map>
        <esri:Map>
            <layers:BingLayer Key="YOUR-BING-KEY" MapStyle="AerialWithLabels"/>
        </esri:Map>
    </esri:MapView.Map>
</esri:MapView>

Which produces the following map

image

GraphicsLayer

The GraphicsLayer is used to show any “client side” data. Think of it as the place for your map pins. The GraphicsLayer has changed from older versions of the .NET SDKs. In the past you were able to style a Graphic any way you wanted in XAML. The new API does all of it’s rendering in C++. With the rendering that deep, it can’t use XAML. They do provide some nice out of the box ways to draw your symbols. The GraphicsLayer is basically like a ItemsControl. You add items to the Graphics collection much like you would the Items of an ItemsControl. You can also bind the GraphicsSource to an IEnumerable<Graphic> just like you would the ItemsSource of an ItemsControl. Unlike an ItemsControl, the GraphicsLayer cannot accept any object into it’s collection. You can only add Graphic objects.

For this sample we need two layers in our Map. One for a base map and our GraphicsLayer. We’ll add new Graphics to the map whenever you tap or click the map. We’ll also define what we want our “map pin” to look like in the page resources. You can specify how each individual Graphic should look, or define a Render for the GraphicsLayer. For this we’ll specify that every Graphic should render an ‘X’ on the map.

<Page.Resources>
    <symbols:SimpleMarkerSymbol x:Key="GraphicSymbol" Color="#FF0A57FC" Size="12" Style="X" />
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <esri:MapView MapViewTapped="OnMapViewTapped">
        <esri:MapView.Map>
            <esri:Map>
                <layers:ArcGISTiledMapServiceLayer ServiceUri="http://services.arcgisonline.com/arcgis/rest/services/ESRI_StreetMap_World_2D/MapServer"/>
                <layers:GraphicsLayer>
                    <layers:GraphicsLayer.Renderer>
                        <symbols:SimpleRenderer Symbol="{StaticResource GraphicSymbol}"></symbols:SimpleRenderer>
                    </layers:GraphicsLayer.Renderer>
                </layers:GraphicsLayer>
            </esri:Map>
        </esri:MapView.Map>
    </esri:MapView>
</Grid>

In our code behind we’ll add new graphics to the map in the OnMapViewTapped method.

private void OnMapViewTapped(object sender, MapViewInputEventArgs e)
{
    var mapView = (MapView)sender;
    var graphicsLayer = (GraphicsLayer)mapView.Map.Layers[1];
    graphicsLayer.Graphics.Add(new Graphic(e.Location));
}

The GraphicsLayer requires a lot more information than this overview blog so I have two more blogs that are dedicated to this topic.

image_thumb1

CsvLayer

The CsvLayer is a new addition to the ArcGIS Runtime. This handy layer allows you to use a csv file as the source of data for a map. Suppose you have a file with all of the locations of Starbucks. The CsvLayer allows you to use this file to show locations on a map! This file can be located online, or it can be local file. As of writing this, XAML only allows for an online file through the ServiceUri property. If you have a local file with your app, or would like to allow the user to specify a file, you can use the SetSourceAsyc method. The CsvLayer is a type of GraphicsLayer. So you can use the Graphics or GraphicsSource properties directly, but you shouldn’t need to. Just like with the GraphicsLayer, you define what the Graphics should look like with the Render property.

<Page.Resources>
    <symbols:SimpleMarkerSymbol x:Key="GraphicSymbol" Color="#FF0A57FC" Size="12" Style="X" />
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <esri:MapView >
        <esri:MapView.Map>
            <esri:Map>
                <layers:ArcGISTiledMapServiceLayer 
                        ServiceUri="http://services.arcgisonline.com/arcgis/rest/services/ESRI_StreetMap_World_2D/MapServer"/>
                <layers:CsvLayer ServiceUri="http://VisuallyLocated.com/samples/starbucks_sample.csv">
                    <layers:CsvLayer.Renderer>
                        <symbols:SimpleRenderer Symbol="{StaticResource GraphicSymbol}"></symbols:SimpleRenderer>
                    </layers:CsvLayer.Renderer>
                </layers:CsvLayer>
            </esri:Map>
        </esri:MapView.Map>
    </esri:MapView>
</Grid>

In the above XAML, I’m have a file with a few locations of Starbucks around the US. Here is what it looks like.

image_thumb2

OpenStreetMapLayer

The OpenStreetMapLayer is also a new addition to the SDK. As you can guess, it displays the Open Street Map data. This is one of those things that “just works”.

<esri:MapView>
    <esri:MapView.Map>
        <esri:Map>
            <layers:OpenStreetMapLayer />
        </esri:Map>
    </esri:MapView.Map>
</esri:MapView>

Here is the app showing Open Street Map data for Colorado.

image_thumb3

You can download a solution demonstrating all five of these layers in a Windows Store and Windows Phone app.

Read part 2: Working with the MapView control in the ArcGIS Runtime

Building a map app with the ArcGIS Runtime Map

This is the first in a series of posts that will go over the new ArcGIS Runtime SDK. This first post will discuss how to get started and create an app that has the ArcGIS Runtime Map. This first step is to download the SDK. The SDK is currently in beta so you will need to sign up for the beta program. It’s important to note that you will not be able to get the SDK from nuget.

Esri packages their installers a little differently than you might be used it. The exe that you download is a zip of the actual installer. Run the ArcGIS_Runtime_SDK_for_DotNet_1022_536.exe (as of writing this the file is missing the exe extension, so you’ll need to add it) and you will be prompted for a location to unpackage the installer.

image

Give it a location, once it completes it will run the actual Setup.exe.

image

image

We’ll be building a Windows Store app with the SDK so you’ll need Visual Studio 2013. The SDK does not support Windows 8 apps, only Windows 8.1 apps. For Windows Phone and WPF you can use Visual Studio 2012. Open up Visual Studio and create a new Windows Store project.

image

The core of the ArcGIS Runtime is built with C++. Because of this, you’ll need to change the platform of the application from Any CPU. Any CPU is a .NET only thing, so we’ll need to specify either x86, x64 or ARM. To change the platform right click on the solution and select Configuration Manager. You may also want to add the platform target dropdown to a toolbar..

image

Make sure that debug and release are set to something other than Any CPU. If you like using the designer, you need to pick x86. When you ship your app, you’ll package it up with x86, x64 and ARMso it will work on any Windows 8.1 device.

image

Next add a reference to the new ArcGIS Runtime assembly. The assembly is under the Windows –> Extensions group.

image

Open the XAML of your MainPage. For this example we’ll create a fully emersive mapping application. We’ll need to add two namespaces to our xaml.

<Page
    x:Class="App1.MainPage"
    ...
    xmlns:esri="using:Esri.ArcGISRuntime.Controls"
    xmlns:layers="using:Esri.ArcGISRuntime.Layers">

If you are using Windows Phone, make sure you define the namespaces properly

<phone:PhoneApplicationPage
    xmlns:esri="clr-namespace:Esri.ArcGISRuntime.Controls;assembly=Esri.ArcGISRuntime"
    xmlns:layers="clr-namespace:Esri.ArcGISRuntime.Layers;assembly=Esri.ArcGISRuntime">

The esri namespace is where the controls live. This is where we will find the new MapView control.  In the past, we have worked with Map control. Now the Map is a property of the MapView. This does seem odd as they have only pulled out the InitialExtent property and the Layers property. The rest of the map functionality still resides on the MapView.

The layers namespace is where we will find the different types of layers we can  to the map. The next post will have more information on the different layers. For this post we’ll use the ArcGISTilesMapServiceLayer using Esri’s free tiled map services.

With the name spaces defined, add the following XAML your page.

<esri:MapView>
    <esri:MapView.Map>
        <esri:Map>
            <layers:ArcGISTiledMapServiceLayer 
                    ServiceUri="http://services.arcgisonline.com/arcgis/rest/services/ESRI_Imagery_World_2D/MapServer"/>
        </esri:Map>
    </esri:MapView.Map>
</esri:MapView>

Run the application and you’ll have a map app! Pan, zoom around. Find your home, have fun!

image

As you can see it is pretty simple to get started with the ArcGIS Runtime SDK. In the next post I’ll cover the different layers in the SDK.

Notice the legal notice in the corner? We are currently using the developer license (or no license) on the SDK. The SDK is still in beta, so you cannot use it in a production app (without asking). When the SDK is final, you can use a basic license for free. This license will get you pretty much everything you need to build an app. I’ll walk through registering for a license when it’s all working properly


You can download this solution that also contains a Windows Phone 8 app as well!

Read Part 2: Working with Basic Mapping Layers in the ArcGIS Runtime 

Getting started with the ArcGIS Runtime (beta) Mapping SDK for .NET

Last Sunday (March 9) Esri announced the public beta release of their mapping SDK for .NET. This new SDK covers Windows Store, Windows Phone, and WPF. Can you believe it? All three platforms, and all using the same API. This is huge news if you develop mapping applications. Personally I find it painful that in Windows Phone 7 you would use the Bing Maps (Silverlight) SDK. In Windows Phone 8 you were encouraged to use the new Nokia Maps SDK, while on Windows Store you had the Bing Maps SDK, but it was a different SDK than the Windows Phone 7 one. So that’s three different SDKs to use. I have no idea who thought this was a sane idea.

Esri has been working hard on this new SDK. During the Devsummit last year (2014), Esri announced the beta of a new SDK that would target Windows Store. At that time, they already had a Windows Phone SDK and a WPF SDK. Both were very similar with a few extras on the WPF side. While working on this new beta for Windows Store, they decided it would be much better to have a new SDK that targeted Phone, Store, and WPF. So for the past year that’s what they have been doing.

Over the coming weeks I’ll be blogging about how you can create mapping apps that use this new SDK. Some of these blogs will have a heavy focus on the GIS person, while others will be targeted to everyday app builders who want a better experience building map apps. These blogs will focus on Windows Store, but can be applied to Windows Phone and WPF as well.

 

Part 1: Building a map app with the ArcGIS Runtime Map
Part 2: Working with Basic Mapping Layers in the ArcGIS Runtime Map
Part 3: Working with the MapView control in the ArcGIS Runtime 
Park 4: Working with location in an ArcGIS Runtime Map app
Part 5: Adding map pins (graphics) to the ArcGIS Runtime Map
Part 6: Customizing map pins (graphics) in the ArcGIS Runtime Map

Part x: Working with the “GIS User” Layers in the ArcGIS Runtime
… More to come.