Windows Store Apps, Error: The certificate specified has expired.

Today I tried to update one of my Windows Store Apps. When I tried to create an App Package for the Store I got an error. One that was completely new to me.

The certificate specified has expired. For more information about renewing certificates, see http://go.microsoft.com/fwlink/?LinkID=241478.

We’re lucky this time, renewing the certificate is very easy. Just follow below steps (copied from MSDN).

  1. In Solution Explorer, open the shortcut menu for the .appxmanifest file, choose Open With, and then choose App Manifest Designer.
  2. In the App Manifest Designer, choose the Packaging tab, and then choose the Choose Certificate button.
  3. In the Choose Certificate dialog box, expand the Configure Certificate list, and then choose Create test certificate.
  4. In the Create test certificate dialog box, click the OK button.

In the end Visual Studio will generate the new certificate with a new expiry date. The new certificate will be valid for a full year.

Navigation through your Windows Style app

I was navigating through the code I found inside the default project templates that are available for Windows Style apps. They already contain a lot of plumbing, specially around navigating through pages.

While reading the LayoutAwarePage.cs I found some code that handles keystrokes. I even found out something I did not know.

- Navigate backward in an app using Alt+Left
- Navigate forward in an app using Alt+Right

But strangely, I’m using to navigate backward using the Backspace key, this was not in the default LayoutAwarePage.cs code. But when you for example use the Store app navigating backward using the Backspace key will work. So let’s improve the default LayoutAwarePage to support the Backspace key as well. Just add the highlighted code to the CodeDispatcher_AcceleratorKeyActived method inside the LayoutAwarePage.cs.

/// <summary>
/// Invoked on every keystroke, including system keys such as Alt key combinations, when
/// this page is active and occupies the entire window.  Used to detect keyboard navigation
/// between pages even when the page itself doesn't have focus.
/// </summary>
/// <param name="sender">Instance that triggered the event.</param>
/// <param name="args">Event data describing the conditions that led to the event.</param>
private void CoreDispatcher_AcceleratorKeyActivated(CoreDispatcher sender,
                                                    AcceleratorKeyEventArgs args)
{
    VirtualKey virtualKey = args.VirtualKey;

    // Only investigate further when Left, Right, or the dedicated Previous or Next keys
    // are pressed
    if ((args.EventType == CoreAcceleratorKeyEventType.SystemKeyDown ||
            args.EventType == CoreAcceleratorKeyEventType.KeyDown) &&
        (virtualKey == VirtualKey.Left || virtualKey == VirtualKey.Right ||
            (int) virtualKey == 166 || (int) virtualKey == 167))
    {
        CoreWindow coreWindow = Window.Current.CoreWindow;
        var downState = CoreVirtualKeyStates.Down;
        bool menuKey = (coreWindow.GetKeyState(VirtualKey.Menu) & downState) == downState;
        bool controlKey = (coreWindow.GetKeyState(VirtualKey.Control) & downState) == downState;
        bool shiftKey = (coreWindow.GetKeyState(VirtualKey.Shift) & downState) == downState;
        bool noModifiers = !menuKey && !controlKey && !shiftKey;
        bool onlyAlt = menuKey && !controlKey && !shiftKey;

        if (((int) virtualKey == 166 && noModifiers) ||
            (virtualKey == VirtualKey.Left && onlyAlt))
        {
            // When the previous key or Alt+Left are pressed navigate back
            args.Handled = true;
            this.GoBack(this, new RoutedEventArgs());
        }
        else if (((int) virtualKey == 167 && noModifiers) ||
                    (virtualKey == VirtualKey.Right && onlyAlt))
        {
            // When the next key or Alt+Right are pressed navigate forward
            args.Handled = true;
            this.GoForward(this, new RoutedEventArgs());
        }
    }
    if((args.EventType == CoreAcceleratorKeyEventType.SystemKeyDown ||
            args.EventType == CoreAcceleratorKeyEventType.KeyDown) && args.VirtualKey==VirtualKey.Back)
    {
        args.Handled = true;
        this.GoBack(this, new RoutedEventArgs());
    }
}

Get more quality reviews for your Windows Style apps

I’ve been creating Windows Phone apps for more than two years, so more and more concepts I use in the Phone apps should be ported to Windows Style apps (former Metro). One of these concepts is the question to review the app after 5 application starts. I currently have made two Windows Style apps, and more are coming, but it’s time to improve the quality and get some reviews.

Yesterday evening I started working on a solution and also discussed it with Matthijs Hoekstra, Fons Sonnemans, Martijn de Meulder and Glenn Versweyveld. So let’s start with the end result. How does it look?!

screenshot_10212012_195138

Yes it’s just a flyout with two buttons. The “Review” button should take you directly to the Store’s review page for the current app. But what about the “Improvements” button? The idea came from Martijn, give your users a way to tell you things you could improve in the app and you’ll definitely get less 1- and 2-star ratings. So it should open the e-mail app.

Store app startup count

Of course something like the startup count can be easily stored in the RoamingSettings, so that even over more than one device you won’t show the review question more than once.

private static int ApplicationStarts
{
    get
    {
        object val = ApplicationData.Current.RoamingSettings.Values["ReviewHelper.AppStarts"];
        return val == null ? 0 : (int)val;
    }
    set { ApplicationData.Current.RoamingSettings.Values["ReviewHelper.AppStarts"] = value; }
}

Flyout

The easiest way to get a flyout in your app is by making use of the Callisto framework created by Tim Heuer. Just make use of nuget to get it installed.

I’m just construction the UI you’ve seen in the example above in code. It’s not difficult code, but most of you probably create the UI only in Xaml. I thought this was easier to combine with the Flyout.

var appName = Application.Current.Resources["AppName"] as string;

var content = new StackPanel
                    {
                        Margin = new Thickness(16)
                    };
content.Children.Add(new TextBlock
                            {
                                Text =
                                    string.Format(
                                        "Thanks for using the {0} app. Would you like to review this app?",
                                        appName),
                                TextWrapping = TextWrapping.Wrap,
                                FontSize = 16,
                            });
var improveButton = new Button
                        {
                            Content = "Improvements?",
                            HorizontalAlignment = HorizontalAlignment.Right,
                            Background = new SolidColorBrush(Colors.Red),
                            Foreground = new SolidColorBrush(Colors.White),
                        };
improveButton.SetValue(ToolTipService.ToolTipProperty, "Send an e-mail with improvements.");
improveButton.Click +=
    (s, e) =>
        {
        };
var reviewButton = new Button
                        {
                            Content = "Review",
                            HorizontalAlignment = HorizontalAlignment.Right,
                            Background = new SolidColorBrush(Colors.Red),
                            Foreground = new SolidColorBrush(Colors.White)
                        };
reviewButton.Click += (s, e) =>
                            {
                            };
var buttonPanel = new StackPanel
                        {
                            Orientation = Orientation.Horizontal,
                            HorizontalAlignment = HorizontalAlignment.Right
                        };
buttonPanel.Children.Add(improveButton);
buttonPanel.Children.Add(reviewButton);
content.Children.Add(buttonPanel);
var flyout = new Flyout
                    {
                        Content = content,
                        Placement = PlacementMode.Top,
                        PlacementTarget = page,
                    };

We should not forget to open the flyout.

flyout.IsOpen = true;

Handling the Button clicks

We are still missing the click implementations of the buttons. So let’s do the Improve button’s click implementation. I want to show the e-mail application with a subject prefilled. This is something that I’m used to do in websites by using the mailto uri scheme this also works in Windows Style apps. To be more precise using Uri’s is one of the ways to integrate your app with apps like Mail, Maps and the Store. Sadly the Uri schemes you can use are often not that well documented, yet. But we’re lucky, the mailto scheme, is well documented.

improveButton.Click +=
    (s, e) =>
        {
            Launcher.LaunchUriAsync(
                new Uri(string.Format("mailto:{0}?subject=Improvements for {1}",
                                        "support@someurl.com", appName.Replace("&", "%26"))));
        };

That was the easy part, how do we access the Store app? We can use an Uri scheme as well, documented, but not completely. We’re lucky again, Andy Beaulieu found out a way to show the review page for an app. That information together with the knowledge that we can get the “Package Family Name” through code as well, give us this code.

reviewButton.Click +=
    (s, e) =>
        {
            string familyName = Package.Current.Id.FamilyName;
            Launcher.LaunchUriAsync(
                new Uri(string.Format("ms-windows-store:REVIEW?PFN={0}", familyName)));
        };

Completing

So I package the above code in side a class (toggle to view the code).

public static class PageExtensions
{
    private static int ApplicationStarts
    {
        get
        {
            object val = ApplicationData.Current.RoamingSettings.Values["ReviewHelper.AppStarts"];
            return val == null ? 0 : (int) val;
        }
        set { ApplicationData.Current.RoamingSettings.Values["ReviewHelper.AppStarts"] = value; }
    }

    public static void AskForReviewAfter(this Frame page, int times)
    {
        ApplicationStarts++;
        if (ApplicationStarts != times)
        {
            var appName = Application.Current.Resources["AppName"] as string;

            var content = new StackPanel
                                {
                                    Margin = new Thickness(16)
                                };
            content.Children.Add(new TextBlock
                                        {
                                            Text =
                                                string.Format(
                                                    "Thanks for using the {0} app. Would you like to review this app?",
                                                    appName),
                                            TextWrapping = TextWrapping.Wrap,
                                            FontSize = 16,
                                        });
            var improveButton = new Button
                                    {
                                        Content = "Improvements?",
                                        HorizontalAlignment = HorizontalAlignment.Right,
                                        Background = new SolidColorBrush(Colors.Red),
                                        Foreground = new SolidColorBrush(Colors.White),
                                    };
            improveButton.SetValue(ToolTipService.ToolTipProperty, "Send an e-mail with improvements.");
            improveButton.Click +=
                (s, e) =>
                    {
                        Launcher.LaunchUriAsync(
                            new Uri(string.Format("mailto:{0}?subject=Improvements for {1}",
                                                    "support@someurl.com", appName.Replace("&", "%26"))));
                    };
            var reviewButton = new Button
                                    {
                                        Content = "Review",
                                        HorizontalAlignment = HorizontalAlignment.Right,
                                        Background = new SolidColorBrush(Colors.Red),
                                        Foreground = new SolidColorBrush(Colors.White)
                                    };
            reviewButton.Click +=
                (s, e) =>
                    {
                        string familyName = Package.Current.Id.FamilyName;
                        Launcher.LaunchUriAsync(
                            new Uri(string.Format("ms-windows-store:REVIEW?PFN={0}", familyName)));
                    };
            var buttonPanel = new StackPanel
                                    {
                                        Orientation = Orientation.Horizontal,
                                        HorizontalAlignment = HorizontalAlignment.Right
                                    };
            buttonPanel.Children.Add(improveButton);
            buttonPanel.Children.Add(reviewButton);
            content.Children.Add(buttonPanel);
            var flyout = new Flyout
                                {
                                    Content = content,
                                    Placement = PlacementMode.Top,
                                    PlacementTarget = page,
                                };

            flyout.IsOpen = true;
        }
    }
}

And I call this code just after activating the Window in the App.xaml.cs file.

// Ensure the current window is active
Window.Current.Activate();

rootFrame.Loaded +=
    (s, e) =>
        {
            //Rootframe loaded.
            Debug.WriteLine("RootFrame Loaded.");
            (s as Frame).AskForReviewAfter(5);
        };

Get the version of your WinRT Package

It might sound strange, but I couldn’t find any place on how to get the version number of the WinRT Package. I want to use the Major and Minor version number parts as part of a HTTP Request. It’s simpler than in the Windows Phone world.

using Windows.ApplicationModel;

PackageVersion version = Package.Current.Id.Version;
string versionString = string.Format("{0}.{1}",version.Major, version.Minor);

 

Wow this was a small post!

MetroGridHelper for WinRT v1.1–Enhanced to work with Snapped and Portrait mode

Because the left-margin is different for Snapped and Portrait mode, the previous version of MetroGridHelper for WinRT was not optimal. It didn’t support a different left margins at all. Don’t be sad, v1.1 supports Filled (120px), Snapped(20px), Fullscreen Landscape(100px) and Fullscreen Portrait(100px).

You can find the updated version on NuGet.

If you’re new to the MetroGridHelper for winrt you can execute the below command in the NuGet Package Manager Console:

PM> Install-Package WinRT.MetroGridHelper

If you have already installed the previous version you can also do the Update-Package command via the Package Manager Console:

PM> Update-Package WinRT.MetroGridHelper

Ah you want to see how it looks like?

screenshot_07252012_204328

screenshot_08032012_224037screenshot_08032012_223554

The code? Yes of course.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using Windows.Graphics.Display;
using Windows.UI;
using Windows.UI.Core;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes;

namespace MC.MetroGridHelper
{
    /// <summary>
    /// A utility class that overlays a designer-friendly grid on top of the
    /// application frame, for use similar to the performance counters in
    /// App.xaml.cs. The color and opacity are configurable. The grid contains
    /// a number of squares that are 24x24, offset with 12px gutters, and all
    /// 24px away from the edge of the device.
    /// </summary>
    public static class MetroGridHelper
    {
        private static bool _visible;
        private static double _opacity = 0.15;
        private static Color _color = Colors.Red;
        private static List<Shape> _shapes;
        private static Grid _grid;
        private static bool _eventsAttached;
        private static double _width;
        private static double _height;

        /// <summary>
        /// Gets or sets a value indicating whether the designer grid is
        /// visible on top of the application's frame.
        /// </summary>
        public static bool IsVisible
        {
            get { return _visible; }
            set
            {
                _visible = value;
                UpdateGrid();
            }
        }

        /// <summary>
        /// Gets or sets the color to use for the grid's squares.
        /// </summary>
        public static Color Color
        {
            get { return _color; }
            set
            {
                _color = value;
                UpdateGrid();
            }
        }

        /// <summary>
        /// Gets or sets a value indicating the opacity for the grid's squares.
        /// </summary>
        public static double Opacity
        {
            get { return _opacity; }
            set
            {
                _opacity = value;
                UpdateGrid();
            }
        }

        /// <summary>
        /// Updates the grid (if it already has been created) or initializes it
        /// otherwise.
        /// </summary>
        private static void UpdateGrid()
        {
            if (_shapes != null)
            {
                var brush = new SolidColorBrush(_color);
                foreach (Shape square in _shapes)
                {
                    square.Fill = brush;
                }
                if (_grid != null)
                {
                    _grid.Visibility = _visible ? Visibility.Visible : Visibility.Collapsed;
                    _grid.Opacity = _opacity;
                }
            }
            else
            {
                BuildGrid();
            }
        }

        /// <summary>
        /// Builds the grid.
        /// </summary>
        private static async void BuildGrid()
        {
            _shapes = new List<Shape>();

            var frame = Window.Current.Content as Frame;
            if (frame == null || VisualTreeHelper.GetChildrenCount(frame) == 0)
            {
                await Window.Current.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, BuildGrid);
                return;
            }

            DependencyObject child = VisualTreeHelper.GetChild(frame, 0);
            var childAsBorder = child as Border;
            var childAsGrid = child as Grid;
            if (childAsBorder != null)
            {
                // Not a pretty way to control the root visual, but I did not
                // want to implement using a popup.
                UIElement content = childAsBorder.Child;
                if (content == null)
                {
                    await Window.Current.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, BuildGrid);
                    return;
                }
                childAsBorder.Child = null;
                await Window.Current.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
                                                         () =>
                                                             {
                                                                 var newGrid = new Grid();
                                                                 childAsBorder.Child = newGrid;
                                                                 newGrid.Children.Add(content);
                                                                 PrepareGrid(newGrid);
                                                                 AttachEvents();
                                                             });
            }
            else if (childAsGrid != null)
            {
                PrepareGrid(childAsGrid);
                AttachEvents();
            }
            else
            {
                Debug.WriteLine("Dear developer:");
                Debug.WriteLine("Unfortunately the design overlay feature requires that the root frame visual");
                Debug.WriteLine("be a Border or a Grid. So the overlay grid just isn't going to happen.");
            }
        }

        private static void AttachEvents()
        {
            if (_eventsAttached)
                return;
            Window.Current.SizeChanged += (s, e) => BuildGridForCurrentView();
            DisplayProperties.OrientationChanged += s => BuildGridForCurrentView(); 
            _eventsAttached = true;
        }

        public static void CreateGrid()
        {
            IsVisible = true;
        }

        /// <summary>
        /// Does the actual work of preparing the grid once the parent frame is
        /// in the visual tree and we have a Grid instance to work with for
        /// placing the chilren.
        /// </summary>
        /// <param name="parent">The parent grid to insert the sub-grid into.</param>
        private static void PrepareGrid(Grid parent)
        {
            if (_grid == null)
            {
                _grid = new Grid
                            {
                                IsHitTestVisible = false,
                                Visibility = _visible ? Visibility.Visible : Visibility.Collapsed,
                                Opacity = _opacity,
                                CacheMode = new BitmapCache()
                            };
                parent.Children.Add(_grid);
            }
            BuildGridForCurrentView();
        }

        public static int GetMarginForCurrentView()
        {
            bool isSnapped = ApplicationView.Value == ApplicationViewState.Snapped;
            bool isPortrait = DisplayProperties.CurrentOrientation == DisplayOrientations.Portrait ||
                              DisplayProperties.CurrentOrientation == DisplayOrientations.PortraitFlipped;
            if (isSnapped)
                return 20;
            if (isPortrait)
                return 100;
            return 120;
        }

        public static void BuildGridForCurrentView()
        {
            // Places the grid into the visual tree. It is never removed once
            // being added.
            var frame = Window.Current.Content as Frame;
            if (frame == null)
                return;

            _width=Math.Max(_width, frame.ActualWidth);
            _height=Math.Max(_height, frame.ActualHeight);
            _grid.Children.Clear();
            _shapes.Clear();
            IEnumerable<Shape> shapes = GetGridShapesForMargin(_width, _height, GetMarginForCurrentView());
            foreach (Shape shape in shapes)
            {
                _grid.Children.Add(shape);
                _shapes.Add(shape);
            }
        }

        public static IEnumerable<Shape> GetGridShapesForMargin(double width, double height, int margin)
        {
            // To support both orientations, unfortunately more visuals need to
            // be used. An alternate implementation would be to react to the
            // orientation change event and re-draw/remove squares.
            var brush = new SolidColorBrush(_color);
            double max = Math.Max(width, height);

            const double strokeWidth = 2.0;

            var horizontalLine = new Line
                                     {
                                         IsHitTestVisible = false,
                                         Stroke = brush,
                                         X1 = 0,
                                         X2 = max,
                                         Y1 = 100 + (strokeWidth/2),
                                         Y2 = 100 + (strokeWidth/2),
                                         StrokeThickness = strokeWidth,
                                     };
            yield return horizontalLine;
            var horizontalLine2 = new Line
                                      {
                                          IsHitTestVisible = false,
                                          Stroke = brush,
                                          X1 = 0,
                                          X2 = max,
                                          Y1 = 140 + (strokeWidth/2),
                                          Y2 = 140 + (strokeWidth/2),
                                          StrokeThickness = strokeWidth,
                                      };
            yield return horizontalLine2;

            var verticalLine = new Line
                                   {
                                       IsHitTestVisible = false,
                                       Stroke = brush,
                                       X1 = margin - (strokeWidth / 2),
                                       X2 = margin - (strokeWidth / 2),
                                       Y1 = 0,
                                       Y2 = max,
                                       StrokeThickness = strokeWidth,
                                   };
            yield return verticalLine;

            var horizontalBottomLine = new Line
                                           {
                                               IsHitTestVisible = false,
                                               Stroke = brush,
                                               X1 = 0,
                                               X2 = max,
                                               Y1 = height - 130 + (strokeWidth/2),
                                               Y2 = height - 130 + (strokeWidth/2),
                                               StrokeThickness = strokeWidth,
                                           };
            _shapes.Add(horizontalBottomLine);
            var horizontalBottomLine2 = new Line
                                            {
                                                IsHitTestVisible = false,
                                                Stroke = brush,
                                                X1 = 0,
                                                X2 = max,
                                                Y1 = height - 50 + (strokeWidth/2),
                                                Y2 = height - 50 + (strokeWidth/2),
                                                StrokeThickness = strokeWidth,
                                            };
            _shapes.Add(horizontalBottomLine2);
            yield return horizontalBottomLine2;

            const int tileHeight = 20;

            for (int x = margin; x < /*width*/ max; x += (tileHeight*2))
            {
                for (int y = 140; y < /*height*/ max; y += (tileHeight*2))
                {
                    var rect = new Rectangle
                                   {
                                       Width = tileHeight,
                                       Height = tileHeight,
                                       VerticalAlignment = VerticalAlignment.Top,
                                       HorizontalAlignment = HorizontalAlignment.Left,
                                       Margin = new Thickness(x, y, 0, 0),
                                       IsHitTestVisible = false,
                                       Fill = brush,
                                   };
                    yield return rect;
                }
            }
        }
    }
}