Visually Located

XAML and GIS

Using the Geolocator API in your Phone 8 AND Phone 7 apps!

If you’ve done any work with location in Windows Phone you probably know that the a new location API was added at Windows Phone 8. If you want to upgrade your app to take advantage of functionality in Window Phone 8 you have a few options.

  1. Continue to use the original GeoCoordinateWatcher API from Windows Phone 7 in your Phone 8 and Phone 7 app
  2. Upgrade your app to Windows Phone 8 and use the new API in your Phone 8 app, while the Phone 7 app uses the original API.
  3. Upgrade your app to Windows Phone 8 and use the new API in your Phone 8 app AND your Phone 7 app!

These options assume you want to continue to support Windows Phone 7. Please do not forget that there are a lot of people with a Phone 7.

If you want to do options one or two you can stop reading now. If you want to do option three then you are in the right place. I’m not a big fan of supporting two different APIs in my apps and I don’t like using “out dated” APIs either. What we will need to do is create an API that duplicates the Windows.Devices.Geolocation API but uses the old System.Device.Location API. This will allow a file that uses location to be used with a Windows Phone 7 app AND a Phone 8 app!

I won’t get into the differences between the APIs as this upgrade link does a pretty good job. Most of the old API maps pretty easily to the new API. The bulk of the work is in the Geolocator class itself.

We’ll start with just a stub of the class.

namespace Windows.Devices.Geolocation
{
    public class Geolocator
    {
        public event TypedEventHandler<Geolocator, PositionChangedEventArgs> PositionChanged;
 
        public event TypedEventHandler<Geolocator, StatusChangedEventArgs> StatusChanged;
 
        public PositionStatus LocationStatus { get; }
 
        public Task<Geoposition> GetGeopositionAsync() {        }
 
        public double DesiredAccuracyInMeters { get; set; }
 
        public double MovementThreshold { get; set; }
 
        public PositionAccuracy DesiredAccuracy { get; set; }
 
        /// <summary>
        /// Not implemented
        /// </summary>
        public int ReportInterval { get; set; }
    }
}

Notice that ReportInterval is not implemented. This is not something I wanted to implement, not nothing is stopping you from doing that!
Also notice that I did not even

Most of the properties are implemented in terms of the original API.

private static bool _disabled;
 
private PositionStatus _status = PositionStatus.NoData;
private GeoCoordinateWatcher _watcher;
 
public Geolocator()
{
    _watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.Default) { MovementThreshold = 10 };
}
 
public event TypedEventHandler<Geolocator, StatusChangedEventArgs> StatusChanged;
 
public PositionStatus LocationStatus
{
    get
    {
        if (_disabled) return PositionStatus.Disabled;
        return _status;
    }
}
 
public double DesiredAccuracyInMeters
{
    get { return _watcher.MovementThreshold; }
    set { _watcher.MovementThreshold = value; }
}

I did not implement DesiredAccuracy or MovementThreshold in this stub because it’s a little more involved to maintain functionality. I’ll get into that more later.

Notice the static disabled property. A nice thing about the Geolocator is that it always knows if the location service for the phone itself is turned off. The GeoCoordinateWatcher only knows about it being disabled after it has already started. So to make life a little easier, this Geolocator will attempt to do the same.

The biggest different between the two APIs is the removal of the Start and Stop methods from the GeoCoordinateWatcher class. Start and Stop were replaced by simply subscribing to the PositionChanged event. Because everything happens when (un)subscribing from the event, we cannot use standard event stubs and must implement the event ourselves.

private TypedEventHandler<Geolocator, PositionChangedEventArgs> _positionChangedDelegate;
private readonly object _padLock = new object();
 
public event TypedEventHandler<Geolocator, PositionChangedEventArgs> PositionChanged
{
    add
    {
        lock (_padLock)
        {
            if (_positionChangedDelegate == null)
            {
                // if this is the first subscription to the PositionChanged event
                // then subscribe to the GeoCoordinateWatcher events and start
                // tracking location.
                _watcher.PositionChanged += OnPositionChanged;
                _watcher.StatusChanged += OnStatusChanged;
                _watcher.Start();
            }
            _positionChangedDelegate += value;
        }
    }
    remove
    {
        lock (_padLock)
        {
            _positionChangedDelegate -= value;
            if (_positionChangedDelegate == null)
            {
                // Last person to unsubscribe from this event
                // Stop the GeoCoordinateWatcher and unsubscribe from the events.
                _watcher.Stop();
                _watcher.PositionChanged -= OnPositionChanged;
                _watcher.StatusChanged -= OnStatusChanged;
            }
        }
    }
}

When the first subscription to the event comes in, we’ll subscribe to the GeoCoordinateWatcher events and Start tracking location. When the last subscription is removed, we unsubscribe from the GeoCoordinateWatcher events and stop tracking location. When the position or status changes from the GeoCoordinateWatcher, we’ll fire off our own PositionChanged or StatusChanged events.

private void OnStatusChanged(object sender, GeoPositionStatusChangedEventArgs args)
{
    var handler = StatusChanged;
    if (handler != null)
    {
        _status = args.Status.ToPositionStatus();
        _disabled = _status == PositionStatus.Disabled;
        var changedEventArgs = new StatusChangedEventArgs(_status);
        handler(this, changedEventArgs);
    }
}
 
private void OnPositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> args)
{
    var handler = _positionChangedDelegate;
    if (handler != null)
    {
        var geoposition = new Geoposition(args.Position);
        handler(this, new PositionChangedEventArgs(geoposition));
    }
}

We have now replaced the Start and Stop functionality from the GeoCoordinateWatcher API with the PositionChanged event. The next biggie are the GeoPositionAsync methods. I choose to only implement the default method as the first parameter from the second method (maximumAge) does not lend itself well to Windows Phone 7. The maximumAge parameter specifies “the maximum acceptable age of cached location data.” While we could cache location data, this is not the same as what is done in Windows Phone 8. In Phone 8, the system itself will cache location data. The GeoPositionAsync method performs it’s asynchronous operations via the IAsyncOperation<T> interface. This interface is not available in Windows Phone 7, but thanks to the Microsoft.Bcl library we do have the Task class which allows us to have methods that can be awaited.

public Task<Geoposition> GetGeopositionAsync()
{
    var completion = new TaskCompletionSource<Geoposition>();
 
    var locator = new Geolocator()
        {
            DesiredAccuracyInMeters = DesiredAccuracyInMeters,
            MovementThreshold = MovementThreshold,
            ReportInterval = ReportInterval
        };
 
    TypedEventHandler<Geolocator, PositionChangedEventArgs> positionChangedHandler = null;
    TypedEventHandler<Geolocator, StatusChangedEventArgs> statusChangedHandler = null;
 
    positionChangedHandler = (s, e) =>
        {
            locator.PositionChanged -= positionChangedHandler;
            locator.StatusChanged -= statusChangedHandler;
            completion.SetResult(e.Position);
        };
 
    statusChangedHandler = (sender, args) =>
        {
            if (args.Status == PositionStatus.Disabled)
            {
                // unsubscribe as we will not get any data
                locator.PositionChanged -= positionChangedHandler;
                locator.StatusChanged -= statusChangedHandler;
                completion.SetResult(null);
            }
        };
 
    locator.PositionChanged += positionChangedHandler;
    locator.StatusChanged += statusChangedHandler;
 
    return completion.Task;
}

The GeoPositionAsync method is meant to be a one time call method. This method initializes a new Geolocator object so we are able to take advantage of the new API we just wrote! The method uses the TaskCompletionSource class which gives us the power to perform this method in an async way. When GetPositionAsync is called, we need to subscribe to both the PositionChanged and the StatusChanged events. If the StatusChanged event comes back with location being Disabled, the PositionChanged event will never fire with a null location.

I mentioned earlier that DesiredAccuracy and MovementThreashold were not stubbed out because they required a little more. In Windows Phone 8, you are not allowed to change these properties (along with ReportInterval) while you are getting location. To maintain this functionality, we must check to see if anyone has subscribed to the PositionChanged event. If they have, throw an exception. In windows Phone 8, it throws the following

System.Exception was unhandled by user code
  HResult=-2147467260
  Message=Operation aborted (Exception from HRESULT: 0x80004004 (E_ABORT))

It throws this exception because the Geolocator is native C++. We’re in .Net so we can throw a better exception.

public double MovementThreshold
{
    get { return _watcher.MovementThreshold; }
    set
    {
        if (_positionChangedDelegate != null)
            throw new NotSupportedException("Cannot change the MovementThreshold while getting location.");
 
        _watcher.MovementThreshold = value;
    }
}
 
public PositionAccuracy DesiredAccuracy
{
    get { return (PositionAccuracy)_watcher.DesiredAccuracy; }
    set
    {
        if (_positionChangedDelegate != null)
            throw new NotSupportedException("Cannot change the DesiredAccuracy while getting location.");
 
        double movementThreshold = MovementThreshold;
        // We cannot change the accuracy in a GeoCoodinateWatcher so we need to create a new one
        _watcher = new GeoCoordinateWatcher((GeoPositionAccuracy)value) 
            { MovementThreshold = movementThreshold };
    }
}

And we are done with the Geolocator class. The rest of the work is stubbing out the other classes. These are pretty much a one for one match from each API. To save you some time you can download the source from github.

If you are a fan of NuGet you can install the bridge:

PM> Install-Package WPLocationBridge

OH, and did I forget to mention that this API is the same used in Windows Store apps? This means that one code file can be used across ALL THREE platforms!

Avoid InvalidOperationException when navigating in your Windows Phone apps

I have no idea how I get this error, but in every app I’ve published I get error reports in which navigation fails and throws an InvalidOperationException. The entire stack trace is similar to

System.InvalidOperationException
Navigation is not allowed when the task is not in the foreground.
   at System.Windows.Navigation.NavigationService.Navigate(Uri source)
   at MyWPApp.MainPage.OnListBoxItemSelected(Object sender, SelectionChangedEventArgs e)
   at System.Windows.Controls.Primitives.Selector.OnSelectionChanged(SelectionChangedEventArgs e)
   at System.Windows.Controls.Primitives.Selector.InvokeSelectionChanged(List`1 unselectedItems, List`1 selectedItems)
   at System.Windows.Controls.Primitives.Selector.SelectionChanger.End()
   at System.Windows.Controls.Primitives.Selector.SelectionChanger.SelectJustThisItem(Int32 oldIndex, Int32 newIndex)
   at System.Windows.Controls.ListBox.MakeSingleSelection(Int32 index)
   at System.Windows.Controls.ListBox.HandleItemSelection(ListBoxItem item, Boolean isMouseSelection)
   at System.Windows.Controls.ListBox.OnListBoxItemClicked(ListBoxItem item)
   at System.Windows.Controls.ListBoxItem.OnManipulationCompleted(ManipulationCompletedEventArgs e)
   at System.Windows.Controls.Control.OnManipulationCompleted(Control ctrl, EventArgs e)

As you can see the error states “Navigation is not allowed when the task is not in the foreground” yet everything about this stack trace indicates that the event and call to Navigate IS in the foreground.

Instead of trying to figure out how or why this occurs, I decided to create a new NavigateToPage extension method that ignores this exception.

public static class Extensions
{
    public static bool NavigateToPage(this NavigationService source, string uri)
    {
        try
        {
            return source.Navigate(new Uri(uri, UriKind.Relative));
        }
        catch (InvalidOperationException)
        {
            return false;
        }
    }
}

I also took the liberty of not requiring a Uri as I hate having to add the UriKind every time. Now everywhere in my app I use the new NavigateToPage method.

NavigationService.NavigateToPage("/SecondPage.xaml");

Performing an async operation in the OnBackKeyPress method and still exit your Windows Phone apps

The OnBackKeyPress method allows you to perform special logic when the user presses the phone back button. You usually override this method when you do not want the user to actually go back a page. An example of this is if you show a popup, when the user presses the back button you should close the popup.

protected override void OnBackKeyPress(CancelEventArgs e)
{
    base.OnBackKeyPress(e);
 
    if (PopupIsOpen())
    {
        e.Cancel = true;
        ClosePopup();
    }
}

This workflow works great because everything is synchronous.

You may have seen some apps that prompt you with a MessageBox asking if you want to exit. If you say yes the app exits and if you say no, you do not exit the app.

protected override void OnBackKeyPress(CancelEventArgs e)
{
    base.OnBackKeyPress(e);
    var result = MessageBox.Show(
        "Are you sure you want to exit?", "Exit app?", MessageBoxButton.OKCancel);
    if(result == MessageBoxResult.Cancel)
    {
        e.Cancel = true;
    }
}

This also works because the built in MessageBox suspends code execution when the Show method is called. This does not work when you are need to perform an async operation. An example of this is when you create a ShowAsync method for the Windows Phone Toolkit CustomMessageBox. Another example is calling to a service to save some settings. You would want to let the user know if you were unable to save.

protected async override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
    base.OnBackKeyPress(e);
 
    Microsoft.Phone.Controls.CustomMessageBox msgBox = new CustomMessageBox();
    msgBox.RightButtonContent = "yes";
    msgBox.LeftButtonContent = "no";
    msgBox.Caption = "Are you sure you want to exit the app?";
    msgBox.Title = "Exit app?";
    var result = await msgBox.ShowAsync();
    
    // right button is cancel button
    if (result == CustomMessageBoxResult.RightButton)
    {
        e.Cancel = true;
    }
}

NOTE: I in no way indorse or support the use of message boxes when exiting the app. This is used merely as an example

When the CustomMessageBox is shown, the method is exited. This is the power of async/await. As soon as the async method happens, the method will exit, and as such, the app will exit. You will need to change your approach here. The first thing is to set e.Cancel to true before the async method call. This will stop the app from exiting, but as I mentioned you will be unable to set it back to true. You will have to manually exit the app. This is done in one of two ways, if you are using Windows Phone 7, you can reference the Microsoft.Xna.Framework.Game assembly and use the Exit method of the Game class.

new Microsoft.Xna.Framework.Game().Exit();

If you are using Windows Phone 8, you can use the new Terminate method  of the Application class.

Application.Current.Terminate();

Wrapping it all up your OnBackKeyPress method looks like

protected async override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
    base.OnBackKeyPress(e);
    e.Cancel = true;
 
    Microsoft.Phone.Controls.CustomMessageBox msgBox = new CustomMessageBox();
    msgBox.RightButtonContent = "yes";
    msgBox.LeftButtonContent = "no";
    msgBox.Caption = "Are you sure you want to exit the app?";
    msgBox.Title = "Exit app?";
    var result = await msgBox.ShowAsync();
    
    // left button is yes button
    if (result == CustomMessageBoxResult.LeftButton)
    {
        // if using WP7
        //new Microsoft.Xna.Framework.Game().Exit();
 
        //if using WP8
        Application.Current.Terminate();
    }
}

This approach works for any of your OnBackKeyPress methods, not just in the first page of your app. If you instead want to navigate backward, change that exits the app to:

NavigationService.GoBack();

Making the Windows Phone Toolkit CustomMessageBox async

The Windows Phone Toolkit has a nice CustomMessageBox control that allows you to customize the button text of a MessageBox. This message box is nice but you must subscribe to an event for when it is closed.

Microsoft.Phone.Controls.CustomMessageBox msgBox = new CustomMessageBox();
msgBox.RightButtonContent = "cancel";
msgBox.LeftButtonContent = "delete";
msgBox.Caption = "Are you sure you want to delete?";
msgBox.Title = "Delete message?";
msgBox.Dismissed += (o, eventArgs) =>
    {
        // Do some logic in here.
    };
msgBox.Show();

This requires that your logic for user input to be either in a separate method or above the Show method like in my example. If the CustomMessageBox had a way to show it asynchronously, you could have your logic in one place. Luckily this is very easy with an extension method.

public static class ToolkitExtensions
{
    public static Task<CustomMessageBoxResult> ShowAsync(this CustomMessageBox source)
    {
        var completion = new TaskCompletionSource<CustomMessageBoxResult>();
        
        // wire up the event that will be used as the result of this method
        EventHandler<DismissedEventArgs> dismissed = null;
        dismissed += (sender, args) =>
            {
                completion.SetResult(args.Result);
                
                // make sure we unsubscribe from this!
                source.Dismissed -= dismissed;
            };
 
        source.Show();
        return completion.Task;
    }
}

This new extension method allows your code to flow better.

Microsoft.Phone.Controls.CustomMessageBox msgBox = new CustomMessageBox();
msgBox.RightButtonContent = "cancel";
msgBox.LeftButtonContent = "delete";
msgBox.Caption = "Are you sure you want to delete?";
msgBox.Title = "Delete message?";
var result = await msgBox.ShowAsync();
// Do something with result

NOTE:  If you are developing a Windows Phone 7 application, you will need the async BCL from nuget

Making the Windows Phone Toolkit ListPicker ItemsPanel display a WrapPanel

There are many things that should be part of the Windows Phone SDK and the ListPicker is one of them. There are so many aspects of the phone that use a control that the ListPicker was based on. One of these is the accent color picker. In Phone 7 the phone would display a vertical list of colors with the name of the colors next to it. In Phone 8 they changed this experience and went with a WrapPanel.

AccentColors

If you want to to get this same experience, you’ll want to use the ListPicker from the Windows Phone Toolkit. The ListPicker will first display what appears to be a ComboBox, yet when you tap this ‘ComboBox’ it opens up and takes over the entire phone. This is all pretty standard and the ListPicker covers this perfectly. Where it fails us is when we want to change how the ListPicker stacks it’s items. This is generally done by changing the ItemsPanel of an ItemsControl. Unfortunately the ListPicker does not allow you to change the ItemsPanel. If you download or browse the source for the ListPicker, you’ll see that it uses a PhoneApplicationPage that has a ListBox in it. The code behind of this page set the ItemTemplate based on a property from the ListPicker, but this is the only one it sets based on a property of the ListPicker.

So here we are with a great control from the toolkit. It allows us to do pretty much everything we need to, but it does not allow us to display a color picker like the native accent color picker. There are two ways that we can accomplish this. The first is to download the source and change it to allow for the ability to override the ItemsPanel. Downloading and changing source is usually risky. It’s risky because you then loose out on any updates that the maintainers may push out. It’s ok provided that you’re ok merging updates with your source.

The second it much easier, does not require you to download source or change any of the toolkit. This simple change requires you to create an implicit style for the ListBox control. Implicit styles allow you to specify a style that all controls of that type will use. To accomplish this, place the following style within your app.xaml

<Style TargetType="ListBox">
    <Setter Property="ItemsPanel">
        <Setter.Value>
            <ItemsPanelTemplate>
                <toolkit:WrapPanel />
            </ItemsPanelTemplate>
        </Setter.Value>
    </Setter>
</Style>

With this in your app.xaml, you can display a WrapPanel within the ListPicker. Unfortunately, with this style, all ListBoxes will display a WrapPanel. If you have other ListBoxes within your app, they will display WrapPanels. You can get the other ListBoxes to display as normal by adding the following style to your app.xaml.

<Style x:Key="StandardListBoxStyle" TargetType="ListBox">
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}"/>
    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
    <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
    <Setter Property="BorderThickness" Value="0"/>
    <Setter Property="BorderBrush" Value="Transparent"/>
    <Setter Property="Padding" Value="0"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ListBox">
                <ScrollViewer x:Name="ScrollViewer" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Foreground="{TemplateBinding Foreground}" Padding="{TemplateBinding Padding}">
                    <ItemsPresenter/>
                </ScrollViewer>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>


Now use this style within your app.

<ListBox Style="{StaticResource StandardListBoxStyle}" ItemsSource="{Binding MyItems}"/>

If you use this approach and you have another ListPicker that you want to use in FullMode, it will display a WrapPanel. If you don’t want to always display a WrapPanel within your ListPicker, or if you don’t want to set the style manually then you’ll need to modify the source code of the ListPicker.

To begin you’ll need to download the source for the Windows Phone Toolkit. The toolkit comes with four projects, two under a Windows Phone 7 folder and two under a Windows Phone 8 folder. The projects use the same code for most of the files. These files have a central location and are added as a link.  You’ll need to modify one file that is shared and another file within each phone 7 and phone 8 project. Open the ListPickerPage.xamlcs file from both the phone 7 and phone 8 project. The ListPicker already has a FullModeItemTemplate, we can continue this style by adding a FullModeItemsPanel.

/// <summary>
/// Gets or sets the ItemsPanel.
/// </summary>
public ItemsPanelTemplate FullModeItemsPanel { get; set; }

Within the OnNavigatedTo method, add the following

if (FullModeItemsPanel != null)
{
    Picker.ItemsPanel = FullModeItemsPanel;
}

Now open the LickPicker.cs file from one of the toolkit projects (not a samples project). Add the following dependency property.

/// <summary>
/// Gets or sets the ItemsPanel used to display the items when ListPickerMode is set to Full.
/// </summary>
public ItemsPanelTemplate FullModeItemsPanel
{
    get { return (ItemsPanelTemplate)GetValue(FullModeItemsPanelProperty); }
    set { SetValue(FullModeItemsPanelProperty, value); }
}
 
/// <summary>
/// Identifies the FullModeItemsPanel DependencyProperty.
/// </summary>
public static readonly DependencyProperty FullModeItemsPanelProperty =
    DependencyProperty.Register(
    "FullModeItemsPanel", 
    typeof(ItemsPanelTemplate), 
    typeof(ListPicker), 
    new PropertyMetadata(null));

Within the OnFrameNavigatedTo method you’ll want to add the following line.

_listPickerPage.FullModeItemsPanel = FullModeItemsPanel;

It’s best to add this line under where the FullModeItemTemplate is set for the page.

I said earlier that changing the source can be risky because you loose out on updates that come from the maintainers of the source. Unfortunately there is little effort going into any of the toolkits from Microsoft and we have yet to see a toolkit for Windows Store apps. Not only does no one work on these toolkit, but you cannot provide contributions. Pedro Lamas has taken the source from codeplex and put it up on github. Pedro is providing fixes and taking pull requests for this repro. I’ve already provided this change and you can download it and start going.

Please, please, please stop using IEnumerable.Count()

As the title says, please, please, please stop using the IEnumerabler Count() extension method UNLESS you must have the count. Over and over again I see this small little snippet

 1: if(myEnumerable.Count() > 0)
 2: {
 3:     // Do stuff
 4: }

This has a huge performance impact on your application. Let’s take a look at what this code is actually doing (decompiled using DotPeek 1.1)

 1: public static int Count<TSource>(this IEnumerable<TSource> source)
 2: {
 3:     if (source == null)
 4:         throw Error.ArgumentNull("source");
 5:     ICollection<TSource> collection1 = source as ICollection<TSource>;
 6:     if (collection1 != null)
 7:         return collection1.Count;
 8:     ICollection collection2 = source as ICollection;
 9:     if (collection2 != null)
 10:         return collection2.Count;
 11:     int num = 0;
 12:     using (IEnumerator<TSource> enumerator = source.GetEnumerator())
 13:     {
 14:         while (enumerator.MoveNext())
 15:             checked { ++num; }
 16:     }
 17:     return num;
 18: }

If your IEnumerable<T> collection supports ICollection<T> then all is well, you'll be accessing a property that already has a value. Many times this is not the case. A lot of APIs will only expose collections as IEnumerable<T>. This follows the Frame Design Guidelines to only expose the minimum (base) interface that you need to. In these cases it must iterate over every single item in your collection to get the count. And all that just to decide if there is at least one item in the collection?!?

Let’s take a look at the Any() extension method.

 1: public static bool Any<TSource>(this IEnumerable<TSource> source)
 2: {
 3:     if (source == null)
 4:         throw Error.ArgumentNull("source");
 5:     using (IEnumerator<TSource> enumerator = source.GetEnumerator())
 6:     {
 7:         if (enumerator.MoveNext())
 8:             return true;
 9:     }
 10:     return false;
 11: }

This method just determines if there is one item in the collection. It does this by attempting to move the iterator one spot. If it can then the collection has an item!. Now, I would probably change lines 7 and 8 to be

 7: return enumerator.MoveNext();

This would remove the need for the if check. Again, this is decompiled code so it’s possible that the actual code is doing this.

So, if you need to know if the collection contains at least one item, and you’re working with an IEnumerable<T>, use the Any() method.

If you want to squeeze every little ounce of performance out of your app continue reading! What I find odd is that the Any() extension method does not try to take advantage of the two most common collections, arrays and ICollection<T>. Both of these collections have a ready made property to aid in this effort. Array has the Length property and ICollection<T> has the Count property. By making a new extension method that takes advantage of these properties you can shrink your calls to Any() in half.

NOTE: In half is very minimal. We’re talking about ticks, not even milliseconds unless it is called MANY MANY times.

   1: public static bool FastAny<TSource>(this IEnumerable<TSource> source)
   2: {
   3:     if (source == null) throw new ArgumentNullException("source");
   4:  
   5:     var array = source as TSource[];
   6:     if (array != null) return array.Length > 0;
   7:  
   8:     var coll = source as ICollection<TSource>;
   9:     if (coll != null) return coll.Count > 0;
  10:  
  11:     using (var enumerator = source.GetEnumerator())
  12:     {
  13:         return enumerator.MoveNext();
  14:     }
  15: }
If you’d like to test this out for yourself, you can run this console application.

Using the WebAPI to send errors for your apps

If your app does anything at all complex, it’s going to crash. You’re going to miss checking something for null. You’re going to use a resource that doesn’t exist. Your app is going to crash. Luckily there are some ways to make sure you know what’s happening. Little Watson by Andy Pennell shows us a great way to send application errors but requires the user to email them to you. Bjorn Kuiper extended Little Watson by removing the need to email the report and instead send it to a PHP endpoint. This is a great solution provided your server is setup to run PHP . If you don’twant to use PHP, don’t want to install PHP or if you are using a hosting service that does not run PHP then you’re out of luck.

Instead of convincing your web provider to install PHP you could create a WCF service, but that seems like a lot of overhead. You could also create an ASP.NET web page and put the error details into a query parameter, but that seems hokie. Luckily the Web API has been introduced. The Web API makes this easy to implement, easy to deploy, and easy to use. Web API allows you to send an object of information in a well known format. Overall, the Web API is just awesome.

The first step is to start with the minimal Web API project. Open the Global.asax file and add the following line inside the Application_Start method

RouteTable.Routes.MapHttpRoute("ErrorRoute", "{controller}/{id}", new { id = RouteParameter.Optional });

Right click on the on controllers folder and create a new ApiController.

image

Following Bjorn’s example, we need an ExceptionContainer class that will hold our exception information. I’ve added an additional property for the application name. This is handy if you have more than one app.

public class ExceptionContainer
{
    ///  <summary>  
    /// Gets or sets the message.  
    /// </summary>  
    public string Message { get; set; }
 
    ///  <summary>  
    /// Gets or sets the stacktrace.  
    /// </summary>  
    public string StackTrace { get; set; }
 
    /// <summary>
    /// The application the error was found.
    /// </summary>
    public string ApplicationName { get; set; }
}

Inside the controller we need one method that we can send exception info to. The Web API allows you to take advantage of the HTTP verbs and structure your API in terms of them. For this error reporting, the most logical verb is POST. We’re not trying to GET, update (PUT) or DELETE anything. Create a new Post method that returns an HttpResponseMessage and takes an ExceptionContainer as a parameter. In the method we’ll send an email.

public HttpResponseMessage Post(ExceptionContainer exception)
{
    if (exception == null) return new HttpResponseMessage(HttpStatusCode.PaymentRequired);
 
    var message = new System.Net.Mail.MailMessage
        {
            From = new System.Net.Mail.MailAddress("phoneApps@yourdomain.com"),
            Subject = "Error report: " + exception.ApplicationName,
            Body = exception.Message + Environment.NewLine + exception.StackTrace
        };
    message.To.Add("you@domain.com");
 
    System.Net.Mail.SmtpClient client = new System.Net.Mail.SmtpClient("localhost", 25);
    // send credentials if your SMTP server requires them
    //client.Credentials = new NetworkCredential("user", "password");
    client.Send(message);
 
    return new HttpResponseMessage(HttpStatusCode.Created);
}

Deploy this up to your site and you’re ready to start sending application errors from your app.  Inside your app you simply need to package up the error and send to your server.

public void SendException(string uri, ExceptionContainer exception)
{
    try
    {
        JsonSerializerSettings settings = new JsonSerializerSettings();
        settings.NullValueHandling = NullValueHandling.Ignore;
        string postStr = JsonConvert.SerializeObject(exception, settings).Replace("\"", "'");
 
        WebClient client = new WebClient();
        client.Headers[HttpRequestHeader.ContentType] = "application/json";
        client.UploadStringAsync(new Uri(uri), postStr);
    }
    catch { }
}

Remember that you should ask the user if you can send error reports, or give them the option to turn it on or off.

Creating a custom async dialog for your Win8 apps Part 2: CustomDialog

In Part 1 of this series I discussed how to create a custom async LoginDialog to use within your Windows Store apps. In this blog, I’ll explain how to turn that dialog into an async dialog that allows for custom content and works more like the MessageDialog. Most of the hard work was already completed in the LoginDialog. It has a constructor that takes content, a ShowAsync method that has the ability to show a dialog asynchronously, responds to a CancellationToken, it is shown as a Popup and responds to the size of the window changing and many more. To create the CustomDialog, I’ll start with the LoginDialog.

For the CustomDialog, I wanted to make it almost identical to the MessageDialog class except replacing the content parameter of the constructor from string, to object. For the new constructors, we’ll be using a ContentPresenter to place the custom content. The ContentPresenter will be created in code when the dialog is shown.

public CustomDialog(object content)
{
    Title = string.Empty;
    Commands = new List<IUICommand>();
    CancelCommandIndex = Int32.MaxValue;
    DefaultCommandIndex = Int32.MaxValue;
    HeaderBrush = new SolidColorBrush(Colors.White);
    Content = content;
}
 
public CustomDialog(object content, string title) : this(content)
{
    if (string.IsNullOrEmpty(title) == false)
    {
        Title = title;
    }
}

Matching the MessageDialog also meant added in custom commands to the dialog that allow for a custom action. Also want to make sure that the default and cancel buttons can be specified.

/// <Summary>
/// Gets or sets the index of the command you want to use as the default. This
/// is the command that fires by default when users press the ENTER key.
/// </Summary>
/// <Returns>The index of the default command.</Returns>
public int DefaultCommandIndex { get; set; }
 
/// <Summary>
/// Gets or sets the index of the command you want to use as the cancel command.
/// This is the command that fires when users press the ESC key.
/// </Summary>
/// <Returns>The index of the cancel command.</Returns>
public int CancelCommandIndex { get; set; }
 
/// <Summary>
/// Gets the set of commands that appear in the command bar of the message dialog.
/// </Summary>
/// <Returns>The commands.</Returns>
public IList<IUICommand> Commands { get; private set; }

When we create the buttons, we need to apply the properties from the custom commands and ensure that the user gets to do their custom action.

private UIElement CreateDialog()
{
    // Create the dialog
    ...
 
    if (Commands.Count == 0)
    {
        Button button = new Button();
        button.Style = buttonStyle;
        button.Content = "Close";
        button.MinWidth = 92;
        button.Margin = new Thickness(20, 20, 0, 20);
        button.Click += (okSender, okArgs) => CloseDialog(null);
        buttonPanel.Children.Add(button);
    }
    else
    {
        foreach (var command in Commands)
        {
            IUICommand currentCommand = command;
            Button button = new Button();
            button.Style = buttonStyle;
            button.Content = command.Label;
            button.Margin = new Thickness(20, 20, 0, 20);
            button.MinWidth = 92;
            button.Click += (okSender, okArgs) => CloseDialog(currentCommand);
            buttonPanel.Children.Add(button);
        }
    }
    ...
}
 
private void CloseDialog(IUICommand command)
{
    UnsubscribeEvents();
 
    if (command != null)
    {
        command.Invoked(command);
    }
    _popup.IsOpen = false;
    _taskCompletionSource.SetResult(command);
}

Now that the dialog has the ability to specify if there is a default and cancel button, we nee to make changes to the KeyDown event of the window.

private void OnKeyDown(object sender, KeyRoutedEventArgs e)
{
    // Only respond to Esc if there is a cancel index
    if ((e.Key == VirtualKey.Escape) && (CancelCommandIndex < Commands.Count))
    {
        OnCanceled();
    }
 
    // Only respond to Enter if there is a cancel index
    if ((e.Key == VirtualKey.Enter) && (DefaultCommandIndex < Commands.Count))
    {
        CloseDialog(Commands[(int)DefaultCommandIndex]);
    }
}

The rest of the CustomDialog is pretty much identical to the LoginDialog. You can download the source and sample application which has both the LoginDialog and CustomDialog in it. If you just want just the CustomDialog class you can download it from GitHub.

Creating a Custom Async Dialog for your Win8 Apps Part 1 - LoginDialog

For a recent Windows Store App, I needed to create a way for people to log into it. I could have easily created a simple control or page that allowed the user to enter their login information, but I wanted to work with the new async/await architecture. I thought that creating a login dialog that fit this pattern would be a fun adventure. I wanted to follow the same pattern found in the MessageDialog class so it would be easy to use and understand how it works. This is part one of a two part blog. Part one will cover creating a LoginDialog class that only handles the ability to login. Part two will cover changing that class to be a more generic CustomDialog class that allows for custom content. By the end of the blog we’ll create a LoginDialog that will display a login to the user that looks a lot like the login you get from the People app.

image

This first stab at the dialog will focus on the ability to login, so we need a class that will hold the information the user enters.

public class LoginResult
{
    public string Name { get; set; }
    public string Password { get; set; }
}

Next, let’s stub out what the API will look like. As I said, I wanted this to follow the same pattern as the MessageDialog, so I’ll create a class that closely mirrors that functionality

public class LoginDialog
{
    public LoginDialog(string title) { }
 
    public LoginDialog(string title, string content) : this(title) { }
 
    public IAsyncOperation<LoginResult> ShowAsync() { }
}

Notice that this is just a plain class. It is not a UIControl. This means that you cannot place this into your XAML, you can only create and show it from code. The LoginDialog is not a control, but it does need to display a control. There are two ways you could go about doing this. One is to create a class that is the control to display, the other is to create the control in code within the LoginDialog itself. The first is probably the easiest, but I wanted to accomplish this with only one class. I could have made an internal control that is only used by the LoginDialog (and this is the easier way to go and I’ll show using it later) but I wanted to try doing this with only one class. For now I’ll just stub out the creation of the actual control within the ShowAsync method. This method needs to return an IAsyncOperation of type LoginResult. To create an instance of IAsyncOperation you use the static Run method of the AsyncInfo.

private Popup _popup;
private TaskCompletionSource<LoginResult> _taskCompletionSource;
 
public IAsyncOperation<LoginResult> ShowAsync()
{
    _popup = new Popup { Child = CreateLogin() };
    if (_popup.Child != null)
    {
        _popup.IsOpen = true;
    }
    return AsyncInfo.Run(token => WaitForInput(token));
}
 
private Task<LoginResult> WaitForInput(CancellationToken token)
{
    _taskCompletionSource = new TaskCompletionSource<LoginResult>();
 
    token.Register(OnCanceled);
    
    return _taskCompletionSource.Task;
}

The WaitForInput method allows me to create the TaskCompletionSource that will be used to return the result. TaskCompletionSource is an awesome class that allows you to set the result at a later time. The WaitForInput method returns the Task property of the TaskCompletionSource. This allows for some async goodness. The code will wait until the SetResult method is called on the TaskCompletionSource.

To set the result of TaskCompletionSource and ultimately of the ShowAsync method we need two methods, one for when the dialog is canceled and one for when the user has entered their information. The cancel method will handle if the user clicked the cancel button or, if the application cancels the IAsyncOperation within the code. Note: I tried using the cancelation token for the cancel method but that did not do anything.

private void OnCompleted()
{
    var result = new LoginResult();
    result.Name = _userTextBox.Text;
    result.Password = _passwordTextBox.Password;
 
    _popup.IsOpen = false;
    _taskCompletionSource.SetResult(result);
}
 
private void OnCanceled()
{
    // null to indicate dialog was canceled
    LoginResult result = null;
 
    _popup.IsOpen = false;
    _taskCompletionSource.SetResult(result);
}

This is the basics of what we need, however windows store apps have so many visual states and sizes to be aware of. This means that the dialog needs to be aware of a few different events. If the app is on a small tablet the dialog needs to adjust for the virtual keyboard. If your app supports portrait the dialog needs to resize itself correctly.

// adjust for different view states
private void OnWindowSizeChanged(object sender, WindowSizeChangedEventArgs e)
{
    if (_popup.IsOpen == false) return;
 
    var child = _popup.Child as FrameworkElement;
    if (child == null) return;
 
    child.Width = e.Size.Width;
    child.Height = e.Size.Height;
} 
 
// Adjust the name/password textboxes for the virtual keyuboard
private void OnInputShowing(InputPane sender, InputPaneVisibilityEventArgs args)
{
    var child = _popup.Child as FrameworkElement;
    if (child == null) return;
 
    var transform = _passwordTextBox.TransformToVisual(child);
    var topLeft = transform.TransformPoint(new Point(0, 0));
 
    // Need to be able to view the entire textblock (plus a little more)
    var buffer = _passwordTextBox.ActualHeight + 10; 
    if ((topLeft.Y + buffer) > sender.OccludedRect.Top)
    {
        var margin = topLeft.Y - sender.OccludedRect.Top;
        margin += buffer;
        child.Margin = new Thickness(0, -margin, 0, 0);
    }
}
 
private void OnInputHiding(InputPane sender, InputPaneVisibilityEventArgs args)
{
    var child = _popup.Child as FrameworkElement;
    if (child == null) return;
 
    child.Margin = new Thickness(0);
}

We only want to subscribe to these events when the user shows the dialog (within the ShowAsync method), and we want to unsubscribe from the events when the dialog closes (OnCanceled and OnCompleted methods). Another event that is good to listen to is the KeyDown event of the window. If the user presses the escape key you should cancel the dialog.

private void SubscribeEvents()
{
    Window.Current.SizeChanged += OnWindowSizeChanged;
    Window.Current.Content.KeyDown += OnKeyDown;
 
    var input = InputPane.GetForCurrentView();
    input.Showing += OnInputShowing;
    input.Hiding += OnInputHiding;
}
 
private void UnsubscribeEvents()
{
    Window.Current.SizeChanged -= OnWindowSizeChanged;
    Window.Current.Content.KeyDown -= OnKeyDown;
 
    var input = InputPane.GetForCurrentView();
    input.Showing -= OnInputShowing;
    input.Hiding -= OnInputHiding;
}

The only thing I’ve left out is the creation of the actual dialog. For this I used a cool github project called XAML Conversion by Petr Onderka. I created the XAML in a user control and used this tool to convert it to code. For the most part it worked really well. It did require that you put children of panels into the Child tag.

<Border Background=""Red"" Height=""80"">
    <Border.Child>
        <TextBlock Text="Hello"/>
    </Border.Child>
</Border>

Download the source and sample application today. This application takes advantage of the light styles I blogged about before.

Easily create light themed styles for your Win8 Settings Flyout

One of the things I love about Windows Store apps is their ability to integrate with the system. One of these integration points is the Settings Charm. I’m not going to show you how to create a settings flyout. There are already lots of examples out there that do this. There are even some helpers like the SettingsFlyout available in Callisto and the helper created by Jerry Nixon. Recently Tim Heuer made a change to the SettingsFlyout to set the background to white. This change allows your app to follow the guidelines. He also added a property that allows you to change what you want the background to be if you are not a fan of white.

This change to the background works great if your app has a light requested theme. If you are using the default dark theme then the new background on the flyout becomes a nightmare. It’s a nightmare because now you have to style all of the controls you use for your settings to work properly with a light theme. You could easily start changing the brushes of various properties, but this doesn’t look very polished. You could restyle the controls and start to guess and what colors to use for this or that, but you’ll forget something (at least I did, and it was a lot).

There has to be an easy way to get light themed styles at runtime, right? I couldn’t find one, but I did find a way to easily create them. The resources and styles used by controls within the app are generally not found within the app itself. The app requests a theme from the system and that theme has all of resources and styles. This allows you to create custom controls and use those brushes and have the control be styled properly for both light and dark themed apps. These resources are not found within your app, but they are on your machine.

The styles and resources for WinRT are found at C:\Program Files (x86)\Windows Kits\8.0\Include\WinRT\Xaml\Design. This folder has two files in it. The themeresource.xaml file has all of the brushes, and other resources like font size and opacity. The generic.xaml file has all of these resources as well as all of the styles for each control. We can use these files to build our light themed styles.

To start with, open the project you need the light styles in, and add a new resource dictionary to store all of our light styles. In the Solution Explorer window, right click the Common folder and select Add –> New Item…

image

In the Add New Item dialog, select Resource Dictionary and name it LightStandardStyles.xaml

image

We then need to add this xaml to our App.xaml. Open the App.xaml and copy the line that adds the StandardStyles.xaml, paste it directly under that line and change the name to LightStandardStyles.

<ResourceDictionary Source="Common/StandardStyles.xaml"/>
<ResourceDictionary Source="Common/LightStandardStyles.xaml"/>

Let’s say you need to have a light themed button. Open LightStandardStyles.xaml and also open C:\Program Files (x86)\Windows Kits\8.0\Include\WinRT\Xaml\Design\generic.xaml.  Search for TargetType="Button" in the file. Copy the style and paste the style into LightStandardStyles. Give the style the key LightButtonStyle. Next open themeresource.xaml and collapse the “Default” and “HighContrast” ResourceDictionary. Now it’s as simple as searching for the brushes used within the button style and copy/paste them from the themeresource file and paste them into LightStandardStyles.

After doing this, the file should look like this.

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
 
    <SolidColorBrush x:Key="ButtonBackgroundThemeBrush" Color="#B3B6B6B6" />
    <SolidColorBrush x:Key="ButtonBorderThemeBrush" Color="#33000000" />
    <SolidColorBrush x:Key="ButtonDisabledBackgroundThemeBrush" Color="#66CACACA" />
    <SolidColorBrush x:Key="ButtonDisabledBorderThemeBrush" Color="#1A000000" />
    <SolidColorBrush x:Key="ButtonDisabledForegroundThemeBrush" Color="#66000000" />
    <SolidColorBrush x:Key="ButtonForegroundThemeBrush" Color="#FF000000" />
    <SolidColorBrush x:Key="ButtonPointerOverBackgroundThemeBrush" Color="#D1CDCDCD" />
    <SolidColorBrush x:Key="ButtonPointerOverForegroundThemeBrush" Color="#FF000000" />
    <SolidColorBrush x:Key="ButtonPressedBackgroundThemeBrush" Color="#FF000000" />
    <SolidColorBrush x:Key="ButtonPressedForegroundThemeBrush" Color="#FFFFFFFF" />
    <SolidColorBrush x:Key="FocusVisualBlackStrokeThemeBrush" Color="Black" />
    <SolidColorBrush x:Key="FocusVisualWhiteStrokeThemeBrush" Color="White" />
 
    <Style x:Key="LightButtonStyle" TargetType="Button">
        <Setter Property="Background" Value="{StaticResource ButtonBackgroundThemeBrush}" />
        <Setter Property="Foreground" Value="{StaticResource ButtonForegroundThemeBrush}"/>
        <Setter Property="BorderBrush" Value="{StaticResource ButtonBorderThemeBrush}" />
        <Setter Property="BorderThickness" Value="{StaticResource ButtonBorderThemeThickness}" />
        <Setter Property="Padding" Value="12,4,12,4" />
        <Setter Property="HorizontalAlignment" Value="Left" />
        <Setter Property="VerticalAlignment" Value="Center" />
        <Setter Property="FontFamily" Value="{StaticResource ContentControlThemeFontFamily}" />
        <Setter Property="FontWeight" Value="SemiBold" />
        <Setter Property="FontSize" Value="{StaticResource ControlContentThemeFontSize}" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Grid>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal" />
                                <VisualState x:Name="PointerOver">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                                                       Storyboard.TargetProperty="Background">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonPointerOverBackgroundThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                                       Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonPointerOverForegroundThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Pressed">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                                                       Storyboard.TargetProperty="Background">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonPressedBackgroundThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                                       Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonPressedForegroundThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Disabled">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                                                       Storyboard.TargetProperty="Background">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonDisabledBackgroundThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                                                       Storyboard.TargetProperty="BorderBrush">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonDisabledBorderThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                                       Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource ButtonDisabledForegroundThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                            <VisualStateGroup x:Name="FocusStates">
                                <VisualState x:Name="Focused">
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="FocusVisualWhite"
                                                         Storyboard.TargetProperty="Opacity"
                                                         To="1"
                                                         Duration="0" />
                                        <DoubleAnimation Storyboard.TargetName="FocusVisualBlack"
                                                         Storyboard.TargetProperty="Opacity"
                                                         To="1"
                                                         Duration="0" />
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Unfocused" />
                                <VisualState x:Name="PointerFocused" />
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <Border x:Name="Border"
                                Background="{TemplateBinding Background}"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}"
                                Margin="3">
                            <ContentPresenter x:Name="ContentPresenter"
                                              Content="{TemplateBinding Content}"
                                              ContentTransitions="{TemplateBinding ContentTransitions}"
                                              ContentTemplate="{TemplateBinding ContentTemplate}"
                                              Margin="{TemplateBinding Padding}"
                                              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                        </Border>
                        <Rectangle x:Name="FocusVisualWhite"
                                   IsHitTestVisible="False"
                                   Stroke="{StaticResource FocusVisualWhiteStrokeThemeBrush}"
                                   StrokeEndLineCap="Square"
                                   StrokeDashArray="1,1"
                                   Opacity="0"
                                   StrokeDashOffset="1.5" />
                        <Rectangle x:Name="FocusVisualBlack"
                                   IsHitTestVisible="False"
                                   Stroke="{StaticResource FocusVisualBlackStrokeThemeBrush}"
                                   StrokeEndLineCap="Square"
                                   StrokeDashArray="1,1"
                                   Opacity="0"
                                   StrokeDashOffset="0.5" />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

Next it’s as simple as prefixing each of these resources with ‘Light’. Doing this results in the following file

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
 
    <SolidColorBrush x:Key="LightButtonBackgroundThemeBrush" Color="#B3B6B6B6" />
    <SolidColorBrush x:Key="LightButtonBorderThemeBrush" Color="#33000000" />
    <SolidColorBrush x:Key="LightButtonDisabledBackgroundThemeBrush" Color="#66CACACA" />
    <SolidColorBrush x:Key="LightButtonDisabledBorderThemeBrush" Color="#1A000000" />
    <SolidColorBrush x:Key="LightButtonDisabledForegroundThemeBrush" Color="#66000000" />
    <SolidColorBrush x:Key="LightButtonForegroundThemeBrush" Color="#FF000000" />
    <SolidColorBrush x:Key="LightButtonPointerOverBackgroundThemeBrush" Color="#D1CDCDCD" />
    <SolidColorBrush x:Key="LightButtonPointerOverForegroundThemeBrush" Color="#FF000000" />
    <SolidColorBrush x:Key="LightButtonPressedBackgroundThemeBrush" Color="#FF000000" />
    <SolidColorBrush x:Key="LightButtonPressedForegroundThemeBrush" Color="#FFFFFFFF" />
    <SolidColorBrush x:Key="LightFocusVisualBlackStrokeThemeBrush" Color="Black" />
    <SolidColorBrush x:Key="LightFocusVisualWhiteStrokeThemeBrush" Color="White" />
 
    <Style x:Key="LightButtonStyle" TargetType="Button">
        <Setter Property="Background" Value="{StaticResource LightButtonBackgroundThemeBrush}" />
        <Setter Property="Foreground" Value="{StaticResource LightButtonForegroundThemeBrush}"/>
        <Setter Property="BorderBrush" Value="{StaticResource LightButtonBorderThemeBrush}" />
        <Setter Property="BorderThickness" Value="{StaticResource ButtonBorderThemeThickness}" />
        <Setter Property="Padding" Value="12,4,12,4" />
        <Setter Property="HorizontalAlignment" Value="Left" />
        <Setter Property="VerticalAlignment" Value="Center" />
        <Setter Property="FontFamily" Value="{StaticResource ContentControlThemeFontFamily}" />
        <Setter Property="FontWeight" Value="SemiBold" />
        <Setter Property="FontSize" Value="{StaticResource ControlContentThemeFontSize}" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <Grid>
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal" />
                                <VisualState x:Name="PointerOver">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                                                       Storyboard.TargetProperty="Background">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource LightButtonPointerOverBackgroundThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                                       Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource LightButtonPointerOverForegroundThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Pressed">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                                                       Storyboard.TargetProperty="Background">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource LightButtonPressedBackgroundThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                                       Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource LightButtonPressedForegroundThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Disabled">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                                                       Storyboard.TargetProperty="Background">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource LightButtonDisabledBackgroundThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Border"
                                                                       Storyboard.TargetProperty="BorderBrush">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource LightButtonDisabledBorderThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                                                       Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource LightButtonDisabledForegroundThemeBrush}" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                            <VisualStateGroup x:Name="FocusStates">
                                <VisualState x:Name="Focused">
                                    <Storyboard>
                                        <DoubleAnimation Storyboard.TargetName="FocusVisualWhite"
                                                         Storyboard.TargetProperty="Opacity"
                                                         To="1"
                                                         Duration="0" />
                                        <DoubleAnimation Storyboard.TargetName="FocusVisualBlack"
                                                         Storyboard.TargetProperty="Opacity"
                                                         To="1"
                                                         Duration="0" />
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Unfocused" />
                                <VisualState x:Name="PointerFocused" />
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <Border x:Name="Border"
                                Background="{TemplateBinding Background}"
                                BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}"
                                Margin="3">
                            <ContentPresenter x:Name="ContentPresenter"
                                              Content="{TemplateBinding Content}"
                                              ContentTransitions="{TemplateBinding ContentTransitions}"
                                              ContentTemplate="{TemplateBinding ContentTemplate}"
                                              Margin="{TemplateBinding Padding}"
                                              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                              VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                        </Border>
                        <Rectangle x:Name="FocusVisualWhite"
                                   IsHitTestVisible="False"
                                   Stroke="{StaticResource LightFocusVisualWhiteStrokeThemeBrush}"
                                   StrokeEndLineCap="Square"
                                   StrokeDashArray="1,1"
                                   Opacity="0"
                                   StrokeDashOffset="1.5" />
                        <Rectangle x:Name="FocusVisualBlack"
                                   IsHitTestVisible="False"
                                   Stroke="{StaticResource LightFocusVisualBlackStrokeThemeBrush}"
                                   StrokeEndLineCap="Square"
                                   StrokeDashArray="1,1"
                                   Opacity="0"
                                   StrokeDashOffset="0.5" />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

With this you can create a light style pretty quickly. But today, and today only, you can download the light styles that I created. This resource file has light themed styles for the ToggleSwitch, TextBox, ComboBox, Button (including a LightAppBarButtonStyle) and all of the standard TextBlock styles.