Styling the CheckBox control with Segoe UI Symbol glyphs

With Windows 8.1 Microsoft updated the Segoe UI Symbol font and added a nice amount of icons for the most commonly actions used in application bar buttons. The reason behind this was to replace the old method of creating small PNG images to use as the content of the buttons and directly use font glyphs that would scale nicely across all target resolutions.

Character Map tool showing Segoe UI Symbol

This font also introduces some other symbols like back/forward arrows, hearts for favourited items and even the tick parts of CheckBox and RadioButton controls. However, the standard XAML controls still don’t use it so I’m assuming they were thought for using inside HTML/WinJS apps.

Today, we are going to dissect the CheckBox control to see what parts it is composed of, and will be switching standard XAML shapes and paths for glyphs when applicable.

Understanding the parts of the CheckBox control

Let’s start by creating a new Universal App project and adding a CheckBox control to both the MainPage of the Windows 8.1 and Windows Phone projects. We have to do it this way since the styles for both platforms are a little different, and we want to make them as accurate to the original version as possible.

Now, to better work with control styles, open the project in Blend. Right click the CheckBox control and select Edit Template > Edit a Copy… . Set a name in the new dialog (we will be using CheckBoxGlyphStyle) and make sure it’s defined at the document level so there aren’t any duplicate names in App.xaml. Now, if you have never customized control templates or styles, what it does is copy all the default XAML for the control so you can edit it and override whatever you want, including animations and visual states.

If you examine the generated templates for both controls, you will see that they have some things in common:

  • Both have a grid that encompasses the ContentPresenter (where the text or custom content will be displayed) and another grid for holding the tick/check part.
  • Inside that grid, both have a Path named CheckGlyph to the represent the tick mark.

However, other parts are platform specific.

Windows Phone
  • The indeterminate mark is a Rectangle called NormalRectangle.
  • A Border named CheckBackground is used as the background of the tick. Its BorderThickness is directly bound to the same property of the CheckBox control.
  • The root container of the control is a Grid.
  • Display of parts depending on the visual state is controlled through the Visibility property.
Windows 8.1
  • The indeterminate mark is a Rectangle too, but this time it’s called IndeterminateGlyph.
  • The NormalRectangle exists, too, but in this case is a Rectangle that acts as the background of the tick part.
  • The root container of the control is a Border, whose BorderThickness is bound to the same property of the CheckBox control.
  • Display of parts depending on the visual state is controlled through the Opacity property.
  • There are two other rectangles, FocusVisualWhite and FocusVisualBlack, for displaying that the control has focus while tab navigating.

Take a deep look at the default templates generated for both controls and make you comfortable with them. When you are ready, let’s start customizing them.

Switching from shapes to glyphs

To achieve our goal we must replace some of the existing XAML shapes with TextBlock controls containing a single glyph. Since the process has some differences depending on the target platform, we are going to detail them separately:

Windows Phone
  • Give a name to the Grid that contains the tick parts, since we will set some of its properties via a visual state later. We will be using CheckGrid.
  • Create three TextBlock controls inside this grid and name them as the existing control parts.
  • Set their font family to Segoe UI Symbol and size to the system resource called TextStyleLargeFontSize.
  • Match the HorizontalAlignment and VerticalAlignment with those of the old controls; in some instances the glyphs will appear cut off due to font padding/kerning. You can try fixing this for perfection or leave it as is.
  • Set their Text values to the matchings glyphs (this is more easily achieved by writing the escaped value in XAML code). The escaped values for each one are as follows:
Usage Escaped Unicode Glyph
Border 
Tick 
Indeterminate 
  • Match the IsHitTestVisible and Visibility properties with those of the old controls.
  • Now, since the brush properties of the old and new controls are different, we have to try and match the bindings as closely as possible:
Control and property Binding value
CheckBackground Foreground TemplateBinding BorderBrush
Parent Grid Background TemplateBinding Background
NormalRectangle Foreground ThemeResource CheckBoxForegroundThemeBrush
CheckGlyph Foreground ThemeResource CheckBoxForegroundThemeBrush

WARNING: by default, the indeterminate state of the CheckBox is broken! The theme background brush is incorrectly assigned to NormalRectangle instead of the foreground one, so if you declare the control as IsThreeState you can see it behave erroneously.

<Grid x:Name=”CheckGrid” Grid.Column=”0″ VerticalAlignment=”Top” Background=”{TemplateBinding Background}“>

    <TextBlock x:Name=”CheckBackground” HorizontalAlignment=”Center” Text=”&#xE003;” VerticalAlignment=”Top” FontFamily=”Segoe UI Symbol” IsHitTestVisible=”False” Foreground=”{TemplateBinding BorderBrush} FontSize=”{StaticResource TextStyleLargeFontSize}“/>

    <TextBlock x:Name=”NormalRectangle” HorizontalAlignment=”Center” Text=”&#xE004;” VerticalAlignment=”Top” FontFamily=”Segoe UI Symbol” IsHitTestVisible=”False” Visibility=”Collapsed” Foreground=”{ThemeResource CheckBoxForegroundThemeBrush} FontSize=”{StaticResource TextStyleLargeFontSize}” />

    <TextBlock x:Name=”CheckGlyph” HorizontalAlignment=”Center” Text=”&#xE001;” VerticalAlignment=”Top” FontFamily=”Segoe UI Symbol” IsHitTestVisible=”False” Visibility=”Collapsed” Foreground=”{ThemeResource CheckBoxForegroundThemeBrush} FontSize=”{StaticResource TextStyleLargeFontSize}” />

</Grid>

Windows 8.1
  • Create three TextBlock controls inside this grid and name them as the existing control parts that aren’t focus visuals.
  • Set their font family to Segoe UI Symbol and size to 11 points.
  • Again, match the HorizontalAlignment and VerticalAlignment with those of the old controls. Fix the small displacements adjusting margins if you want.
  • Set their Text values to the matchings glyphs. They are almost the same, except that in this instance the tick has a solid background instead of a border:
Usage Escaped Unicode Glyph
Background &#xE002;
Tick &#xE001;
Indeterminate &#xE004;
  • Match the Opacity properties with those of the old controls.
  • Again, match the brush properties using the following table:
Control and property Binding value
NormalRectangle Foreground ThemeResource CheckBoxBackgroundThemeBrush
CheckGlyph Foreground ThemeResource ComboBoxForegroundThemeBrush
IndeterminateGlyph Foreground TemplateBinding ComboBoxForegroundThemeBrush

<Grid VerticalAlignment=”Top”>

    <TextBlock x:Name=”NormalRectangle” HorizontalAlignment=”Center” Text=”&#xE002;” VerticalAlignment=”Center” FontFamily=”Segoe UI Symbol” Foreground=”{ThemeResource CheckBoxBackgroundThemeBrush}“/>

    <TextBlock x:Name=”CheckGlyph” HorizontalAlignment=”Center” Text=”&#xE001;” VerticalAlignment=”Center” FontFamily=”Segoe UI Symbol” Foreground=”{ThemeResource ComboBoxForegroundThemeBrush} Opacity=”0″/>

    <TextBlock x:Name=”IndeterminateGlyph” HorizontalAlignment=”Center” Text=”&#xE004;” VerticalAlignment=”Center” FontFamily=”Segoe UI Symbol” Foreground=”{ThemeResource ComboBoxForegroundThemeBrush} Opacity=”0″/>

    <Rectangle x:Name=”FocusVisualWhite” Height=”27″ Opacity=”0″ StrokeDashOffset=”0.5″ StrokeEndLineCap=”Square” Stroke=”{ThemeResource FocusVisualWhiteStrokeThemeBrush} StrokeDashArray=”1,1″ Width=”27″/>

    <Rectangle x:Name=”FocusVisualBlack” Height=”27″ Opacity=”0″ StrokeDashOffset=”1.5″ StrokeEndLineCap=”Square” Stroke=”{ThemeResource FocusVisualBlackStrokeThemeBrush} StrokeDashArray=”1,1″ Width=”27″/>

</Grid>

Fixing the visual states

Now you could run the project in both platforms and check that it displays correctly. However, interacting with the CheckBox controls in any way will crash the application. This is due to changing the parts that compose the control, so when a new visual state tries to change a property that doesn’t exist an exception is thrown. We are going to fix this by modifying the default visual states so they match our new layout.

Windows Phone

In this case we only need to modify the Pressed and Disabled visual states, since they are the ones that change the conflicting values. We need to match the Storyboard.TargetProperty and Storyboard.TargetName accordingly to the names and properties of the new control parts.

<VisualState x:Name=”Pressed”>

    <Storyboard>

        <PointerDownThemeAnimation Storyboard.TargetName=”Grid”/>

        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty=”Background” Storyboard.TargetName=”CheckGrid”>

            <DiscreteObjectKeyFrame KeyTime=”0″ Value=”{ThemeResource CheckBoxPressedBackgroundThemeBrush}“/>

        </ObjectAnimationUsingKeyFrames>

        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty=”Foreground” Storyboard.TargetName=”CheckGlyph”>

            <DiscreteObjectKeyFrame KeyTime=”0″ Value=”{ThemeResource CheckBoxPressedForegroundThemeBrush}“/>

        </ObjectAnimationUsingKeyFrames>

        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty=”Foreground” Storyboard.TargetName=”NormalRectangle”>

            <DiscreteObjectKeyFrame KeyTime=”0″ Value=”{ThemeResource CheckBoxPressedBackgroundThemeBrush}“/>

        </ObjectAnimationUsingKeyFrames>

    </Storyboard>

</VisualState>

<VisualState x:Name=”Disabled”>

    <Storyboard>

        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty=”Foreground” Storyboard.TargetName=”CheckBackground”>

            <DiscreteObjectKeyFrame KeyTime=”0″ Value=”{ThemeResource CheckBoxDisabledBorderThemeBrush}“/>

        </ObjectAnimationUsingKeyFrames>

        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty=”Foreground” Storyboard.TargetName=”CheckGlyph”>

            <DiscreteObjectKeyFrame KeyTime=”0″ Value=”{ThemeResource CheckBoxDisabledForegroundThemeBrush}“/>

        </ObjectAnimationUsingKeyFrames>

        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty=”Foreground” Storyboard.TargetName=”NormalRectangle”>

            <DiscreteObjectKeyFrame KeyTime=”0″ Value=”{ThemeResource CheckBoxDisabledBackgroundThemeBrush}“/>

        </ObjectAnimationUsingKeyFrames>

        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty=”Foreground” Storyboard.TargetName=”ContentPresenter”>

            <DiscreteObjectKeyFrame KeyTime=”0″ Value=”{ThemeResource CheckBoxDisabledForegroundThemeBrush}“/>

        </ObjectAnimationUsingKeyFrames>

    </Storyboard>

</VisualState>

Windows 8.1

As before, but this time the visual states to be modified are PointerOver, Pressed and Disabled. Also, setting the Stroke property of NormalRectangle should be deleted since we don’t have an equivalent for it.

<VisualState x:Name=”PointerOver”>

    <Storyboard>

        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty=”Foreground” Storyboard.TargetName=”NormalRectangle”>

            <DiscreteObjectKeyFrame KeyTime=”0″ Value=”{ThemeResource CheckBoxPointerOverBackgroundThemeBrush}“/>

        </ObjectAnimationUsingKeyFrames>

        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty=”Foreground” Storyboard.TargetName=”CheckGlyph”>

            <DiscreteObjectKeyFrame KeyTime=”0″ Value=”{ThemeResource CheckBoxPointerOverForegroundThemeBrush}“/>

        </ObjectAnimationUsingKeyFrames>

        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty=”Foreground” Storyboard.TargetName=”IndeterminateGlyph”>

            <DiscreteObjectKeyFrame KeyTime=”0″ Value=”{ThemeResource CheckBoxPointerOverForegroundThemeBrush}“/>

        </ObjectAnimationUsingKeyFrames>

    </Storyboard>

</VisualState>

<VisualState x:Name=”Pressed”>

    <Storyboard>

        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty=”Foreground” Storyboard.TargetName=”NormalRectangle”>

            <DiscreteObjectKeyFrame KeyTime=”0″ Value=”{ThemeResource CheckBoxPressedBackgroundThemeBrush}“/>

        </ObjectAnimationUsingKeyFrames>

        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty=”Foreground” Storyboard.TargetName=”CheckGlyph”>

            <DiscreteObjectKeyFrame KeyTime=”0″ Value=”{ThemeResource CheckBoxPressedForegroundThemeBrush}“/>

        </ObjectAnimationUsingKeyFrames>

        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty=”Foreground” Storyboard.TargetName=”IndeterminateGlyph”>

            <DiscreteObjectKeyFrame KeyTime=”0″ Value=”{ThemeResource CheckBoxPressedForegroundThemeBrush}“/>

        </ObjectAnimationUsingKeyFrames>

    </Storyboard>

</VisualState>

<VisualState x:Name=”Disabled”>

    <Storyboard>

        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty=”Foreground” Storyboard.TargetName=”NormalRectangle”>

            <DiscreteObjectKeyFrame KeyTime=”0″ Value=”{ThemeResource CheckBoxDisabledBackgroundThemeBrush}“/>

        </ObjectAnimationUsingKeyFrames>

        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty=”Foreground” Storyboard.TargetName=”CheckGlyph”>

            <DiscreteObjectKeyFrame KeyTime=”0″ Value=”{ThemeResource CheckBoxDisabledForegroundThemeBrush}“/>

        </ObjectAnimationUsingKeyFrames>

        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty=”Foreground” Storyboard.TargetName=”IndeterminateGlyph”>

            <DiscreteObjectKeyFrame KeyTime=”0″ Value=”{ThemeResource CheckBoxDisabledForegroundThemeBrush}“/>

        </ObjectAnimationUsingKeyFrames>

        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty=”Foreground” Storyboard.TargetName=”ContentPresenter”>

            <DiscreteObjectKeyFrame KeyTime=”0″ Value=”{ThemeResource CheckBoxContentDisabledForegroundThemeBrush}“/>

        </ObjectAnimationUsingKeyFrames>

    </Storyboard>

</VisualState>

And that’s it. Now you can run both projects and test that they work.

Custom CheckBox styles on Windows 8.1 and Windows Phone

Further customization

While you can leave the controls as they are right now, the purpose of this article is to give an entry point so you can customize them further. What about styling the RadioButton in a similar way, too? Or using the CheckBox to mark favourite items with a heart icon? Now you can use whatever glyphs you like to give your app a more personalized look. This is just the entry point.

Showing the CheckBox using glyphs and with a new custom style with hearts

Source code

You can download the source code as a Visual Studio 2013 C#/XAML Universal App project from the GitHub repository. Feel free to use in any way you like since it’s MIT licensed, and if you have any questions or improvements contact me via the contact page or the repository’s issues page.

Proper lifecycle management of SharpDX resources in C#/XAML Universal Apps

In the last tutorial we learned how to properly use SharpDX in our XAML apps so we can get the power of DirectX without having to touch native C++ code. However, it was a very superficial introduction for demonstrative purposes that didn’t take into account anything more than single page applications. Using that code in real-world applications would introduce lots of problems (memory leaks, bad performance, crashes) that we are going to learn how to fix in this article. So, we are going to learn how to extend that code so it behaves better when our application has page navigation, gets snapped or is suspended/reactivated.

Now that we are focusing on integrating SharpDX with XAML applications, we have to take into account proper finalization of the created resources when navigating away from pages that contain SwapChainPanel/SwapChainBackgroundPanel controls.

Start by adding a new Page to the shared project. Add a button in MainPage to navigate to the new page, and another one there to make the frame go back in the navigation stack so we don’t end with an infinite navigation loop. If you run the project you will see that it works correctly; however, there is a small problem that can only be spotted by running the Performance and Diagnostics tool with the Memory Usage option selected:

leak


There is a memory leak in the application, because when we are navigating away from the page, we aren’t disposing any of the SharpDX resources we have created for rendering. And since they are wrappers over native objects, they will hardly be automatically reclaimed by the garbage collector.

But this has a very easy solution. Since we subscribed to the Loaded event of the SwapChainPanel for creating everything, we can subscribe to the Unloaded one and perform the opposite operations:

private void SwapChainPanel_Unloaded(object sender, RoutedEventArgs e)
{
    CompositionTarget.Rendering -= CompositionTarget_Rendering;    using (DXGI.ISwapChainPanelNative nativeObject = ComObject.As<DXGI.ISwapChainPanelNative>(this.SwapChainPanel))
    {
        nativeObject.SwapChain = null;
    }

    Utilities.Dispose(ref this.backBufferView);
    Utilities.Dispose(ref this.backBufferTexture);
    Utilities.Dispose(ref this.swapChain);
    Utilities.Dispose(ref this.deviceContext);
    Utilities.Dispose(ref this.device);
}


If we run again the memory diagnostics tool, we can verify that all allocated memory is properly being released when navigating away from the page:

leak_fixed


Window resizing

UPDATE: SourceSize isn’t the most appropriate approach to use when the application is being snapped, since it’s thought for uniformly scaling the swap chain to smaller sizes in less powerful hardware; using it this way will stretch the output image when drawing with Direct 3D. In this case, setting a different viewport will be enough.

Now we take into account when resizing happens so the swap chain dimensions match those of the control it is associated with. DirectX 11.2 introduced the new SourceSize property for DXGI.SwapChain2 objects, which lets you specify a region equal or smaller than the swap chain’s total size so you don’t have to always destroy and recreate it, only in the cases that a bigger one is needed.

Let’s subscribe to the SizeChanged event of the SwapChainPanel to accomplish this. But, this event can fire before the Loaded one if we don’t specify a default size for the control. To check that our swap chain is initialized and ready for resizing, we must declare a boolean flag (in our case it’s named isDXInitialized) and set it to true at the end of the SwapChainPanel_Loaded function. Now we can safely resize set the SourceSize property:

private void SwapChainPanel_SizeChanged(object sender, SizeChangedEventArgs e)
{
    if (isDXInitialized)
    {
        Size2 newSize = RenderSizeToPixelSize(e.NewSize);
        swapChain.SourceSize = newSize;
    }
}

This will work nicely in a number of cases but it’s far from perfect. Remember that I said that the specified region should be equal or smaller in size to the swap chain’s dimensions? If you make the control bigger at runtime or launch the application in snapped mode and resize it to full screen, you will receive a 0x887A0001 (DXGI_ERROR_INVALID_CALL) exception.

So, the logic outcome is to check the new size of the control and resize the swap chain if a bigger one is needed then set the SourceSize property, isn’t it?

private void SwapChainPanel_SizeChanged(object sender, SizeChangedEventArgs e)
{
    if (isDXInitialized)
    {
        Size2 newSize = RenderSizeToPixelSize(e.NewSize);        if (newSize.Width > swapChain.Description1.Width || newSize.Height > swapChain.Description1.Height)
        {
            swapChain.ResizeBuffers(swapChain.Description.BufferCount, (int)e.NewSize.Width, (int)e.NewSize.Height, swapChain.Description1.Format, swapChain.Description1.Flags);
        }

        swapChain.SourceSize = newSize;
    }
}


While technically true, it is still missing a minor detail: all resources linked to a swap chain must be destroyed before calling SwapChain2.ResizeBuffers. In our case it’s the render target and its associated resource view, so if you call the previous code as-is, you will receive the a dreaded DXGI_ERROR_INVALID_CALL exception again.

To fix this, we must destroy the associated resources, resize the swap chain and recreate them:

private void SwapChainPanel_SizeChanged(object sender, SizeChangedEventArgs e)
{
    if (isDXInitialized)
    {
        Size2 newSize = RenderSizeToPixelSize(e.NewSize);        if (newSize.Width > swapChain.Description1.Width || newSize.Height > swapChain.Description1.Height)
        {
            Utilities.Dispose(ref this.backBufferView);
            Utilities.Dispose(ref this.backBufferTexture);

            swapChain.ResizeBuffers(swapChain.Description.BufferCount, (int)e.NewSize.Width, (int)e.NewSize.Height, swapChain.Description1.Format, swapChain.Description1.Flags);

this.backBufferTexture = D3D11.Texture2D.FromSwapChain<D3D11.Texture2D>(this.swapChain, 0);
            this.backBufferView = new D3D11.RenderTargetView(this.device, this.backBufferTexture);
        }

        swapChain.SourceSize = newSize;
    }
}


 

Application suspension

At last, we are going to implement a new requisite when creating Windows Store apps that use DirectX: calling the DXGI.Device3.Trim method when the app goes into suspension. This function frees some internal buffers created by the graphics driver for faster performance and must be used to reduce the app’s memory footprint so there are less chances of it being terminated while suspended. The buffers will be transparently recreated when the app is reactivated, introducing only a minor execution delay.

So, let’s subscribe to the Suspending event of the current Application instance inside the SwapChainPanel_Loaded function, and unsubscribe inside SwapChainPanel_Unloaded to ensure proper finalization. Our new function will perform minimal processing, calling only DeviceContext.ClearState and Device3.Trim as per the guidelines. Since we aren’t storing an instance of DXGI.Device3, you can use QueryInterface on the current Direct3D 11.2 device or call GetDevice on the swap chain; remember to put it inside an using block or dispose it manually since both calls return a new object that needs to be freed:

private void Application_Suspending(object sender, Windows.ApplicationModel.SuspendingEventArgs e)
{
    if (isDXInitialized)
    {
        this.deviceContext.ClearState();        using (DXGI.Device3 dxgiDevice3 = this.swapChain.GetDevice<DXGI.Device3>())
        {
            dxgiDevice3.Trim();
        }
    }
}


Source code

As always, you can get the full soure code (Windows Store C#/XAML Universal App project, compatible with Visual Studio 2013 only) from GitHub.

UniversalRateReminder, a rate pop up for Windows/Windows Phone Universal XAML apps

While slowly moving from making Windows Phone Silverlight apps to Universal XAML ones, I found that the availability of some basic libraries and controls is very fragmented. There are lots of resources for enhancing your Windows Phone Silverlight app, while Windows 8 XAML feels a little neglected. And on top of it, a good amount of Windows libraries/controls don’t work out of the box when targeting 8.1 projects or just plain crash.

One of these features that is very helpful is a pop up reminder for rating the app. While there are lots of implementations for Silverlight (Telerik has one in its controls suite, and even Nokia released a free one), in XAML it’s more difficult to find a library that performs this, to the point that searching Google for “windows 8 xaml rate reminder” only produces one significant result. And don’t forget that almost all implementations rely on XAML controls, which can introduce additional complexity if you want to show the reminder programmatically.

To try and fix some of these shortcomings, a new library is available for Universal XAML apps. It allows you to show a rate reminder pop up for both the Windows and Windows Phone versions of the app with only one line of code:

  1. RatePopup.CheckRateReminder();

Just call it at the end of the OnLaunched function of your App class and it will automatically check the number of times the app has been run, and if it exceeds the threshold (by default five times), the pop up will be shown. Dismissing it by tapping either one of the buttons will make it never show again.

Sample app showing UniversalRateReminder pop up


Of course, everything is customizable, from the text shown inside the pop up to the number of times the application must be launched before showing it. Just be sure to modify the static properties before calling CheckRateReminder:

  1. RatePopup.LaunchLimit = 1;
  2. RatePopup.RateButtonText = “rate”;
  3. RatePopup.CancelButtonText = “cancel”;
  4. RatePopup.Title = “Rate app”;
  5. RatePopup.Content = “Would you like to rate this app?”;
  6. RatePopup.CheckRateReminder();

And if for whatever reason you want to reset the launch count or want to show the reminder more than once, you can call ResetLaunchCount to reinitialize all internal counters.

You can get the source code, including a small sample app showing how to use the library, from its GitHub page; or you can search for UniversalRateReminder on NuGet or view its project page.