Visually Located

XAML and GIS

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.