Tuesday, June 18, 2013

Making modifying WMAppManifest.xml easier

When it comes to some of the more advanced features of Windows Phone 8 development you may need to make changes to the manifest file (WMAppManifest.xml) which the SDK doesn't provide a nice visual way to do.
In this scenario it means opening the xml file in a text editor and, probably, copying and pasting the required pieces for the appropriate page on MSDN-after you've searched for and found it.

Obviously this isn't an ideal way of working and recently I felt something needed to be done.

After exploring a few possibilities, I've created nine new NuGet packages which will allow you to modify the WMAppManifest.xml file to indicate supporting:

  • New tile formats, via reflection, when a 7.X app is run on a 7.8 or 8.0 device.
  • Background location tracking
  • Fast-App-Resume
  • Lock Screen background images
  • Lock Screen notification text
  • Lock Screen notification counts
  • All Lock Screen items (rather than adding them individually)
  • Lauching via a custom schema
  • Custom file formats/extensions

You can find the packages by searching for "WMAppManifest"
Or, if like me, you're super lazy (efficient), you can search for "WMAM" (the acronym) and you'll find them that way too.

The package will make appropriate modifications to the WMAppManifesst.xml file and add a readme file to the project.
When you uninstall the package the readme file is removed but the modifications to the XML file remain.
This is deliberate. The NuGet package is just a means to an end. There is no expectation that you'll need to update the package in the future so you can uninstall it immediately after it's been installed. This will mean you have no unnecessary dependencies in your project.

If you are adding support for file extensions or a custom schema you'll still need to modify the file manually to set the schema name and file extension. Everything else is set up though. You just need to alter the "ChangeMe" or "SetMe" values. This is documented in the readme file for each package so you may want to read that before removing the readme file and/or uninstalling the package.

You can find all the packages at nuget.org if you want to explore them in a bit more detail.

If you think these could be useful, you use them, find an issue or have any other feedback I'd love to hear it. Please do share your thoughts and experiences with this. It's my attempt to help make Windows Phone development that little bit easier for everyone.




Tap, Click, Command or Select - How to trigger navigation.

Here's a scenario: You have a number of items on a page and you want the person using the app to be able to touch one of those items and have the app navigate to another page.

It's a simple and common scenario. It's also one where there are lots of ways of implementing the
behaviour. But which one should be used?

The navigation part is pretty straight forward but how to detect the "touch" and intent.

There are four options available:
  1. Contain each item in a Button and use the `Click` event to detect the users action.
  2. Use the `Tap` event on the containing UIElement to detect the users action.
  3. Contain each item in a Button and bind to the `Command` to detect the users action.
  4. If the items are in a  ListBox (or similar) use the SelectionChanged event to determine the users action.
Some may think there is no difference or they're interchangeable but there are some important differences.

A Click event occurs when contact is made with the sceen and the same control is still under the touch point when contact is lost. This is regardless of how long the touch was made for or what happened in the mean time. This means you can move around the screen, move off of the control and back onto it, move the control within a scrollable area, and as long as there is no other control which will capture the gesture, swipe across the control and still trigger the click event. This may be more than you want or a user will expect to trigger the action/navigation.

A Tap event is intended to be used when you want to capture the users intention to interact with a screen element by tapping it. To trigger the tap event of a control contact must be made and released within a short period of time (about 300ms) and without the touchpoint moving more than a small amount.  This avoids the event being triggered by pressing on something for a long period of time or when moving a control on the screen. This is what you should be using instead of a `Click` event as it is designed and created to be used for finger based interaction while the click event was created for use with a mouse.

Using the SelectionChanged event for items in a ListBox (or similar) is a popular technique as it is used by the DataBound project template. There are a couple of issues with this though. The first is that you must clear the selection after it's made to allow the selection of the same item again. The second, and bigger issue in my opinion, is that this is a misuse of what the ability to select an item is for. The ability to select an item (or items) is to enable it to be distinguished from the other items in the group. That's why there's a selected state. It allows you to see which items have been selected, so you can act on them. Thirdly, triggering a change in the selected item can also happen accidentally when scrolling a list.
If you have multiple items in a list and want to be able to perform an action when one of them is tuched, it would be better to use a Tap event on the individual item, rather than an event attacehd to the outer collection.
Like this:

    <ListBox ItemsSource="{Binding ListOptions}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Grid Tap="ItemTapped">
                    <TextBlock Text="{Binding}" />
                </Grid>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>


But, I hear you say, what about MVVM? I don't want to use coded behind, I want to bind the action to an ICommand on the ViewModel.

Yes, the ICommand is the solution here and the ButtonBase control has a Command property that you can bind your ICOmmand implementation to. But how is it triggered?
Disappointingly, from my perspective, it is triggered by either a Click or Tap event. This means that it can still be triggered in the same unexpected and undesired ways as a Click event.

Fortunately it's easy to create a user control that has the ability to call an ICommand implementation when it is Tapped and not Clicked.

Here's the incredibly simple XAML you need:

<UserControl
    x:Class="TapClickCommand.TapCommandControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Tap="ControlTapped" />

Yes, it's just an empty control with a Tap event handler wired up.

Then we just need the code to make it work:
namespace TapClickCommand
{
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
 
    public partial class TapCommandControl : UserControl
    {
        public readonly DependencyProperty TapCommandProperty =
            DependencyProperty.Register(
                "TapCommand",
                typeof(ICommand),
                typeof(TapCommandControl),
                new PropertyMetadata(null));
 
        public readonly DependencyProperty TapCommandParameterProperty =
            DependencyProperty.Register(
                "TapCommandParameter",
                typeof(object),
                typeof(TapCommandControl),
                new PropertyMetadata(null));
 
        public TapCommandControl()
        {
            InitializeComponent();
        }
 
        public ICommand TapCommand
        {
            get { return (ICommand)GetValue(TapCommandProperty); }
            set { this.SetValue(TapCommandProperty, value); }
        }
 
        public object TapCommandParameter
        {
            get { return GetValue(TapCommandParameterProperty); }
            set { this.SetValue(TapCommandParameterProperty, value); }
        }
 
        public void ControlTapped(object sender, GestureEventArgs e)
        {
            if (this.TapCommand != null)
            {
                this.TapCommand.Execute(this.TapCommandParameter);
            }
        }
    }
}


You use it just like the Command property in ButtonBase.
e.g.

    <local:TapCommandControl TapCommand="{Binding TheTapCommand}"
                             TapCommandParameter="{Binding Id}">
        <TextBlock Style="{StaticResource PhoneTextLargeStyle}"
                    Text="{Binding Name}" />
    </local:TapCommandControl>

Voila!


So, to summarize:
Use a Tap event, rather than Click or SelectionChanged if using code behind.
Bind commands to be triggered by a Tap event rather than a Click event if using commanding.




Saturday, June 15, 2013

Renewing a Windows Phone developer subscription with an MSDN token

For the last 3 years I've paid (yes, with real money) for my Windows Phone developer subscription. As I've just come up for renewal again I wanted to use the token I get as part of my MSDN subscription (that I also pay for).

In the phone dev centre there was a nice link prompting me to renew. On that renewal page there was an option to pay for renewal or enter a code. Obviously I wanted the "enter a code" option but where to get that code from? Unfortunately it wasn't as easy to find as I would have liked so I thought I'd share it here.

It's actually quite simple (once you know how)

  • Log into your account on msdn.microsoft.com.
  • Got to https://msdn.microsoft.com/en-us/subscriptions/manage/
  • Under the Subsccription Benefits find "Windows Phone developer account"
  • Click on the "get code" link to reveal your code - it is a GUID
  • Enter that code (GUID) in to the phone dev center renewal page.
  • Done!

Hope this helps.



Wednesday, June 12, 2013

ShellTile.ActiveTiles sometimes forgets about one of the tiles

A couple of times, when working with an app with lots of tiles pinned, I've seen `ShellTile.ActiveTiles` "forget" about one of the tiles.  By that I mean that when updating all the tiles from a background agent one of them isn't updated.

This is with code like:

    foreach (var tile in ShellTile.ActiveTiles)
    {
        // update the tile.
    }


At the moment I only have anecdotal evidence of this behaviour but wondered if anyone else could shed any knowledge or experience of this while I continue to investigate.

Deleting and repinning the tile in question seems to make the problem go away but this isn't a real solution.
Additionally it doesn't seem like it's the first or last created pin but I can't be sure of this.

Has anyone else seen this?



Saturday, June 08, 2013

LongListSelector does not "play nicely" with a static DataContext

Here's a lesson from a day lost to debugging an obscure issue.

Microsoft recommend that you should "use the LongListSelector instead of ListBox for phone apps".

That's great advice, especially if upgrading an existing app where ListBox wass used previously. But there's a gotcha you may need to be aware of.

If a LongListSelector is bound to a static ItemsSource then a reference is held that stops the page being collected. This means that such a page would leak memory!
If it's a large or complex page or one that is opened a lot (so you end up with lots of copies in memory) this could be very bad for your app.

This doesn't happen when bound to a non-static source. It also doesn't happen when using a ListBox bound to either a static or non-static object.

If you're upgrading an app built several years ago when using a static view model seemed like a not unreasonable way to architect an app you may be more likely to hit this. (That's why I discovered the issue-when upgrading an app originally written in 2011.)


Don't believe me or want to see this in action for yourself?
I've put a project at https://github.com/mrlacey/WPMisc/tree/master/LlsStaticTest which demonstrates all the above.
It allows opening of pages which contain:
  • a ListBox bound to a static object; 
  • a ListBox bound to a non-static object; 
  • a LongListSelector bound to a static object; 
  • a LongListSelector bound to a non-static object; 
  • and a way to force garbage collection.
Each page also outputs creation, navigation and destruction information to the debug window.
To see this in action, open each page then tap "FORCE GC" twice and you should see the destructors for all but the static LongListSelector page being called.
You can also see the same by running the app through the memory profiler but I think it's easier and faster to see this problem via the debug output.

There are two ways to address this issue:
  1. Remove the use of a static view model. Depending on your application this may or may not be a viable solution but I would recommend against using a static view model whenever possible.
  2. Remove the binding when backing out of the page. It feels slightly imperfect but works and is easy to do.

To remove the binding when leaving the page, just do something like this.

protected override void OnNavigatedFrom(NavigationEventArgs e)
{
    base.OnNavigatedFrom(e);
 
    // The following removes the binding of the LLS to the VM
    // so the page can be collected
    if (e.NavigationMode == NavigationMode.Back)
    {
        this.DataContext = null;
    }
}

Note that this is done in OnNavigatedFrom and not in OnNavigatingFrom as if done before you have navigated away from the page the removal of the binding may cause the UI to update and you may see screen flicker before the page closes.

This discovery was found via a lot of experimentation, insight and a process of elimination.I couldn't find any indication of what was holding a reference via the profiler. If you know where this would be indicated (or even hinted at) I'd love to know.