Category Archives: UWP

Everything about the UWP ParallaxView Control

In this article we dive into the UWP ParallaxView control, an important player in Fluent Design that allows you to create a feeling of depth, perspective, and movement in your layered UI.

I created a small UWP app to demonstrate

  • defining a vertical parallax effect,
  • defining a horizontal parallax effect,
  • fine-tuning the animations, and
  • declaratively and programmatically adapting the UI to the Windows release.

I’m not going to spend too much time in introductions, but if you insist: there’s this great article on docs.microsoft.com. It also hosts this picture that says it all:

parallax_v2

To achieve  a parallax effect, all you need is

  • a (faster) scrolling foreground: any element with a ScrollViewer will do,
  • a (slower) scrolling background: any UIElement, but typically an image, and
  • a ParallaxView control to glue these together.

The ParallaxView control adjusts the size of the background to always remain in view, and registers a Composition Animation that moves the background when you scroll through the foreground element.

Vertical parallax

Here’s the canonical ParallaxView setup:

  • it’s wrapped around the background Image,
  • its Source property refers to the ListView in the foreground, and
  • its VerticalShift property defines the range in pixels (and the axis) of the parallax motion:
<ParallaxView Source="{x:Bind ForegroundElement}"
                VerticalShift="100">

    <!-- Background element -->
    <Image x:Name="BackgroundImage"
            Source="ms-appx:///Assets/cyberpunk.jpg"
            Stretch="UniformToFill" />
</ParallaxView>

<!-- Foreground element -->
<ListView x:Name="ForegroundElement"
            ScrollViewer.VerticalScrollBarVisibility="auto">
    <!-- ListView style and content ... -->
</ListView>

Here’s how this looks like in the sample app:

VerticalParallax

This page uses a double parallax effect: the white text in the center is animated too. I used a smaller VerticalShift value so it appears to dangle between the foreground and the background:

<ParallaxView Source="{x:Bind ForegroundElement}"
                VerticalShift="50">
    <TextBlock Text="Bladerunner 2049" />
</ParallaxView>

This is just to illustrate that the background element does not need to be an image, and that multiple ParallaxView instances can be tied to the same source.

Horizontal Parallax

If you have a horizontally scrolling app –such as the Weather app- then you can also achieve a parallax effect, just set the HorizontalShift property. Here’s three controls simulating the sea:

<ParallaxView Source="{x:Bind ForegroundElement}"
                HorizontalShift="33"
                Margin="0 0 -33 180">
    <Image Source="ms-appx:///Assets/waves.png"
            Stretch="UniformToFill"
            Height="200"
            VerticalAlignment="Bottom" />
</ParallaxView>

<ParallaxView Source="{x:Bind ForegroundElement}"
                HorizontalShift="66"
                Margin="-66 0 0 100">
    <Image Source="ms-appx:///Assets/waves.png"
            Stretch="UniformToFill"
            Height="200"
            VerticalAlignment="Bottom" />
</ParallaxView>

<ParallaxView Source="{x:Bind ForegroundElement}"
                HorizontalShift="100">
    <Image x:Name="BackgroundImage"
            Source="ms-appx:///Assets/waves.png"
            Stretch="UniformToFill"
            Height="200"
            VerticalAlignment="Bottom" />
</ParallaxView>

Here’s how this looks like in the sample app:

HorizontalParallax

By the way: this is a nice use case for playing with negative shift values. Feel free to install the sample app and give it a try…

Fine-tuning the shift animations

In most cases it suffices to setting the vertical or horizontal shift to create a decent parallax effect. In other cases you may want to adjust the animations to achieve pixel-perfectness or realistic behavior. The sample app comes with a configuration page where you can test the other relevant properties of the ParallaxView control: VerticalSourceStartOffset, VerticalSourceEndOffset, VerticalSourceOffsetKind, MaxVerticalShiftRatio, and IsVerticalShiftClamped. For the sake of completeness: all of these have also a a Horizontal counterpart.

This is how the configuration page looks like:

ConfigurationPage

Sometimes it’s hard to see the impact of changing one of the parameters. This is especially the case when the background image automatically resizes itself (e.g. when it’s Stretched to Uniform or UniformToFill, which is … well… always).

For the edge cases I created an alternative background with a non-stretched ruler from 0 to 100. To enable is, just switch the comments in the configuration view:

<ParallaxView x:Name="Parallax"
                Source="{x:Bind ForegroundElement}">
    <Image x:Name="BackgroundImage"
            Source="ms-appx:///Assets/mountains.jpg"
            Stretch="UniformToFill"
            HorizontalAlignment="Center" />
    <!--<Image x:Name="BackgroundImage"
            Source="ms-appx:///Assets/ruler.jpg"
            Stretch="None" />-->
</ParallaxView>

The page looks less sexy like this, but it’s a lot more useful. Here’s a standard vertical parallax with a VerticalShift of 200 pixels:

ConfigurationDetails_1

In this configuration, you lose part of the background. The start and the end of the ruler (the 0 and 100 marker) are off-screen and only become visible when scrolling by touch – because of the built-in inertia animations. If you’re using a mouse, these parts of the background will never show.

Fortunately, with VerticalSourceStartOffset and VerticalSourceEndOffset and their horizontal counterparts, you can move the start and the end position of the background element. When we move the vertical source start offset to 100 pixels, the zero marker appears on top:

ConfigurationDetails_2

Likewise, setting the vertical source end offset to –100 reveals the 100 marker when you scroll to the bottom of the foreground (note: that was using Stretch.Uniform on the background):

ConfigurationDetails_3

Please observe that this behavior of the ParallaxView is only a side effect (pun intended Smile). These properties actually specify the vertical scroll offset at which parallax motion starts and ends. This would allow you to do small adjustments in the foreground element without starting an animation on the background – I assume.

Unfortunately the settings only have an effect against a background image that does not stretch (i.e. almost never) and only when you start scrolling from the top or the bottom.

Here’s how this looks like in practice – there’s a small delay in the background animation:

VerticalSourceStartOffset

Use MaxVerticalShiftRatio (with a range from 0 to 1) to limit the background scrolling speed. If you set it to 0.2 in the sample app and scroll down, you’ll see that you can’t reach the end of the ruler anymore:

ConfigurationDetails_4

I assume that the IsVerticalShiftClamped property switches the vertical shift on and off, but I see no effect in the sample app.

The VerticalSourceOffsetKind is even more mysterious. The documentation states that it can be Absolute or Relative, and that’s it. I can’t see the logic in the state changes – yet. I do observe some unexpected shifts from time to time, like this:

ConfigurationDetails_5

We want more

If you want more control over the parallax effect than what’s provided by the ParallaxView, then you have to roll the animations yourself. Here are two fine examples:

Targeting pre-FCU versions

The ParallaxView is an easy way to get some of that Fluent Design into your app. It was introduced with the Fall Creators Update (a.k.a. FCU, or Build 16299), and your apps may be targeting earlier releases. Don’t worry: it’s easy to make the ParallaxView an optional component in your UI. With the same code base, you can present  a static background image for the users on an earlier release, and use the parallax effect for the ones on a newer release.

Let me prove that to you. The Conditional XAML page in the sample app is divided in three zones:

  • on the left is the canonical implementation that requires FCU,
  • the image in the middle uses declarative conditional XAML, while
  • the right hand part uses programmatic conditional XAML.

Here’s how it looks like at run-time:

ConditionalPage

Declarative conditional XAML

If you’re targeting Creators Update (Build 15063) or higher, then you can use Conditional XAML –a markup extension on top of IsApiContractPresent -to configure the UI based on the release.

Here’s how to use it. First declare the conditional XAML namespaces to see whether or not you’re running on Fall Creators Update (that’s UniversalApiContract 5) or higher:

xmlns:PriorToFcu="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractNotPresent(Windows.Foundation.UniversalApiContract,5)"
xmlns:FcuOrHigher="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract,5)"

Now you can create conditional elements in your XAML, like this:

<!-- Declarative conditional XAML expressions. -->
<FcuOrHigher:ParallaxView Source="{x:Bind ForegroundElement}"
                            VerticalShift="100">
    <Image Source="ms-appx:///Assets/beach.jpg" />
</FcuOrHigher:ParallaxView>
<PriorToFcu:Image Source="ms-appx:///Assets/beach.jpg" />

These will be evaluated at run-time to spawn the appropriate XAML.

Programmatic conditional XAML

Alternatively you can call the primitives on which the markup extension is built. I’m not sure it’s a good idea to call IsApiContractPresent all over the place, so I created this nice helper class –with room for extension- in a MVVM Versioning service. It allows me to evaluate Sdk.SupportsParallaxView:

public static class Sdk
{
    public static bool SupportsParallaxView
    {
        get
        {
            return ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 5);
        }
    }
}

For the XAML part, just draw the image. Don’t forget to give it a Name:

<!-- Programmatic conditional XAML expressions. -->
<Image x:Name="BeachImage"
        Source="ms-appx:///Assets/beach.jpg" />

The Grid that hosts the elements should also get a name – I called it ContentGrid. Here’s the code that detects the support for ParallaxView and modifies the XAML programmatically. It executes in the Loaded event, when the Visual Tree was populated and is ready for interaction:

private void ConditionalPage_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
    if (Sdk.SupportsParallaxView)
    {
        // Insert ParallaxView.
        var parallax = new ParallaxView();
        parallax.Source = ForegroundElement;
        parallax.VerticalShift = 100;
        Grid.SetColumn(parallax, 2);
        ContentGrid.Children.Remove(BeachImage);
        parallax.Child = BeachImage;
        ContentGrid.Children.Insert(0, parallax);
    }
}

I definitely prefer the programmatic approach here, because

  • I can adapt the XAML not only based on the Windows Release, but also on hardware specifications, or on user preferences, and
  • it comes with decent XAML Designer support.

This is how the page looks at design time. All conditional XAML elements are simply ignored:

XamlDesigner

Call to action

You see: nothing prevents you from using ParallaxView in your apps to bring in some Fluent Design. Just make sure you don’t exaggerate…

The code

The ParallaxView sample app lives here on GitHub.

Enjoy!

Advertisements

An Extended Splash Screen with Lottie Animations in UWP

In this article we demonstrate how to use Lottie animations in the extended splash screen of a UWP application. A Lottie animation is a programmable animated graphic that can be rendered into your XAML.

Here’s how the companion sample app starts up, with its splash screen transitioning into an look-alike page that displays an animation, whilst executing some longer-running code:

AppStart

Creating an extended splash screen

Sometimes an app needs to execute some longer-running code on startup. Especially the very first time after an install or an upgrade, you may want to connect to the backend, create a user profile, populate a local SQLite database, and defeat the Klingons, the Sith and/or the Daleks.

The long-running code in my sample app is less ambitious:

await Task.Delay(10000);

It is common to handle this scenario with a so-called Extended Splash Screen. This is a page that looks like the native splash screen and that executes the longer-running code, before eventually navigating to the main page. Typically an extended splash screen is decorated with a progress ring to indicate that the app does not hang.

The nice official documentation for creating an extended the splash screen is right here. I started with a copy of the sample code from there, and replaced the progress ring by a Lottie animation.

In a nutshell, here’s the routine to create an extended splash screen:

  • get the position of the SplashScreen image from the LaunchActivatedEventArgs,
  • navigate to an extended splash screen page that displays the same image at the same location,
  • execute the long running code in the Dismissed event handler of the original splash screen, and finally
  • navigate to the ‘real’ homepage or shell.

Adding Lottie capabilities

Lottie is a library to render animations. It uses JSON files that were generated by the Bodymovin extension of Adobe After Effects, a Special Effects editor to create picture and SVG animations. Lottie has implementations for iOS, Android, and the Web (React Native). It is supported by a broad community and has won a number of awards as design and development tool. It seems fair to assume that Lottie is becoming one of the standards for stand-alone animations in apps.

For Native Windows developers, Lottie is now available as LottieUWP, a NuGet package written by Alexandre Chohfi. To look it up from Visual Studio, you need to check the ‘Include prerelease’ box in NuGet Package Manager:

LottieUWP_NuGet

Adding Lottie files

LottieFiles is a great resource to get some free JSON files to experiment with:

LottieFiles

That’s where I found the beer bubbles animation.

Add the downloaded JSON file(s) to your project, and don’t forget to change their Build Action to Content:

Json_Build_Action

Displaying Lottie animations

The best way to get some insight into LottieUWP and its API is viewing this #ifdef episode on Channel 9. For the sample app, I just added a LottieAnimationView in the extended splash screen, with an auto-played, infinite-looping animation, nicely positioned over the beer glass background:


That’s all that’s needed to host and run the animation. I just modified the Speed – programmatically, since assigning a value declaratively in XAML is not very well supported in the current LottieUWP version (after all it *is* a pre-release):

// Adjust the speed of the Lottie animation.
SplashScreenAnimation.Speed = 3;

The end-user may resize the window or rotate his device when the app is starting. So when the background image is repositioned we also have to update the size and location of the LottieAnimationView:

// Position the extended splash screen image in the same location as the system splash screen image.
private void PositionImage()
{
    extendedSplashImage.SetValue(Canvas.LeftProperty, splashImageRect.X);
    extendedSplashImage.SetValue(Canvas.TopProperty, splashImageRect.Y);
    extendedSplashImage.Height = splashImageRect.Height;
    extendedSplashImage.Width = splashImageRect.Width;

    // Position the Lottie animation.
    var factor = splashImageRect.Width / 620;
    SplashScreenAnimation.SetValue(Canvas.LeftProperty, splashImageRect.X + 100 * factor);
    SplashScreenAnimation.SetValue(Canvas.TopProperty, splashImageRect.Y + 150 * factor);
    SplashScreenAnimation.Width = 180 * factor;
}

Tweaking the JSON files

Visual Studio allows you to unminify the JSON file, this will reveal a structure of layers with the strokes and shapes and their use in animations and transformations. I assume that it’s unlikely that we’re going to apply changes manually in there. Nevertheless there are some ways to slightly tweak the files.

In LottieFile’s preview page you can visualize the selected JSON against different background colors. This helps you to reveal the color scheme that is used in the animation. Here you can see that the filter animation uses plain white to fill the circles – so they’re not transparent:

LottiePreview

The button in the top right corner launches the Lottie Editor:

LottieEditor

This page allows you to change the color of some elements. The corresponding changes to the JSON files are logged in the browser’s Console.

Other use cases

The main page of the sample app shows how to decorate a button with a (more or less) subtle animation to draw the user’s attention. This is how it looks like:

AppMain

Please note that the animated GIF on this page loops infinitely, unlike the animation in the UWP app.

Again, we used a LottieAnimationView, but we set the RepeatCount to 2 and the RepeatMode to Reverse to obtain a brief symmetric animation:


And again, we adjusted the speed programmatically:

// Adjust the speed of the animation.
// Does not work declaratively for now.
MainpageAnimation.Speed = 3F;

Use PlayAnimation to (re)play the Lottie animation:

// Replay the animation.
MainpageAnimation.PlayAnimation();

I just added this call to verify whether the button is still clickable when the animation is running on top of it. Fortunately this is the case.

if you want see more Lottie API examples, please check Corrado’s blog post on the subject.

GitHub Repo N° 50

The sample app lives here on GitHub in my 50th public repo.

Enjoy!

Creating human-friendly texts on UWP with Humanizer

This article highlights some of the many features of the Humanizer for .NET project which also runs in UWP. It’s a project from the .NET Foundation that comes with a lot of helper functions for generating human-readable strings from … well … less human-readable expressions, for multiple cultures. Here’s an overview of the functionality:

  • Humanize and dehumanize strings
  • Truncate strings
  • Format strings
  • Humanize and dehumanize enumerations
  • Humanize dates, times, and time spans
  • Pluralize and singularize
  • Transforming numbers to words
  • Transforming numbers to ordinal words
  • Transforming to and from Roman numerals
  • … and more

I used many features of this package in many apps in several .NET technologies (console apps, WPF, and WCF). I’m a huge fan of the relative date and time functions, because after all:

Your 3 books will be delivered in 10 minutes.” sounds a lot better than ‘”Item: book; Quantity:3; ETA 2018-06-18T13:45:30”.

This extremely useful functionality is available as source on GitHub and as a NuGet package. I created a small app to test the package in UWP.

All you need to do is include the namespace:

using Humanizer;

Then you can call the many functions in the package. Most of these are implemented as extension methods. Here’s an overview of some expressions and their result:

“Can_return_title_Case”.Humanize(LetterCasing.Title) Can Return Title Case
“Pascal case input string is turned into sentence”.Dehumanize() PascalCaseInputStringIsTurnedIntoSentence
“Long text to truncate”.Truncate(10) Long text…
DateTime.UtcNow.AddHours(-30).Humanize() yesterday
TimeSpan.FromMilliseconds(1299630020).Humanize(3, collectionSeparator: null) 2 weeks, 1 day, and 1 hour
“Man”.Pluralize() Men
“process”.ToQuantity(2) 2 processes
“dollar”.ToQuantity(2, “C2”, new CultureInfo(“en-US”)) $2.00 dollars
5.Ordinalize() 5th
3501.ToWords() three thousand five hundred and one
21.ToOrdinalWords() twenty-first
“MMXVIII”.FromRoman().ToString() 2018

Seeing is believing, so here’s how these calls look like in the sample UWP app:

Humanizer_HomePage

The main page of the sample app allows you to set a time using Dean Chalk’s radial UWP TimePicker control. It then displays the selected time, and its Humanized value:

Humanizer_MainPage

I’m not diving further into Humanizer’s features and code here, since it is well documented. My UWP sample app lives here on GitHub.

Enjoy!

App tile pinning in UWP

In this article we walk through the different APIs for pinning and unpinning a UWP app to different destinations, and show how to bundle these calls into a single AppTile class that provides a ‘pinning service’ including:

  • pinning to the taskbar,
  • pinning to the start menu, and
  • enumerating, pinning and unpinning secondary tiles.
public class AppTile
{
    // ...
}

We also describe the impact of pinned tiles to the application launch process and how to debug your app in this scenario.

This article comes with a sample app on GitHub that looks like this:

ScreenShot

The AppTile class or service makes it easier to use the down-to-earth API’s in UWP apps that use MVVM and data binding. Here’re the class diagram. I’m assuming that its member names are sufficiently self-explanatory:

AppTileClass

Pinning to the taskbar

Users can manually pin your app to the taskbar, but you can also friendly hint this from your app and then pin programmatically. All the details for this are nicely explained in the official documentation, so allow me to stay brief on the details.

Service API

Not every device that runs your app comes with a recent OS and/or a taskbar. Before calling pinning features, you have to ensure that there is a Windows TaskBarManager (via ApiInformation.IsTypePresent) and that the taskbar itself is present and accessible (through IsPinningAllowed):

public static bool IsPinToTaskBarEnabled 
	=> ApiInformation.IsTypePresent("Windows.UI.Shell.TaskbarManager") 
	   && TaskbarManager.GetDefault().IsPinningAllowed;

When you programmatically pin your app to the taskbar, a dialog will pop up to ask for the user’s consent. To avoid an embarrassing experience, it makes sense to first discover whether the app is already pinned. This is done with a call to IsCurrentAppPinnedAsync():

public async static Task<bool?> IsPinnedToTaskBar()
{
    if (IsPinToTaskBarEnabled)
    {
        return await TaskbarManager.GetDefault().IsCurrentAppPinnedAsync();
    }
    else
    {
        return null;
    }
}

Eventually a call to RequestPinCurrentAppAsync() will launch the pinning process:

public static async Task<bool?> RequestPinToTaskBar()
{
    if (IsPinToTaskBarEnabled)
    {
        return await TaskbarManager.GetDefault().RequestPinCurrentAppAsync();
    }
    else
    {
        return null;
    }
}

Usage

The AppTile API is designed for easy use in any UWP app, but maybe the IsPinnedToTaskBar() method will pose a challenge. I can imagine that you may want to access this asynchronous member as a property or from inside a synchronous method (e.g. in data binding). I did not code a synchronous version inside the AppTile class, since it feels like an anti-pattern. There are more than enough asynchronous methods in a page or control’s life cycle, so you should use these to do calls that are asynchronous by nature.

Nevertheless, with Task.Run<T> you could easily create a synchronous wrapper that executes on the UI thread (a requirement for the call). Here’s the corresponding code snippet from the main page of the sample app:

var isPinned = Task.Run<bool?>(() => AppTile.IsPinnedToTaskBar()).Result;

Using this wrapper, the hosting UI element can define bindable properties and commands:

private bool PinToTaskBar_CanExecute()
{
    var isPinned = Task.Run<bool?>(() => AppTile.IsPinnedToTaskBar()).Result;
    return !isPinned ?? false;
}

private async void PinToTaskBar_Executed()
{
    await AppTile.RequestPinToTaskBar();
}

Here are the XAML snippets for status field and command button:

<TextBlock Text="{x:Bind IsPinnedToTaskBar()}" />

<AppBarButton Icon="Pin"
              Label="Pin to Task Bar"
              IsCompact="False"
              Command="{x:Bind PinToTaskBarCommand }" />

Here’s how the system dialog to get the user’s consent looks like:

PinToTaskbar_Dialog

A couple of years ago, Windows 8.* came with different icons for ‘Pin to Start’ and ‘Pin to Taskbar’ using pins that pointed in the appropriate direction:

Windows8_Experience

Windows 10 uses the same horizontal pin icon for both, and a diagonal one for unpinning. Inside your own app you may choose other icons of course. The Symbol Enum has a Pin and an UnPin icon.

Pinning to the start menu

It should not come as a surprise that the Start Menu Pinning API is similar to the Taskbar Pinning API. All documentation is here. Again, we made a wrapper to detect whether the service is enabled. It uses ApiInformation.IsTypePresent, and checks whether your app is allowed through SupportsAppListentry in the Windows StartScreenManager. To verify if your app is allowed you need to look up its main tile as an AppListEntry from GetAppListEntriesAsync:

public static bool IsPinToStartMenuEnabled
{
    get
    {
        if (ApiInformation.IsTypePresent("Windows.UI.StartScreen.StartScreenManager"))
        {
            return Task.Run<bool>(() => IsPinToStartMenuSupported()).Result;
        }

        return false;
    }
}

private static async Task<bool> IsPinToStartMenuSupported()
{
    AppListEntry entry = (await Package.Current.GetAppListEntriesAsync())[0];
    return StartScreenManager.GetDefault().SupportsAppListEntry(entry);
}

To detect whether you main tile is already pinned to the start menu, you have to look up the app list entry again from your Package [note to self: there’s room for a helper method in the AppTile class] and then ask it to the StartScreenManager with ContainsAppListEntryAsync:

public static async Task<bool?> IsPinnedToStartMenu()
{
    if (IsPinToStartMenuEnabled)
    {
        AppListEntry entry = (await Package.Current.GetAppListEntriesAsync())[0];
        return await StartScreenManager.GetDefault().ContainsAppListEntryAsync(entry);
    }
    else
    {
        return null;
    }
}

The request to programmatically pin is done through RequestAddAppListEntryAsync():

public static async Task<bool?> RequestPinToStartMenu()
{
    if (IsPinToStartMenuEnabled)
    {
        AppListEntry entry = (await Package.Current.GetAppListEntriesAsync())[0];
        return await StartScreenManager.GetDefault().RequestAddAppListEntryAsync(entry);
    }
    else
    {
        return null;
    }
}

Here’s the corresponding system dialog:

PinToStart_Dialog

Observe the complete difference in style with the taskbar system dialog…

A word (or four) about unpinning

By default, all developer’s pinned tiles are automatically unpinned when you compile the app after a source code change. I didn’t find a switch to alter this behavior.

Programmatically unpinning from start menu or taskbar is not included in the official API’s.

You-Shall-Not-Unpin

Secondary tiles

A secondary tile allows your users not only to startup the app, but also to directly navigate to a specific page or specific content. All the official info is right here.

Pinning secondary tiles

When you pin a secondary tile, the app (or the user) needs to give it a name. The name of the secondary tile serves as an identifier for the specific page or content that it is deep-linked to. In most cases you can grab this from the current context, the sample app just asks the user for it:

SecondaryTileNameDialog

There are some restrictions in the string identifier for a secondary tile: there’s a maximum length of 2048 (that’’s still long enough to hold a simple serialized object) and it doesn’t like some characters, like spaces or exclamation marks. The AppTile service comes with a method to clean this up:

private static string SanitizedTileName(string tileName)
{
    // TODO: complete if necessary...
    return tileName.Replace(" ", "_").Replace("!","");
}

The API for pinning secondary tiles is available in all Windows 10 versions and is enabled on all devices, so there’s no call required to check if it’s enabled. Before pinning a secondary tile, you should verify whether it exists already with SecondaryTile.Exists, and then you call one of the constructors of SecondaryTile. If you want the tile name to be displayed with ShowNameOnSquare150x150Logo (which is a horrible property name), then you have to make sure to provide a tile image that comes with free space at the bottom. Fortunately the SecondaryTile class can deal with this – you can even use a different image for each secondary tile. Actually there is a lot more that you can do with secondary tiles, but I’m just focusing on the pinning part here. With RequestCreateAsync the tile is created:

public async static Task<bool> RequestPinSecondaryTile(string tileName)
{
    if (!SecondaryTile.Exists(tileName))
    {
        SecondaryTile tile = new SecondaryTile(
            SanitizedTileName(tileName),
            tileName,
            tileName,
            new Uri("ms-appx:///Assets/Square150x150SecondaryLogo.png"),
            TileSize.Default);
        tile.VisualElements.ShowNameOnSquare150x150Logo = true;
        return await tile.RequestCreateAsync();
    }

    return true; // Tile existed already.
}

Here’s the corresponding system dialog to get the user’s consent:

Pin_SecondaryTile_Dialog

Here’s a screenshot from a start screen with the main tile and some secondary tiles from the sample app:

StartMenu

This is the code from the main page, it uses the Dialog Service:

private async void PinSecondaryTile_Executed()
{
    var tileName = await ModalView.InputStringDialogAsync("Pin a new tile.", "Please enter a name for the new secondary tile.", "Go ahead.", "Oops, I changed my mind.");
    if (!string.IsNullOrEmpty(tileName))
    {
        await AppTile.RequestPinSecondaryTile(tileName);
    }
}

Enumerating secondary tiles

The FindAllAsync static method on SecondaryTile returns all secondary tile instances for your app, so you could use it to detect if there are any:

public async static Task<bool> HasSecondaryTiles()
{
    var tiles = await SecondaryTile.FindAllAsync();
    return tiles.Count > 0;
}

or to enumerate their identities:

public async static Task<List<string>> SecondaryTilesIds()
{
    var tiles = await SecondaryTile.FindAllAsync();
    var result = new List<string>();
    foreach (var tile in tiles)
    {
        if (!string.IsNullOrEmpty(tile.TileId))
        {
            result.Add(tile.TileId);
        }
    }

    return result;
}

Here’s the sample app displaying the list of secondary tiles:

SecondaryTiles_Enum

Unpinning secondary tiles

With RequestDeleteAsync you can unpin a secondary tile. You have to provide its identity:


public async static Task<bool> RequestUnPinSecondaryTile(string tileName)
{
    if (SecondaryTile.Exists(tileName))
    {
        return await new SecondaryTile(tileName).RequestDeleteAsync();
    }

    return true; // Tile did not exist.
}

Unpinning does not require the user’s consent, so there’s no dialog involved.

Launching the App from a pinned tile

When the user clicks a pinned tile, your app is launched. If the launch came from a secondary tile, then its identity is reflected in the startup arguments.

UWP does not support running multiple instances of the same app. This means that when the user clicks a tile, the OnLaunched of the running instance of the app may be called. You have to prepare for that – I had to change my ActivationService for this:

  • When the app was already running (ApplicationExecutionState.Running) and there are no startup arguments (main tile or taskbar) then we may simply ignore the call.
  • If there are startup arguments then the launch was done through a secondary tile. In that case, we navigate to the tile-specific content. In the sample app, this means navigating to the Home page.

Here’s the code for this scenario:

public async Task LaunchAsync(LaunchActivatedEventArgs e)
{
    if (e.PreviousExecutionState == ApplicationExecutionState.Running)
    {
        if (string.IsNullOrEmpty(e.Arguments))
        {
            // Launch from main tile, when app was already running.
            return;
        }

        // Launch from secondary tile, when app was already running.
        Navigation.Navigate(typeof(HomePage), e.Arguments);
        return;
    }

    // Default Launch.
    await DefaultLaunchAsync(e);
}

When the app was not running during the launch, we do the standard initializations, and afterwards navigate to the tile-specific content if necessary. Notice that the Navigation Service passes the startup arguments to the target page:

private async Task DefaultLaunchAsync(LaunchActivatedEventArgs e)
{
    // Custom pre-launch service calls.
    await PreLaunchAsync(e);

    // Navigate to shell.
    Window.Current.EnsureRootFrame().NavigateIfAppropriate(typeof(Shell), e.Arguments).Activate();

    // Custom post-launch service calls.
    await PostLaunchAsync(e);

    // Navigate to details.
    if (!string.IsNullOrEmpty(e.Arguments))
    {
        Navigation.Navigate(typeof(HomePage), e.Arguments);
    }
}

The target page gets the startup arguments in its OnNavigatedTo handler and can act on it. The sample app just stores the tile name in a field:

private string navigationParameter = string.Empty;

public string NavigationParameter => navigationParameter;

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    if ((e != null) && (e.Parameter != null))
    {
        navigationParameter = e.Parameter.ToString();
    }

    base.OnNavigatedTo(e);
}

A text block is bound to the value of that parameter:

<Run Text="{x:Bind NavigationParameter}" />

Here’s how this looks like at runtime:

LaunchFromSecondaryTile

Debugging launch from a tile

To debug an app-launch from a tile, go to Debug/Other Debug/Targets/Debug Installed Package:

DebugSecondaryTileMenu

Select your app from the list, check the do-not-launch-but-debug-when-it-starts box, and press the start button:

 DebugSecondaryTile

When you click on one the pinned tiles, you’ll see your breakpoints getting hit:

DebugSecondaryTileBreakpoint

Code

That’s it! The AppTile services and the sample app live here on GitHub.

Enjoy!

A Fluent Button Flyout for UWP

In this article we describe how to build an elegantly designed and animated fluent ToggleButton-Popup combination for use in UWP apps as an alternative for the less fluent Button Flyout. The code is not mine, I merely reused code and components from the Continuity framework by Justin Liu. This frameworks contains a lot of helpers for implementing Fluent Design in your apps without needing Windows 10 Fall Creators Update.

The ToggleButton-Popup combo is an excellent widget to display extra information such as a help text.

Here’s how all of this may look like (styling is up to you of course). It starts with a stand-alone round ‘more’ button, with hover animations. When pressed, the button rotates toward the opening flyout, while changing its shape to look like a ‘close’ button that becomes connected to the content that was just revealed. In the mean time, the flyout itself opens with a scale animation as if it grew out of the button:

FluentFlyoutButton

Closing the button and dismissing the flyout come with reverse animations.

I’ve been looking for ways to animate opening and closing Flyout or ContentDialog instances. I went through many of the XAML animations techniques, but could not find a way. Flyout and ContentDialog don’t come with Visual States, so Visual Transitions are not an option. Although its name seems promising, PopInThemeAnimation is not applicable. And if it were, it doesn’t come with a scale animation (only opacity and translation).

I almost gave up, and tried to to accept that flyouts would always open and close like this:

DefaultFlyoutButton

Frankly, I don’t like the animations. But what’s worse: you can not even see which of the buttons was actually pressed…

Then I came across this sample Kliva design with exactly the user experience I was looking for:

ContinuityPanel

I decided to copy the relevant code into my own solution under Features/Continuity to get some Fluent-As-A-Service:

ContinuityClasses

The Kliva demo is not using a Button with its Flyout, but a ToggleButton with ‘just’ a Grid. My only mission was to replace the Grid with a Popup. After a few iterations, I came up with the following setup, which even allows the Popup to have IsLightDismissEnabled on.:

  • A toggle button with storyboarded animations is placed in a container
  • A Popup is placed next to it with
  • The content of the Popup (not the Popup itself) is given implicit Show and Hide Composition API animations.

Here’s the corresponding XAML definition:

<!-- Toggle Button -->
<continuity:CircularToggleButton x:Name="TheToggle"
                                    CheckedBackground="{StaticResource HighlightBrush}"
                                    CheckedCornerRadius="6 0 0 6"
                                    FontFamily="Segoe UI">
    <continuity:CircularToggleButton.CheckedContent>
        <ContentControl Margin="3"
                        Style="{StaticResource IconCloseStyle}" />
    </continuity:CircularToggleButton.CheckedContent>
    <ContentControl Style="{StaticResource IconMoreStyle}" />
</continuity:CircularToggleButton>
<!-- 'Flyout' -->
<Popup x:Name="ThePopup"
        IsOpen="{Binding IsChecked, ElementName=TheToggle, Mode=TwoWay}"
        IsLightDismissEnabled="False"
        HorizontalOffset="{Binding ActualWidth, ElementName=TheToggle}"
        VerticalOffset="-20">
    <Grid x:Name="TheGrid"
            Visibility="{Binding IsOpen, ElementName=ThePopup}">
        <!-- Content -->
    </Grid>
</Popup>

That’s it! Let’s dive into some details.

An animated circular toggle button

The CircularToggleButton adds a few dependency properties to ToggleButton, like content, background color and corner radius for the different states:

public sealed class CircularToggleButton : ToggleButton
{
    public static readonly DependencyProperty CheckedContentProperty =
        DependencyProperty.Register(
            "CheckedContent",
            typeof(object),
            typeof(CircularToggleButton),
            new PropertyMetadata(null));

    public object CheckedContent
    {
        get => GetValue(CheckedContentProperty);
        set => SetValue(CheckedContentProperty, value);
    }

    // ..
}

It also comes with a circular custom style and some nice visual effects and animations.

Here’s how the PointerOver VisualState pumps up the size of the content using a RenderTransform with a CompositeTransform on ScaleX and ScaleY:

<VisualState x:Name="PointerOver">
    <VisualState.Setters>
        <Setter Target="CheckedContentPresenter.(UIElement.RenderTransform).(CompositeTransform.ScaleX)"
                Value="1.1" />
        <Setter Target="CheckedContentPresenter.(UIElement.RenderTransform).(CompositeTransform.ScaleY)"
                Value="1.1" />
        <Setter Target="UncheckedContentPresenter.(UIElement.RenderTransform).(CompositeTransform.ScaleX)"
                Value="1.1" />
        <Setter Target="UncheckedContentPresenter.(UIElement.RenderTransform).(CompositeTransform.ScaleY)"
                Value="1.1" />
        <Setter Target="BackgroundVisual.Opacity"
                Value="0.9" />
    </VisualState.Setters>
</VisualState>

Here’s the VisualTransition with the StoryBoard on CornerRadius that turns the round button into its ‘connected’ shape when checked:

<VisualTransition GeneratedDuration="0:0:0.25"
                    To="Checked">
    <Storyboard>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.CornerRadius)"
                                        Storyboard.TargetName="BackgroundVisual">
            <DiscreteObjectKeyFrame KeyTime="0"
                                    Value="{Binding CheckedCornerRadius, RelativeSource={RelativeSource TemplatedParent}}" />
        </ObjectAnimationUsingKeyFrames>
    </Storyboard>
</VisualTransition>

If you want to know more about storyboarded animations, this circular toggle button style definition is a nice tutorial. Storyboarded animations are a way to change a dependency property over time. When there’s a visual impact of this, the animation may or may not require the UI thread. While the SDK’s evolve, more and more of these animations are internally rewritten to run on the composition thread. So there’s no need for you give up readable declarative Storyboards in XAML in favor of dark imperative code against the Composition API. But for the second part of this article, we’ll use the latter…

An animated Popup

The Popup control is a XAML container that allows you to place content on top of other content. You can not animate the Popup itself but fortunately you can animate its content. As promised we’ll use Composition animations for this. These are 60-frames-per-second animations that run independent of the UI thread. They’re a bit harder to write, but there are a lot of helpers available, like these from UWP Community Toolkit.

Here’s the Continuity helper that starts it all:

TheGrid.EnableFluidVisibilityAnimation(
    centerPoint: new Vector3(0.0f, 40.0f, 0.0f), 
    showFromScale: 0.2f, 
    hideToScale: 0.2f, 
    showDuration: 400, 
    hideDuration: 400);

Here’s part of its implementation.

A time based Composition API animation of the type Vector2KeyFrameAnimation is created with the Scale of the Visual as Target:

if (!showFromScale.Equals(1.0f))
{
    showeScaleAnimation = compositor.CreateVector2KeyFrameAnimation();
    showeScaleAnimation.InsertKeyFrame(0.0f, new Vector2(showFromScale));
    showeScaleAnimation.InsertKeyFrame(1.0f, Vector2.One);
    showeScaleAnimation.Duration = TimeSpan.FromMilliseconds(showDuration);
    showeScaleAnimation.DelayTime = TimeSpan.FromMilliseconds(showDelay);
    showeScaleAnimation.Target = "Scale.XY";
}

The different animations (scale, position, opacity, …) are placed together in an AnimationGroup (one for hide and one for show):

var showAnimationGroup = compositor.CreateAnimationGroup();
// ...
if (showeScaleAnimation != null)
{
    showAnimationGroup.Add(showeScaleAnimation);
}

These animation groups are then implicitly hooked to the Popup’s content, using SetImplicitShowAnimation and SetImplicitHideAnimation:

ElementCompositionPreview.SetImplicitShowAnimation(element, showAnimationGroup);

Under the hood, a lot of different animation techniques were used to create this user experience, but I love the result! And while it’s probably possible to forge this into a single custom control, I’m not sure if it would add much value….

The code

The ‘fluent button flyout’ sample lives here on Github, the inspiring Continuity by Justin Liu is right here.

Enjoy!

Milestone User Prompts in UWP

In this article we describe how to put the logic and the UI in a UWP application to execute some code and display a dialog on important milestones in its lifetime. We provide an implementation for the following milestones:

  • the application was run for the first time,
  • the application updated to a new release,
  • a trial version was upgraded to a purchase,
  • it’s time to rate and review.

Here’s one of the dialogs in action, in a sample application:

FirstUseDialog

The architecture of the solution comes with one helper service and one content dialog for each milestone, and one central activation Service to rule them all. Exactly the same constituents are found in a Windows Template Studio based project (in Basic MVVM and Code Behind style projects). The logic to detect whether or not a milestone is hit, is powered by helper classes from UWP Community Toolkit v2.1.

Milestone Prompts in Windows Template Studio

Service and Dialogs

The requirement for ‘First Run Prompt’ and ‘What’s New Prompt’ dialogs is often only identified when your application is almost ready to be shipped. If you created your project with Windows Template Studio that’s not a problem. Template Studio allows you to add features to your generated solution as an afterthought:

TemplateStudio

After you selected the feature(s) to be added, there’s even an overview of all the changes that come with them so you can bail out when there’s an unexpected modification of your existing code:

TemplateStudioCode

Here’s a screenshot of the dialog from the  ‘First Run Prompt’ feature. All you need to do is replace its content of with your own:

TemplateStudioDialog

The logic to open these dialogs is implemented around a central Activation Service. This service brings your application startup code –which is usually hidden in app.xaml.cs– conveniently together with the rest of your services code. The UI element for each milestone feature is a ContentDialog. These dialogs are added to the Views section:

TemplateStudioArchitecture

When the application is launched, the activation service navigates to the main page, and then calls StartupAsync:

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

// Tasks after activation
await StartupAsync();

This anchor method is the place where the dialog services hook in their calls:

private async Task StartupAsync()
{
    await WhatsNewDisplayService.ShowIfAppropriateAsync();
    await FirstRunDisplayService.ShowIfAppropriateAsync();
}

Windows Template Studio provides a clean architecture and a straightforward way of introducing new user prompt services and any other service that needs to run on application startup.

Let’s now take a look at the implementation of the logic. Here’s how the What’s New Prompt feature determines whether or not to pop up the dialog:

public class WhatsNewDisplayService
{
    internal static async Task ShowIfAppropriateAsync()
    {
        var currentVersion = PackageVersionToReadableString(Package.Current.Id.Version);

        var lastVersion = await Windows.Storage.ApplicationData.Current.LocalSettings.ReadAsync<string>(nameof(currentVersion));

        if (lastVersion == null)
        {
            await Windows.Storage.ApplicationData.Current.LocalSettings.SaveAsync(nameof(currentVersion), currentVersion);
        }
        else
        {
            if (currentVersion != lastVersion)
            {
                await Windows.Storage.ApplicationData.Current.LocalSettings.SaveAsync(nameof(currentVersion), currentVersion);

                var dialog = new WhatsNewDialog();
                await dialog.ShowAsync();
            }
        }
    }

    private static string PackageVersionToReadableString(PackageVersion packageVersion)
    {
        return $"{packageVersion.Major}.{packageVersion.Minor}.{packageVersion.Build}.{packageVersion.Revision}";
    }
}

It also looks very straightforward, but allow me to show you how this code would look like when using the latest version of UWP Community Toolkit:

if (SystemInformation.IsAppUpdated)
{
    var dialog = new WhatsNewDialog();
    await dialog.ShowAsync();
}

Let’s take a look at some other relevant goodies that this toolkit provides.

Milestone Prompts in UWP Community Toolkit

Logic and Persistency

UWP Community Toolkit is well-known for its controls, its animations and its services. But it also contains a huge amount of helper classes for different scenarios. Notably the SystemInformation and LocalObjectStorageHelper have some members that may help in determining whether or not an application lifetime milestone was reached, based on information that was stored in local settings. Here’s the UML for these two classes:

UwpCommunityToolkitHelpers

Here’s the subset of SystemInformation members that may help to detect milestones:

Property Purpose
ApplicationVersion Gets the application’s version as a PackageVersion
IsFirstRun Gets a value indicating whether the app is being used for the first time since it was installed.
IsAppUpdated Gets a value indicating whether the app is being used for the first time since being upgraded from an older version.
LaunchTime Gets the DateTime (in UTC) that this instance of the app was launched.
LastLaunchTime Gets the DateTime (in UTC) that this was previously launched.
LaunchCount Gets the number of times the app has been launched.
AppUptime Gets the length of time this instance of the app has been running.
FirstVersionInstalled Gets the first version of the app that was installed.
FirstUseTime Gets the DateTime (in UTC) that the app as first used.
Method Description
LaunchStoreForReviewAsync() Launch the store app so the user can leave a review.
TrackAppUse() Track app launch time and count.

And here’s the list for LocalObjectStorageHelper:

Property Purpose
Settings Gets or sets settings container
Method Description
bool KeyExists(string key) Detect if a setting already exists
bool KeyExists(string compositeKey, string key) Detect if a setting already exists in composite.
T Read<T>(string key, T) Retrieve single item by its key.
T Read<T>(string compositeKey, string key, T) Retrieve single item by its key in composite.
void Save<T>(string compositeKey, IDictionary values) Retrieve single item by its key in composite.
Save(String, IDictionary) Save a group of items by its key in a composite.
void Save<T>(string key, T value) Save single item by its key.

These classes will definitely allow you to write the complex milestone scenarios that your application may require.

UWP Community Toolkit provides the helpers to implement the logic and persist the settings for user prompt services and any other service that needs to run on application startup.

Let’s say you want to execute some stuff the first time the application is started after a milestone, but you want to keep on opening the user prompt dialog on startup until the user explicitly opts out via the don’t-show-this-again checkbox. Well, that’s exactly what we’re going to do.

Rolling your own Milestone Prompts

Here’s the structure of my sample application, with a central activation service, and a service-and-dialog pair per milestone (just like in Windows Template Studio):

MySolutionArchitecture

Activation Service

The core member of the Activation Service is LaunchAsync which is called by app.xaml.cs when the application is launched. It allows other services to execute some initialization code, then navigates to the main page (using a nice fluent API that I couldn’t resist writing), and then allows the services to execute the rest of the startup code:

public async Task LaunchAsync(LaunchActivatedEventArgs e)
{
    // Custom pre-launch service calls.
    await PreLaunchAsync(e);

    // Navigate
    Window
      .Current
      .EnsureRootFrame()
      .NavigateIfAppropriate(typeof(Shell), e.Arguments)
      .Activate();

    // Custom post-launch service calls.
    await PostLaunchAsync(e);
}

The PreLaunchAsync() method hosts the initialization code, which is executed before the UI is ready. Use it for things like

  • selecting the culture,
  • setting the theme,
  • starting to log, and
  • determining the page to navigate to.

Here’s how it looks like in the sample application:

private async Task PreLaunchAsync(LaunchActivatedEventArgs e)
{
    Theme.ApplyToContainer(); // await ThemingService.PreLaunchAsync(e);

    await FirstUseActivationService.PreLaunchAsync(e);
    await NewReleaseActivationService.PreLaunchAsync(e);
    await TrialToPurchaseActivationService.PreLaunchAsync(e);
    await RateAndReviewActivationService.PreLaunchAsync(e);
}

The PostLauncAsync() method is the anchor for the startup code that requires the visual elements, like

  • moving around and resizing controls, and
  • opening a Content Dialog.

This is the code from the sample application:

private async Task PostLaunchAsync(LaunchActivatedEventArgs e)
{
    // await ThemingService.PostLaunchAsync(e);
    CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true; 

    await FirstUseActivationService.ShowIfAppropriateAsync(e);
    await NewReleaseActivationService.ShowIfAppropriateAsync(e);
    await TrialToPurchaseActivationService.ShowIfAppropriateAsync(e);
    await RateAndReviewActivationService.ShowIfAppropriateAsync(e);
}

Dialog Services

The milestone dialog services that I present in this article all come with these PreLaunchAsync() and PostLaunchAsync() methods. On top of that, they all have an instance of a LocalObjectStorageHelper to read and write local Settings, and a variable to hold whether or not the user still wants to see the dialog. Last but not least all dialogs have a Reset() and a Deactivate() method:

private const string HasShown = "FirstUseActivation_HasShown";
private static readonly LocalObjectStorageHelper _localSettings = new LocalObjectStorageHelper();

internal static void Reset()
{
    _localSettings.Save(HasShown, false);
}

internal static void Deactivate()
{
    _localSettings.Save(HasShown, true);
}

Each milestone service also comes with a Content Dialog. I added an extra buttons to the dialogs that I copied from Windows Template Studio, since I want to reshow the dialog until the user opts out of it:

DialogDetail

Let’s dive in the details for each milestone.

First Use Prompt Dialog

The SystemInformation helper from UWP Community Toolkit has an IsFirsRun() method to detect whether or not the application is started for the first time. So we’ll call this in our PreLaunchAsync() together with the other initialization code, including a call to Reset() to initialize the dialog logic:

internal static async Task PreLaunchAsync(LaunchActivatedEventArgs e)
{
    if (SystemInformation.IsFirstRun)
    {
        // First-time app initialization.
        // ...
        Reset();
    }

    await Task.CompletedTask;
}

After navigating to the main page, we call the ShowIfAppropriateAsync() where we verify if we should open the dialog based on the saved Settings. When the user closes that dialog with the ‘Never Again’ button, we deactivate the service:

internal static async Task ShowIfAppropriateAsync(LaunchActivatedEventArgs e)
{
    bool hasShownFirstRun = _localSettings.Read(HasShown, false);

    if (!hasShownFirstRun)
    {
        var dialog = new FirstUseDialog();
        var response = await dialog.ShowAsync();
        if (response == ContentDialogResult.Secondary)
        {
            Deactivate();
        }
    }
}

Here’s how the dialog looks like in the sample application:

FirstUseDialog

All other milestone services follow the same pattern.

New Release Prompt Dialog

The ‘New Release Prompt’ service is identical to the ‘First Use Prompt’ service, except that it uses SystemInformation’s IsAppUpdated() method:

internal static async Task PreLaunchAsync(LaunchActivatedEventArgs e)
{
    if (SystemInformation.IsAppUpdated)
    {
        // New release app initialization.
        // ...
        NewReleaseActivationService.Reset();
    }

    await Task.CompletedTask;
}

internal static async Task ShowIfAppropriateAsync(LaunchActivatedEventArgs e)
{
    var currentVersion = SystemInformation.ApplicationVersion;

    if (currentVersion.ToFormattedString() == SystemInformation.FirstVersionInstalled.ToFormattedString())
    {
        // Original version. Ignore.
        return;
    }

    var hasShown = _localSettings.Read(HasShown, false);

    if (!hasShown)
    {
        // New release dialog.
        var dialog = new NewReleaseDialog();
        var response = await dialog.ShowAsync();
        if (response == ContentDialogResult.Secondary)
        {
            Deactivate();
        }
    }
}

[For a brand new application, the comparison between ApplicationVersion and FirstVersionInstalled is probably obsolete, but I’m planning to add these services to existing applications so I’m playing a bit with alternative algorithms.]

Here’s how the dialog looks like in the sample application:

NewReleaseDialog

Trial-to-Purchase Prompt Dialog

You don’t need UWP Community Toolkit to figure out if a trial version of the application is running and when that version upgrades to an officially purchased one.  That’s because there are already two ways of doing that in the current SDKs. You can use the members of the (now becoming legacy) Windows.ApplicationModel.Store namespace or the ones in the newer Windows.Services.Store namespace. I’m going for the former version, which is based on the LicenceInformation that you get from CurrentAppSimulator during development and from CurrentApp in the deployed version of your application:

_licenseInformation = CurrentAppSimulator.LicenseInformation;

The pattern is again the same as for the other milestone services, with one extension. The user may decide to buy your application when it is running, so the service is not only called on launch, but also in the LicenseChanged event handler:

internal static async Task PreLaunchAsync(LaunchActivatedEventArgs e)
{
    if (_licenseInformation.IsTrial)
    {
        // Trial: set HasShown to false to trigger detection.
        Reset();
        _licenseInformation.LicenseChanged += LicenseInformation_LicenseChanged;
    }
    else
    {
        // Purchased: set HasShown to true to inhibit detecting, but only if we were not detecting already.
        var hasShown = _localSettings.Read(HasShown, true);
        if (hasShown)
        {
            Deactivate();
        }
    }

    await Task.CompletedTask;
}
private async static void LicenseInformation_LicenseChanged()
{
    await ShowIfAppropriateAsync(null);
}
internal static async Task ShowIfAppropriateAsync(LaunchActivatedEventArgs e)
{
    if (_licenseInformation.IsTrial)
    {
        return;
    }

    var hasShown = _localSettings.Read(HasShown, true);

    if (!hasShown)
    {
        // New trial-to-purchase dialog.
        var dialog = new TrialToPurchaseDialog();
        var response = await dialog.ShowAsync();
        if (response == ContentDialogResult.Secondary)
        {
            Deactivate();
        }
    }
}

You can easily test the service by simulating a purchase with RequestAppPurchaseAsync(), like this:

internal async static Task SimulatePurchase()
{
    try
    {
        var result = await CurrentAppSimulator.RequestAppPurchaseAsync(false);

        // Purchased.

    }
    catch (Exception)
    {
        // Purchase failed.
    }

    await Task.CompletedTask;
}

The simulator will then open a new dialog where you can specify the answer to test (purchase or not, or an error):

TrialToPurchaseDialogTest

Here’s the Trial-to-Purchase dialog in the sample application:

TrialToPurchaseDialog

Rate and Review Prompt Dialog

For the last milestone service in this article, the UWP Community is back in full force. There’s no ideal moment for popping up a dialog to send the user to the store to rate or review. But for some applications this is important, and the SystemInformation helper has all the members to brew your own logic: when the application was first launched, how many times it has been launched, how long the current instance is running, and so on.

These settings are only maintained if you activate application tracking with a call to TrackAppUse(). So that’s what we do in PreLauncAsync(). The following code snippet also shows a small hack to transform the standard AppUptime to a cumulative version:

internal static async Task PreLaunchAsync(LaunchActivatedEventArgs e)
{
    // Start tracking app usage (launch count, uptime, ...)
    try
    {
        // Make the AppUptime cumulative over sessions.
        var uptimeSoFar = TimeSpan.FromTicks(new LocalObjectStorageHelper().Read<long>("AppUptime", 0));

        SystemInformation.TrackAppUse(e); // Resets AppUptime to 0.
        SystemInformation.AddToAppUptime(uptimeSoFar);
    }
    catch (Exception)
    {
        SystemInformation.TrackAppUse(e);
    }

    await Task.CompletedTask;
}

I’m not going to dive into the logic to open the dialog. It will be different for each application. The dialog itself has a hyperlink that points to the Store’s Rate and Review page for the application:

<TextBlock TextWrapping="WrapWholeWords">
    <Run>Replace the content of this dialog with whatever content is appropriate to your app.</Run>
    <LineBreak /><LineBreak />
    <Hyperlink Click="Hyperlink_Click">Rate and Review this app</Hyperlink>
    <LineBreak /><LineBreak />
    <Run>Don't feel restricted to just text. You can also include images and animations if you wish too.</Run>
</TextBlock>

When that link is clicked UWP Community Toolkit comes to the rescue again, with LaunchStoreForReviewAsync():

private async void Hyperlink_Click(Hyperlink sender, HyperlinkClickEventArgs args)
{
    await SystemInformation.LaunchStoreForReviewAsync();
}

Of course this only works when the application is associated with the store. Here’s the corresponding dialog:

RateAndReviewDialog

And that concludes the list of milestone user prompt services. I think that the architecture and implementation is generic enough so you can use some of it in your own applications.

Styling the Dialog

To give the dialogs in the sample application a more contemporary look, I extended the ContentDialog Style to have a DropShadowPanel (again from UWP Community Toolkit) around the border. After all, Depth is one of the building blocks of Fluent Design:

<!-- Added -->
<toolkit:DropShadowPanel Color="{StaticResource CustomDialogBorderColor}"
                            BlurRadius="20"
                            HorizontalContentAlignment="Stretch"
                            VerticalContentAlignment="Stretch">

All the code and more

The sample application lives here on GitHub. Feel free to reuse it or launch pull requests to improve and enhance it. Also don’t hesitate to dive into the source code of Windows Template Studio and UWP Community Toolkit. There’s a lot of gems in there…

Enjoy!

Data validation in UWP

In this article we describe how to implement validation of an object –typically an Entity, a Model, or a ViewModel instance- in a UWP app. We’ll use the Template10 Validation core classes for this.

The validation of an instance includes:

  • validating individual fields,
  • comparing two (or more) fields to each other,
  • comparing a newly assigned value to its original value,
  • verifying whether one or more fields have changed, and
  • undoing all changes to the instance.

I built a small sample app to illustrate all of this. Here’s how the main page looks like: on the left there’s a list of company cars. If one of these is selected, its details appear in the middle and we show an Edit button in the top right corner:

List

When the Edit button is clicked, an edit form pops open inside a content dialog. All fields of the ViewModel are editable. At the bottom of the dialog there are some switches that indicate the state of the instance (whether it was changed in the dialog, and whether it is valid) and a button to reset all fields to their original value.

If the object breaks any of the validation rules, then a list of errors appears at the bottom. As long as there are validation errors, the Save button is disabled:

Screenshot

I think this is a quite common use case, especially in enterprise environments. Here’s how I built it.

Template 10 Validation

The Template 10 Validation project by Jerry Nixon covers all of these scenarios with Property<T> and ValidationModelBase as its core classes. I copied these classes with their helpers and interfaces into my own project (under Services/Validation):

classes

I know it would have been easier to just reference the Template 10 Validation NuGet package. But I initially wanted to identify the smallest possible set of classes that cover my requirements and then make an old school Portable Class Library or a more modern .NET Standard Library from it. Unfortunately that was too ambitious. The current implementation relies on IObservableMap<K,V> from the Windows.Foundations.Collection namespace which –as its name implies- is not platform independent. If ObservableDictionary<K,V> could be rewritten without members from this namespace, then I think it would be possible to create a .NET Standard version of the code, that could then be used in environments such as Xamarin…

I kept all the code as is, except for the JsonIgnore and NotMapped attributes on some properties. These were removed to further reduce dependencies. Here’s an overview of the seven classes and interfaces that make up the Validation service:

ValidationClassDiagram

The core class is ValidatableModelBase, which holds the default implementation for an editable data object that supports validation:

  • an implementation of INotifyPropertyChanged,
  • an internal collection of Property<T> instances that store the new and original values of all its properties,
  • a Validator Action<T> delegate to hold your validation logic,
  • a Validate method to trigger the validation,
  • an Errors collection to hold the validation messages,
  • IsValid and isDirty properties to inspect the state, and
  • a Revert method to undo all changes.

Let’s see how this works in practice.

A simple Model

My UWP sample app contains the following class to hold Company Car information. Instances of this Model class are bound to the list at the left, and to the read-only details. The Model class uses the change propagation that comes with my own compact MVVM library and I will stick to this:

public class CompanyCar : BindableBase
{
    private string _brand;
    private string _type;
    private string _body;
    // ...

    public string Brand
    {
        get { return _brand; }
        set { SetProperty(ref _brand, value); }
    }

    public string Type
    {
        get { return _type; }
        set { SetProperty(ref _type, value); }
    }

    public string Body
    {
        get
        {
            return _body;
        }
        set
        {
            SetProperty(ref _body, value);
            OnPropertyChanged(nameof(BodyIcon));
        }
    }

    // ...
}

An editable and validatable ViewModel

To create the corresponding ViewModel class that will be bound to the edit dialog, you must plug ValidatableModelBase somewhere in its inheritance chain and define the properties in such a way that they are automatically hooked to the underlying Property<T> instances:

public class CompanyCarViewModel : ValidatableModelBase
{
    public string Brand { get { return Read<string>(); } set { Write(value); } }

    public DateTime ProductionDate { get { return Read<DateTime>(); } set { Write(value); } }

    public double Mileage { get { return Read<double>(); } set { Write(value); } }

    // ...
}

Of course you also need to provide the validation logic. The validation delegate typically iterates through a set of rules. Any validation rule that is not met by the instance, adds a message in the Errors collection of the corresponding property. Here are some validation rules from the sample app:

  • Brand and Type are mandatory
  • Date of first use should come after date of production
  • Mileage may not decrease

Validations on a single field can be done in many ways with many frameworks, most of which rely on data annotation through validation attributes on the properties. Comparing two fields in a validation rule is a lot more complex (but not impossible, there’s an example of using Prism for this right here). I am not aware of a library that allows to compare the changed value of a field to its original value, except for the bloated self-tracking entities. Nevertheless this is a requirement that I often encounter (typically with counters and dates). I believe that the Template 10 Validation classes provide an excellent service in an elegant way and with minimal impact on your app.

Here’s the code for the validation rules in the sample app:

private void Validation_Executed(CompanyCarViewModel c)
{
    if (string.IsNullOrEmpty(c.Brand))
    {
        c.Properties[nameof(c.Brand)].Errors.Add("Brand is mandatory.");
    }

    if (string.IsNullOrEmpty(c.Type))
    {
        c.Properties[nameof(c.Type)].Errors.Add("Type is mandatory.");
    }

    // Compare two properties.
    if (c.FirstUseDate < c.ProductionDate)
    {
        // Unfortunately errors have to be assigned to a property.
        c.Properties[nameof(c.FirstUseDate)].Errors.Add("Date of first use should come after date of production.");
    }

    // Compare with original value.
    if (c.Mileage < (c.Properties[nameof(c.Mileage)] as Property<double>).OriginalValue)
    {
        c.Properties[nameof(c.Mileage)].Errors.Add("Turning back the mileage is illegal.");
    }
}

The ViewModel is ready now, so let’s provide edit functionality in its most common form: as a modal edit dialog.

The Edit Dialog

According to the dialogs and flyouts recommendations, a ContentDialog would be the ideal control for this in UWP. If you’re planning to use content dialogs for more than just messages and confirmation, then you would want to override some of the size restrictions in the default style. Here’s how to set the maximum width from the default of 548 pixels (which is way to small for an edit form) to 800, in app.xaml:

<x:Double x:Key="ContentDialogMaxWidth">800</x:Double>

In editable fields, don’t forget to set the BindingMode to TwoWay (it’s not the default):

<TextBox Header="Brand" Text="{Binding Brand, Mode=TwoWay}" />

Here’s the XAML for the status bar at the bottom, displaying the validation errors:

<ItemsControl ItemsSource="{Binding Errors, Mode=OneWay}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

And here’s how the entire edit form looks like in action:

Screenshot

When the Edit button is clicked, you need to create the ViewModel from the currently selected Model. You can use any kind of Mapper for this, or conversion operators, or you can do it in a constructor like this:

public CompanyCarViewModel(Models.CompanyCar model)
{
    this.Brand = model.Brand;
    this.Type = model.Type;
    this.Body = model.Body;
    this.ProductionDate = model.ProductionDate;
    this.FirstUseDate = model.FirstUseDate;
    this.PowerUnit = model.PowerUnit;
    this.Emission = model.Emission;
    this.Mileage = model.Mileage;
    this.Driver = model.Driver;
    this.Validator = that => { Validation_Executed(that as CompanyCarViewModel); };

    // Not needed: ValidatableModelBase constructor does this.
    // this.PropertyChanged += (o, e) => Val(o as CompanyCar);
}

Of course you also need to provide the code to update the Model with the –validated- data when the Save button was pressed:

internal void Update(Models.CompanyCar model)
{
    model.Brand = this.Brand;
    model.Type = this.Type;
    model.Body = this.Body;
    model.ProductionDate = this.ProductionDate;
    model.FirstUseDate = this.FirstUseDate;
    model.PowerUnit = this.PowerUnit;
    model.Emission = this.Emission;
    model.Mileage = this.Mileage;
    model.Driver = this.Driver;
}

Here’s the code to open the dialog and to make sure that the primary button is disabled as long as there are validation errors:

// Prepare ViewModel.
var companyCarViewModel = new CompanyCarViewModel(ViewModel.SelectedCompanyCar);
companyCarViewModel.PropertyChanged += (obj, ev) => EditDialog.IsPrimaryButtonEnabled = companyCarViewModel.IsValid;
companyCarViewModel.Validate();
EditDialog.DataContext = companyCarViewModel;

// Process Dialog.
var result = await EditDialog.ShowAsync();

Here’s how the Model is updated when the dialog is closed through the primary button:

var result = await EditDialog.ShowAsync();
if (result == ContentDialogResult.Primary)
{
    // Update model.
    companyCarViewModel.Update(ViewModel.SelectedCompanyCar);
}

Here’s how to reset the ViewModel to its original values:

private void ResetButton_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
    (EditDialog.DataContext as CompanyCarViewModel).Revert();
}

Wait, there’s more

Validation checks are not restricted to edit forms. You could for example validate all the (view)models in the UI, to show your end users which objects need some attention. Just bind the IsValid property to an element in the data template, like in this example from the Template10 Validation sample app:

Template10ValidationMain

That sample project also shows how to decorate the controls in the edit form with error indicators, like this:

Template10Validation

This requires some extra behaviors and control templates from the NuGet package. I don’t have these in my own sample app, because I was looking for reusable logic, not UI.

The code

My own sample app lives here on GitHub.

Enjoy!