Visually Located

XAML and GIS

Migrating from the Windows Phone Toolkit ToggleSwitch to the new XAML ToggleSwitch

This is part of a series on migrating from the WP Toolkit.

The new Windows Phone 8.1 XAML SDK comes with new controls that previously were only in the Windows Phone Toolkit. One of these controls in the ToggleSwitch. The new ToggleSwitch control is really nice. The team has made some great improvements to this control.

Migrating to the new control is pretty easy. Along with all of the new controls, you no longer need to declare a namespace when using the control in XAML.

<!-- from -->
<toolkit:ToggleSwitch/>
 
<!-- to -->
<ToggleSwitch/>
 

Instead of IsChecked, you’ll use the IsOn property.

<!-- from -->
<toolkit:ToggleControl IsChecked=”True/>
 
<!-- to -->
<ToggleControl IsOn=”True/>

The IsOn property is still a dependency property, so you can use binding as well.

<ToggleControl IsOn=”{Binding SomeSetting}”/>

The toolkit ToggleControl has built in Margins designed for use within a Phone app. The new XAML ToggleControl does not have any Margins defined. This is the case for all of the XAML controls. For a direct replacement you will have to add the margins in.

<ToggleControl Margin="9.5,5,9.5,33.6"/>

The new ToggleSwitch comes a few new properties. Four of these new properties allow you to control the “On” and ”Off” content. With the toolkit ToggleSwitch controlling the On/Off content was not that easy. The new OnContent and OffContent allow you to control the text to display when the switch is on or off. So if you wanted to display “true” and “false” you could do the following.

<ToggleSwitch OnContent=”trueOffContent=”false/>
image            image

The ToggleSwitch also comes with two properties for the template to use for the on and off content. If for some reason you wanted to display an image, you could set the templates to do just that.

<DataTemplate x:Key=”ImageToggleContent> 
    <Image Source=”{Binding}” Stretch="None"/> 
</DataTemplate>
 
<!-- Other xaml -->
<ToggleSwitch OnContent=”Assets/On.pngOffContent=”Assets/Off.png
              OnContentTemplate=”{StaticResource ImageToggleContent}” 
              OffContentTemplate=”{StaticResource ImageToggleContent}”/> 
 

image            image 

Replacing the four previous events is one simple Toggled event. I like this change as it is the one stop location for being notified of state change. Having Checked, Unchecked, etc. events just adds bloat.

There you go, easy to move over to the new ToggleSwitch and you get some nice new features to boot!

Migrating from the Windows Phone Toolkit to the new Runtime XAML controls

With the introduction of the new Windows Phone XAML Apps, Microsoft released new controls that previously only existed in the Windows Phone Toolkit. For any years these controls existed in open source format, but did not allow for contributions. These controls would get some bug fixes, or new functionality/controls every now and then. Ownership of the toolkit changed hands many times and the toolkit was mostly forgotten.

There was often complaints from the community that Microsoft would put “must have controls” in a toolkit. I personally liked that these controls were in a toolkit in which I could see the source. It allowed me to learn from  the people that know the core code the best.

Sidebar: Take advantage of open source software. Contribute or not, it is a great learning tool.

A nice thing about it being open was that you could fix bugs that you found. While the source was open, contributions were closed, so you could not submit bug fixes are add features to the toolkit. However, it was possible for bug fixes to come out at any time from the Windows team. With the transition to the new XAML platform, source will be closed. This means that you will not be able to fix any bugs that you find. You will have to submit a Connect ticket and hope it gets fixed in the next update of Visual Studio.

The new  SDK comes with replacements or the following controls that were previously only in the Windows Phone Toolkit. I’ll walk through each one showing how to replace code that used the toolkit version with the new XAML controls.

ToggleSwitch

DatePicker

TimePicker

ListPicker

ContextMenu

Transitions

Migrating from the LongListSelector to the ListView in Windows Phone XAML Apps

The new Windows Phone 8.1 SDK comes with support for Silverlight and XAML based apps. If you built an app with the Silverlight Phone SDK, you probably used the LongListSelector. This control was released with the Windows Phone 8 SDK for Silverlight Phone apps. This control is still available if you are building Windows Phone 8.1 apps if you are using the Silverlight controls. If you want to build a Universal app or just an app based on the XAML stack, The LongListSelector is not available. Instead, we have the ListView control.

Moving to the ListView is really easy, provided you did not use the jump list functionality of the LLS. If you did not have a jump list, moving your app over is as simple as replacing ‘phone:LongListSelector’ with ‘ListView’. The LongListSelector was not in the default namespace, whereas the ListView is so there is no need for a namespace prefix.

<!-- OLD -->
<phone:LongListSelector ItemsSource="{Binding MyItems}"
                        toolkit:TiltEffect.IsTiltEnabled="True">
    <phone:LongListSelector.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Title}" Style="{StaticResource PhoneTextLargeStyle}">
        </DataTemplate>
    </phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
 
<!-- NEW -->
<ListView ItemsSource="{Binding MyItems}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Title}" Style="{StaticResource PhoneTextLargeStyle}">
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Notice the ListView also did not need the TitlEffect from the toolkit. That is because it is built into the ListView. As you can see, moving over is really easy. Now lets look at the jump list functionality and differences in the two controls. Jump list functionality requires two key pieces.

The style for the group headers of the section

image

And the style for the jump list itself.

image

The LLS has both the group header and the jump list functionality built in. The ListView has the ability to display group headers, but not the jump list. Moving the group header functionality over is pretty simple. The LLS had the GroupHeaderTemplate, and the ListView has the GroupStyle.

For the rest of the blog, I’ll take the MSDN example of How to display data in a grouped list in LongListSelector for Windows Phone 8.

<!--OLD -->
<phone:LongListSelector
  GroupHeaderTemplate="{StaticResource AddrBookGroupHeaderTemplate}"
  ItemTemplate="{StaticResource AddrBookItemTemplate}"
  IsGroupingEnabled="true"
  HideEmptyGroups ="true"/>
 
<!-- NEW -->
<ListView ItemsSource="{Binding Source={StaticResource AddressGroups}}"
          ItemTemplate="{StaticResource AddrBookItemTemplate}">
    <ListView.GroupStyle>
        <GroupStyle HidesIfEmpty="True" 
                    HeaderTemplate="{StaticResource AddrBookGroupHeaderTemplate}"/>
    </ListView.GroupStyle>
</ListView>

When grouping items in a LLS you had to set the IsGroupingEnabled to true. When you do this, it tells the LLS that the ItemsSource is of type IEnumerable<IEnumerable<T>. It then knows that the ItemTemplate should not be used to display the items of the bound collection. Instead the ItemTemplate should be used to display the items in the collection of each item of the bound source. The ListView does not have a property that will tell it that it should display items within a collection of each item of the bound source. Instead, you should use a CollectionViewSource. The CollectionViewSource does have the IsSourceGrouped property. This works the same way as the IsGroupingEnabled property.

<Page.Resources>
    <CollectionViewSource x:Key="AddressGroups"
                          IsSourceGrouped="True"/>
</Page.Resources>
<Grid>
    <ListView ItemsSource="{Binding Source={StaticResource AddressGroups}}"
              ItemTemplate="{StaticResource AddrBookItemTemplate}">
        <ListView.GroupStyle>
            <GroupStyle HidesIfEmpty="True" HeaderTemplate="{StaticResource AddrBookGroupHeaderTemplate}"/>
        </ListView.GroupStyle>
    </ListView>
<Grid>

The ListView does not have GroupHeaderTemplate or the HideEmptyGroups property like the LLS. Instead it uses a GroupStyle. A GroupStyle displays the header of the group through the HeaderTemplate property and hiding groups though the HidesIfEmpty property. We are able to reuse our templates for both the items in the list as well as the group headers! This is pretty cool.

So now we have our ListView grouped

imageimage

Now we need a jump list. Again, this was built into the LLS. For Windows Phone XAML apps, you must use the SemanticZoom control. This control was introduced with Windows 8 Store apps. It allows you to set a control to display when it is zoomed in, and one for when it is zoomed out. In Windows Store [tablet] apps, you could pinch to zoom out, or tab a header element to get to a jump list control. The People app is a great example of the SemanticZoom control.

image

<SemanticZoom>
    <SemanticZoom.ZoomedInView>
        <!-- Elment to display when "zoomed in". Usually a ListView or GridView -->
    </SemanticZoom.ZoomedInView>
    <SemanticZoom.ZoomedOutView>
        <!-- Element for jump list, usually a GrivView or ListView -->
    </SemanticZoom.ZoomedOutView>
</SemanticZoom>

For Windows Phone, this control is also used to display jump lists as well. With the LLS, you would set the Style of the control to use when in jump list mode. This would be another LLS that would display either in list mode or grid mode. In XAML apps, you set the actual control to use. For our address book we will use the GridView for the jmp list style, or the zoomed out view of the SemanticZoom. The ListView that we built will be used for the ZoomedInView.

<Page.Resources>
    <DataTemplate x:Key="AddrBookJumpTemplate">
        <Border Padding="5">
            <Border Background="{Binding Converter={StaticResource BackgroundConverter}}" 
                    Width="82" Height="82" HorizontalAlignment="Left">
                <TextBlock Text="{Binding Group.Key}" 
                           Foreground="{Binding Converter={StaticResource ForegroundConverter}}" 
                           FontSize="48" Padding="6" 
                           HorizontalAlignment="Left" VerticalAlignment="Center"/>
            </Border>
        </Border>
    </DataTemplate>
    <!-- other templates -->
</Page.Resources>
 
 
<SemanticZoom>
    <SemanticZoom.ZoomedInView>
        <ListView ItemsSource="{Binding Source={StaticResource AddressGroups}}"
                  ItemTemplate="{StaticResource AddrBookItemTemplate}">
            <ListView.GroupStyle>
                <GroupStyle HidesIfEmpty="True" HeaderTemplate="{StaticResource AddrBookGroupHeaderTemplate}"/>
            </ListView.GroupStyle>
        </ListView>
    </SemanticZoom.ZoomedInView>
    <SemanticZoom.ZoomedOutView>
        <GridView Background="Black" 
              ItemsSource="{Binding Source={StaticResource AddressGroups}, Path=CollectionGroups}"
              ItemTemplate="{StaticResource AddrBookJumpTemplate}">
        </GridView>
    </SemanticZoom.ZoomedOutView>
</SemanticZoom>

We need a different template for the jump list than what was used with the LLS. Most of the changes have to do with the size of the squares used. The ItemsSource for the GridView will use the same CollectionViewSource that the ListView uses, but must bind to the CollectionGroups property of the View. The CollectionGroups is only the groups for the source. It is the top level collection.

We now have our jump list complete! The first image is the jump list built with the LLS while the second is the ListView.

LongListSelectorListView

Download a complete sample including getting the complete WP8 Silverlight sample working in WP8.1 XAML apps.

Creating live tiles with WriteableBitmap and transparent backgrounds

Creating apps with live tiles is nothing new. Many apps have live tiles, there are built in APIs for creating live tiles. With the release of Windows Phone 8.1 there are new APIs for creating live tiles. But what happens when the tiles you are creating go beyond what is supported? One of the easiest ways to create live tiles is with the WriteableBitmap.

private static Uri GenerateTile(Control tileBackground, string fileName)
{
    fileName = Path.Combine("Shared", "ShellContent", fileName);
 
    using (var stream = IsolatedStorageFile.GetUserStoreForApplication().CreateFile(fileName))
    {
        tileBackground.Measure(new Size(tileBackground.Width, tileBackground.Height));
        tileBackground.Arrange(new Rect(0, 0, tileBackground.Width, tileBackground.Height));
        var bitmap = new WriteableBitmap(tileBackground, null);
        bitmap.SaveJpeg(stream, (int)tileBackground.Width, (int)tileBackground.Height, 0, 100);
    }
    return new Uri("isostore:/" + fileName, UriKind.Absolute);
}

I’ve been using the code above for a few years and it works great. I would always ensure that the control I created has the background set to be the accent brush

<Grid x:Name="LayoutRoot" Background="{StaticResource PhoneAccentBrush}">

I never thought much about this code until I read a blog by Sanjay Sharma titled Transparent Live Tile For Windows Phone 8.1. The blog walks you through creating tile images with transparency. The blog title is a little misleading as it doesn’t talk about live tiles at all. But it got me thinking, how can I ensure that my apps live tiles do have transparency. So I set out to remove the Background from the controls I use for my tiles.

<Grid x:Name="LayoutRoot">

This did not work. So I thought I would try setting the background to Transparent.

<Grid x:Name="LayoutRoot" Background="Transparent">

No luck there either. Then I tried setting the background to x:Null. But no luck. I was pretty frustrated and thought using WriteableBitmap would not be a solution for making tiles with transparency. Luckily Andrej Tozon, was there to help me do a face-palm.

image

Of course! The way I’ve been saving the WriteableBitmap is with the SaveJpeg method. And of course jpeg’s do not support transparency. I remembered that Cimbalino from Pedro Lamas had a method to save a WritebaleBitmap as a png. So I added the Nuget pack and changed the save method for my GenerateTile method.

// Old:
// bitmap.SaveJpeg(stream, (int)tileBackground.Width, (int)tileBackground.Height, 0, 100);
 
// New using Cimbalino
bitmap.SavePng(stream);

And now my tiles always match the background the user chooses. If they change the accent color, it will match.

image

If they select a new background image for the start screen, the tile will be transparent so the image will show through!

image

Now my tiles will always match what the user wants!

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.