Category Archives: UWP

Using a TreeView Control for Navigation in UWP

In this article we’ll show how to use a TreeView as the main navigation control in a UWP app. We will stay as close as possible to the Fluent Design principles and other current UI guidelines.

Our first approach was to rely on the NavigationView control, since it comes with a full user experience (navigation, hamburger, page title, secondary commands, responsive and fluent design). Unfortunately it is entirely focused on (read: limited to) a flat list of menu items. So we decided to design and build the entire user experience from scratch.

We admit that we expected to run into issues. None of the native UWP apps that could clearly use treeview based navigation –such as the Mail client and the OneNote app- actually have one. So we were a bit suspicious of the TreeView’s capabilities. Fortunately this was just unfounded fear.

We created a sample app with these main navigation components in a Shell page:

  • a SplitView,
  • a TreeView for primary navigation,
  • a Frame to host the pages on a background with parallax effect,
  • a Hamburger button, and
  • a CommandBar for secondary navigation.

Here’s how that app looks like:
TreeViewNavigation

Building the User Experience

Here’s the main XAML content of the Shell page:

<!-- SplitView -->
<SplitView x:Name="ShellSplitView">
    <SplitView.Pane>
        <Grid x:Name="SplitViewPane">
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="auto" />
            </Grid.RowDefinitions>
            <!-- Navigation Tree -->
            <TreeView x:Name="NavigationTree"
                        ItemInvoked="TreeView_ItemInvoked"
                        Style="{StaticResource TreeViewStyle1}" />
            <!-- Command Bar -->
            <CommandBar>
                <!-- AppBarButtons -->
            </CommandBar>
        </Grid>
    </SplitView.Pane>
    <SplitView.Content>
        <Grid>
            <!-- Does not seem to work. -->
            <ParallaxView Source="{Binding ElementName=NavigationTree}"
                            VerticalShift="100">
                <!-- Background Image -->
            </ParallaxView>

            <!-- Navigation Frame -->
            <Frame x:Name="SplitViewFrame"
                    Navigated="SplitViewFrame_OnNavigated"/>
        </Grid>
    </SplitView.Content>
</SplitView>

<!-- Title Bar -->
<TextBlock x:Name="AppTitle" />

<!-- Hamburger Button -->
<Button x:Name="HamburgerButton">
    <!-- ... -->
</Button>

SplitView

We used a classic SplitView control to host the main components: the TreeView on the left and a Frame to hold the current page on the right. The SplitView Pane can be opened or closed with a Hamburger button that sits on top of it (z-index wise).

A SplitView supports four display modes for the Pane, but the NavigationView only uses three display modes for the menu:

  • Minimal: panel shows if needed and on top of content,
  • Compact: panel shows a narrow band of icons, and
  • Expanded: panel shows alongside the content.

We didn’t use icons in the TreeView’s ItemTemplate – and it would anyway be impossible to  to show a multi-level tree in a narrow vertical band. So we decided to skip compact mode in the visual states. As a result the SplitView Pane has always the same width (when visible). It will just toggle between Inline and Expanded according to the app’s width.

Following the guidelines for Acrylic, we made the navigation pane background

  • 60% in-app acrylic in overlay mode, and
  • 60% background acrylic in side-by-side mode.

When using acrylic brushes in your app, don’t forget to provide a fallback color. It’s the solid color that is shown when the composition brushes are not used – i.e. when the app loses focus, or when the user settings or the machine hardware prevent it. Here’s a screenshot of the app when it does not have the focus:

Unfocused

Here’s the definition of the corresponding brushes:

<!-- Splitview Pane -->
<AcrylicBrush x:Key="SplitViewInlineBackgroundBrush"
                BackgroundSource="HostBackdrop"
                TintOpacity="0.6"
                FallbackColor="#ffe6ff" />
<AcrylicBrush x:Key="SplitViewOverlayBackgroundBrush"
                BackgroundSource="Backdrop"
                TintOpacity="0.6"
                FallbackColor="#ffe6ff" />

And here’s how they are declaratively applied in the Visual State Manager:

<!-- VisualState to be triggered when window width is >=1007 effective pixels -->
<VisualState x:Name="Expanded">
    <VisualState.StateTriggers>
        <AdaptiveTrigger MinWindowWidth="1007" />
    </VisualState.StateTriggers>
    <VisualState.Setters>
        <!-- SplitView pane shows as overlay -->
        <Setter Target="ShellSplitView.DisplayMode"
                Value="Inline" />
        <Setter Target="ShellSplitView.PaneBackground"
                Value="{StaticResource SplitViewInlineBackgroundBrush}" />
    </VisualState.Setters>
</VisualState>

The Shell page -including the SplitView and its content- is blended into the title area:

// Blends the app into the title bar.
var coreTitleBar = CoreApplication.GetCurrentView().TitleBar;
coreTitleBar.ExtendViewIntoTitleBar = true;
var titleBar = ApplicationView.GetForCurrentView().TitleBar;
titleBar.ButtonBackgroundColor = Colors.Transparent;
titleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
titleBar.ButtonForegroundColor = (Color)Application.Current.Resources["TitlebarButtonForegroundColor"];

For more info on this code and its consequences, check the TitleBar Customization documentation.

TreeView

The TreeView control is the obvious candidate for displaying a hierarchical menu. It is also one of the UWP controls that comes with built-in Reveal highlight effect, a lighting effect that highlights interactive elements, such as command bar buttons, listview items, or treeview nodes when the user moves the pointer near them. Check the bottom left part of the first screenshot in this article for an impression.

We tweaked the TreeViewItem style a little bit to decorate the selected node with a thin vertical bar, just like the NavigationView does (but without an animation). Here’s what we changed :

<!-- Added -->
<Grid x:Name="SelectionGrid"
        Width="4"
        Margin="8"
        HorizontalAlignment="Left" />

<VisualState x:Name="Selected">
    <VisualState.Setters>
        <!-- Changed -->
        <Setter Target="SelectionGrid.Background"
                Value="{ThemeResource TreeViewItemBackgroundSelected}" />
        <Setter Target="ContentPresenter.Foreground"
                Value="{ThemeResource TreeViewItemForegroundSelected}" />
        <Setter Target="ContentPresenterGrid.BorderBrush"
                Value="{ThemeResource TreeViewItemBorderBrushSelected}" />
    </VisualState.Setters>
</VisualState>

As part of the process, we also changed the different accent colors so that we don’t rely on the user’s personal accent color:

<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.ThemeDictionaries>
            <!-- AccentColor overrides -->
            <!-- Shades of OrangeRed -->
            <ResourceDictionary x:Key="Default">
                <Color x:Key="SystemAccentColor">#ff4500</Color>
                <Color x:Key="SystemAccentColorLight1">#ff4500</Color>
                <Color x:Key="SystemAccentColorLight2">#ff8f66</Color>
                <Color x:Key="SystemAccentColorLight3">#b33000</Color>
                <Color x:Key="SystemAccentColorDark1">#ff4500</Color>
                <Color x:Key="SystemAccentColorDark2">#ff8f66</Color>
                <Color x:Key="SystemAccentColorDark3">#b33000</Color>
            </ResourceDictionary>
            <!-- ... -->

Here’s how all of this looks like – before and after the template and color changes:
WithoutVisualChanges

WithVisualChanges

Notice that we also moved the whole TreeView control some pixels to the left, to vertically align the chevron icons with the Hamburger button.

Hamburger button

We decided to give the Hamburger button the same size and padding as the system buttons (minimize, maximize, and close) and place it into the title bar in the top left corner. If you place input controls in the title bar, then you should override the default interactive part of the title bar (the part that responds to dragging and double clicking) – otherwise your control will not be reachable.

Here’s the XAML for the top left corner:

<!-- Hamburger Button -->
<Button x:Name="HamburgerButton"
        Margin="0"
        Width="48"
        Height="32"
        <!-- ... -->

<!-- Title Bar -->
<Grid x:Name="AppTitleBar"
        Background="Transparent"
        Height="32"
        VerticalAlignment="Top"
        HorizontalAlignment="Stretch">
    <TextBlock x:Name="AppTitle"
                xmlns:appmodel="using:Windows.ApplicationModel"
                Text="{x:Bind appmodel:Package.Current.DisplayName}"
                Style="{StaticResource CaptionTextBlockStyle}"
                IsHitTestVisible="False"
                Margin="48 8 0 0" />
</Grid>

Here’s how the default title bar zone is overridden:

Window.Current.SetTitleBar(AppTitleBar);

The code behind the Hamburger button is straightforward. It just needs to toggle IsPaneOpen on the SplitView:

/// <summary>
/// Toggles the SplitView pane.
/// </summary>
private void HamburgerButton_Click(object sender, RoutedEventArgs e)
{
    ShellSplitView.IsPaneOpen = !ShellSplitView.IsPaneOpen;
}

Secondary commands

For the secondary commands at the bottom of the navigation panel, we opted for a CommandBar with regular app bar buttons. It’s one of the controls that comes with the Reveal effect built in, and it has the correct size. We considered buttons of the same dimensions as the Hamburger and the system buttons, but this size is to small for buttons that are used often and that have more complex icons.

Navigation

Our focus of the sample app was mainly on the user experience, so we kept the functional part -the navigation itself- as simple as possible. All the related code is placed directly in the Shell page, albeit in a partial class file. In a real-world app you would build a Navigation Service and then find and call it using singletons, dependency injection, service locator, or any other kind of blood magic. For more info, please check my older blog post on SplitView navigation.

To separate at least some of the concerns, we did create a NavigationMenuItem class that allows to define a hierarchic navigation structure (with the destination page type and parameter, and a Children collection):
NavigationMenuItem

Here’s a part of the logical navigation menu in the sample app:

private ObservableCollection<NavigationMenuItem> MainMenu => 
    new ObservableCollection<NavigationMenuItem>
        {
            new NavigationMenuItem
            {
                Text = "Edged Weapons",
                NavigationDestination = typeof(BladesPage),
                Children = new ObservableCollection<MenuItem>
                {
                    new NavigationMenuItem
                    {
                        Text = "Arakh",
                        NavigationDestination = typeof(BladesPage),
                        NavigationParameter = "Arakh"
                    },
                    new NavigationMenuItem
                    {
                        Text = "Dragonglass",
                        NavigationDestination = typeof(BladesPage),
                        NavigationParameter = "Dragonglass"
                    },
                    // ...

The Navigate method uses this information to … well … navigate:

/// <summary>
/// Navigates to the specified source page type.
/// </summary>
public bool Navigate(Type sourcePageType, object parameter = null)
{
    return SplitViewFrame.Navigate(sourcePageType, parameter);
}

When the app starts up, TreeView nodes are created from the menu structure – with a little help from a recursive extension method:

internal static TreeViewNode AsTreeViewNode(this NavigationMenuItem menuItem)
{
    var result = new TreeViewNode
    {
        Content = menuItem
    };

    foreach (NavigationMenuItem subItem in menuItem.Children)
    {
        result.Children.Add(subItem.AsTreeViewNode());
    }

    return result;
}
/// <summary>
/// Populates the TreeView from the Menu.
/// </summary>
private void PopulateTreeView()
{
    // Populate the tree.
    foreach (var item in MainMenu)
    {
        NavigationTree.RootNodes.Add(item.AsTreeViewNode());
    }
}

Each node in the TreeView now has a NavigationMenuItem as its Content, so it knows which page to load and with which parameter. Here’s what happens when a node is clicked:

/// <summary>
/// Navigates to the corresponding treeview selection.
/// </summary>
private void TreeView_ItemInvoked(TreeView sender, TreeViewItemInvokedEventArgs args)
{
    if (args.InvokedItem is TreeViewNode node)
    {
        if (node.Content is NavigationMenuItem menuItem)
        {
            var target = menuItem.NavigationDestination;
            if (target != null)
            {
                Navigate(menuItem.NavigationDestination, menuItem.NavigationParameter);
            }
        }
    }
}

The secondary command buttons call the same method, but without a parameter:

private void SettingsButton_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
{
    Navigate(typeof(SettingsPage));
}

Just to prove that the parameter from the NavigationMenuItem is correctly passed to the Page, here’s how the different pages in the sample app update their subtitle in the top right corner:

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

    base.OnNavigatedTo(e);
}

The Back Button

The hierarchical menu on the left -together with the secondary commands at the bottom- give the user immediate access to any page in the app. So personally we’re not in favor of providing a back button. But just for the sake of completeness, we also implemented it.

This implies a method to navigate back:

/// <summary>
/// Returns to the previous page.
/// </summary>
public void GoBack()
{
    if (SplitViewFrame.CanGoBack)
    {
        SplitViewFrame.GoBack();
    }
}

And you also need to make the system button visible:

/// <summary>
/// Shows the system back button.
/// </summary>
public void EnableBackButton()
{
    var navManager = SystemNavigationManager.GetForCurrentView();
    navManager.AppViewBackButtonVisibility = AppViewBackButtonVisibility.Visible;
    navManager.BackRequested -= (s, e) => GoBack();
    navManager.BackRequested += (s, e) => GoBack();
}

We placed the Hamburger button in the top left corner. When the system back button (dis)appears, we need to shift that button together with the text block holding the app title:

// Update the title bar when the back button (dis)appears or resizes.
Window.Current.CoreWindow.SizeChanged += (s, e) => UpdateAppTitle();
coreTitleBar.LayoutMetricsChanged += (s, e) => UpdateAppTitle();
/// <summary>
/// Updates the title bar when the back button (dis)appears or resizes.
/// </summary>
private void UpdateAppTitle()
{
    var full = (ApplicationView.GetForCurrentView().IsFullScreenMode);
    var left = (full ? 0 : CoreApplication.GetCurrentView().TitleBar.SystemOverlayLeftInset);
    HamburgerButton.Margin = new Thickness(left, 0, 0, 0);
    AppTitle.Margin = new Thickness(left + HamburgerButton.Width + 12, 8, 0, 0);
}

We also added the code to unselect the current TreeView node when the Back or a secondary command button is pressed. Since we weren’t successful in programmatically selecting and unselecting nodes, we applied the old trick of toggling the SelectionMode:

/// <summary>
/// Makes the TreeView lose its selection when there is no corresponding main menu item.
/// </summary>
/// <remarks>This works, but I don't know why...</remarks>
private void SplitViewFrame_OnNavigated(object sender, NavigationEventArgs e)
{
    NavigationTree.SelectionMode = TreeViewSelectionMode.None;
    NavigationTree.SelectionMode = TreeViewSelectionMode.Single;
}

We assumed it would be necessary to add some extra code to determine whether the navigation was triggered by the TreeView or not, before deciding to unselect the current node. It turns out that unconditionally toggling the selection mode seems to do the job already. But honestly: this feels like a coincidence.

NavigationTreeView, first of his name ?

We just created a great looking fluent design compatible TreeView based navigation UI. The development was easier than we expected, and the results look better than we expected. Some of you may be tempted to componentize all of this into a user experience just like the current NavigationView control. We think that this can be done with not too much extra effort, but personally we prefer the more granular control that we have in the sample app.

That sample app lives here on GitHub.

Enjoy!

Advertisements

Displaying Dynamic SQL Results in a UWP DataGrid

In this article we’ll show how you can display the result of any query against a SQL Server database directly in a UWP DataGrid. The grid control that we use is the new Windows Community Toolkit DataGrid. The companion sample app hosts 3 different TSQL queries (feel free to add your own), but only one instance of the DataGrid. Here’s how it looks like:

Grid_1

We’ll show you how to

  • connect to a SQL Server database from UWP,
  • read a dynamic TSQL statement into a DataTable,
  • modify the content of the DataTable progammatically – if needed,
  • bind the DataTable to a DataGrid, and
  • sort the grid on clicking a header column.

This type of dynamic data binding and visualization is particularly useful in the parts of an app that deal with administration, diagnostics, monitoring, or trouble shooting – where you don’t necessarily know upfront which queries to launch and don’t have the possibility (or resources, or priority) to define a full entity model and/or specialized UI controls.

Get that DataGrid

The DataGrid XAML Control is a port from the popular Silverlight control with the same name. Most -but not all- of the functionality has been migrated. This article does NOT focus on its full feature set, but only on dynamic data binding. Please check the official documentation and the source code of a complete sample app for more info. Its documentation is not yet fully uploaded, so some of the hyperlinks in this article will point to the (2011!) Silverlight version.

The DataGrid Control is distributed as a NuGet package within Windows Community Toolkit, currently as a prerelease :

Grid_NuGet

Here’s how the data grid is defined in the sample app. With no columns specified and AutoGenerateColumns to false it is ready for dynamic data binding:

<controls:DataGrid x:Name="ResultsGrid"
                    RowDetailsTemplate="{StaticResource DetailsTemplate}"
                    RowDetailsVisibilityMode="VisibleWhenSelected"
                    CanUserSortColumns="True"
                    Sorting="ResultsGrid_Sorting"
                    BorderThickness="2"
                    BorderBrush="DarkSlateGray"
                    AlternatingRowBackground="BlanchedAlmond"
                    GridLinesVisibility="All"
                    AutoGenerateColumns="False"
                    SelectionMode="Single" />

So let’s create some tabular data.

Populating a DataTable

DataTable is one of the core classes of the ADO.NET library. It represents an in-memory, database-agnostic structure of rows and strongly typed columns. An easy way to populate a DataTable is calling Fill() against a SqlDataAdapter that executes a SqlCommand on a SqlConnection. Here’s how this looks like in the sample app:

using (var connection = new SqlConnection(connectionString))
{
    await connection.OpenAsync();
    var command = connection.CreateCommand();
    command.CommandText = query;
    dataTable = new DataTable();

    using (var dataAdapter = new SqlDataAdapter(command))
    {
        dataAdapter.Fill(dataTable);
    }
}

Defining the DataGrid structure

In WPF, it would suffice to set AutoGenerateColumns to true and then run the following to populate the DataGrid from the DataTable:

ResultsGrid.ItemsSource = dataTable;

[Actually just data binding would even do the trick.]

The Silverlight -and hence UWP- version of the control doesn’t allow this, so there’s a tiny bit more programming required.

We’ll create a list of DataGridTextColumn instances -one for each column in the DataTable- and assign their Header text and and index Binding:

for (int i = 0; i < table.Columns.Count; i++)
{
        grid.Columns.Add(new DataGridTextColumn()
        {
            Header = table.Columns[i].ColumnName,
            Binding = new Binding { Path = new PropertyPath("[" + i.ToString() + "]") }
        });
}

If you would want to rename columns here, or skip some, or add some new ones, then this would be the place to do these changes.

Populating the DataGrid

The DataGrid is now ready to accept content. This content comes from an ObservableCollection that we populate with the ItemArray of each row in the DataTable. The collection is then set as ItemsSource of the DataGrid:

var collection = new ObservableCollection<object>();
foreach (DataRow row in table.Rows)
{
    collection.Add(row.ItemArray);
}

grid.ItemsSource = collection;

Here’s another view on the result. Same grid, same code, different query:

Grid_2

Tweaking the content

In the sample app, we manipulated the content of one of the columns. Some of the queries contain the text of a TSQL query, a long string that may contain visual formatting with tabs, carriage returns and series of blanks. That’s good to display in the details template – which is what we do. For a regular column it makes more sense to truncate the content, and get rid of the carriage returns.

Fortunately it’s easy to iterate through the rows of a DataTable and update one or more of its columns). Here’s how we remove obsolete white space from a string (using a Split() with StringSplitOptions.RemoveEmptyEntries), and truncate the SQL statements:

if (table.Columns.Contains("SQL Statement"))
{
    var column = table.Columns["SQL Statement"];

    foreach (DataRow row in table.Rows)
    {
        string sqlStatement = ((row[column] as string) ?? string.Empty).Trim();
        row[column] = string.Join(' ', sqlStatement.Split(default(string[]), StringSplitOptions.RemoveEmptyEntries)).Substring(0, 80) + "...";
    }

    table.AcceptChanges();
}

The call to AcceptChanges() is not strictly necessary but we do it to save memory. The call locally commits the changes inside the DataTable and clears the –potentially bloated- row versioning information.

Here’s how the sample app looks like for a query that has a “SQL Statement” column. The manipulated value goes to a regular column and the full text appears in the details of the selected row:

Grid_3

Sorting

Last but not least, we implemented the canonical single-column-sorting-on-header-click behavior. This is only enabled when CanUserSort on the column or CanUserSortColumns on the DataGrid is set to true. In the current release, the DataGrid only covers the visual part: it displays an arrow in the column header according the current SortDirection. We have to implement the sort ourselves in a handler hooked to the Sorting event that exposes the column and the sort direction. We set that sort direction for the clicked column and reset I for the others:

var currentSortDirection = e.Column.SortDirection;

foreach (var column in ResultsGrid.Columns)
{
    column.SortDirection = null;
}

var sortOrder = "ASC";

if ((currentSortDirection == null || currentSortDirection == DataGridSortDirection.Descending))
{
    e.Column.SortDirection = DataGridSortDirection.Ascending;
}
else
{
    sortOrder = "DESC";
    e.Column.SortDirection = DataGridSortDirection.Descending;
}

Then we sort the content itself. We assign the Sort property of the DataTable’s DefaultView, transform the resulting DataView back to a DataTable, and update the binding:

var dataView = dataTable.DefaultView;
dataView.Sort = e.Column.Header + " " + sortOrder;
dataTable = dataView.ToTable();

RefreshContents(dataTable, ResultsGrid);

Code

The sample app lives here on GitHub. When playing with it, don’t forget to bring your own connection string to MainPage.xaml.cs.

Enjoy!

How to build a SQL Connection Dialog in UWP

This article explains how to build a dialog in UWP that sets up a connection from your app to any SQL Server database on your network or in the cloud. Since the Windows Fall Creators Update we can -finally- directly connect to SQL Server from UWP. In that SDK .net core was extended with a large portion of the object model of ye olde ADO.NET, hosted in the System.Data.SqlClient namespace. In this article we’ll use some of these to build a connection dialog to SQL Server, with the following features:

  • You can type a server name or select a recently use one.
  • You can select the security mode.
  • You can enter your credentials when SQL Authentication is used.
  • You can select the database from a list.
  • You have direct access to the connection string.
  • You can test the connection.

When the dialog closes, it will serve you with a validated connection string (unless you cancelled the operation).

Here’s how the dialog looks like in its default mode, with different input fields:

SqlDialogDefaultInput

And here’s how it looks like in direct access mode, where you can edit the connection string:

SqlDialogDirectInput

Basic structure

The SQL Connection Dialog is based on a ContentDialog. Under the title (which has a nice SVG Icon – thanks to TheNounProject) there’s a ProgressBar from which we toggle the IsIndeterminate property to indicate whether the control is busy – i.e. establishing a connection or fetching the database names. The first row in the input form is a custom editable combobox for the server name. Then come some regular input controls –ComboBox, TextBox, PasswordBox– for the security parameters. At the bottom of the input zone there’s a ComboBox that hosts the names of the databases. All text fields on the input form have their IsSpellCheckEnabled set to false – we assume you don’t want red squigglies under server names or user accounts.

All input fields are bound to properties of a SqlConnectionBuilder. As an example, here’s the code for the UserId field:

private SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder();
private string userId;

/// <summary>
/// Gets or sets the SQL user identifier.
/// </summary>
public string UserId
{
    get { return userId; }
    set
    {
        userId = value;
        builder.UserID = userId;
        OnPropertyChanged();
    }
}

And its corresponding XAML:

<TextBox Text="{x:Bind UserId, Mode=TwoWay}"
         IsEnabled="{x:Bind SqlSecurity, Mode=OneWay}" />

The ellipsis button in the top left corner sets the control in direct input mode, showing a large multi-row textbox to manipulate the connection string.

A ContentDialog can have maximum three buttons at the bottom, and we’re using all of these. The PrimaryButton allows to test the current connectionstring, the SecondaryButton returns a validated connectstring to the caller and closes the dialog, and the CloseButton … well … closes.

An Editable ComboBox

The name of the server to connect to can be chosen from a dropdown with recently used successful connections (stored in LocalSettings) or it can be typed in manually. Now UWP does not come with an editable ComboBox, so we needed to simulate one through an AutoSuggestBoxToggleButton combination. The toggle button opens the AutoSuggestBox’s dropdown. Here’s the XAML:

<AutoSuggestBox x:Name="SuggestBox"
                Style="{StaticResource AutoSuggestBoxNoSpellCheckingStyle}"
                Text="{x:Bind Server, Mode=TwoWay}"
                ItemsSource="{x:Bind MostRecentConnections}"
                VerticalAlignment="Stretch"
                IsSuggestionListOpen="{Binding IsChecked, ElementName=Toggle, Mode=TwoWay}"
                FontFamily="Segoe UI" />
<ToggleButton x:Name="Toggle"
                Grid.Column="1"
                VerticalAlignment="Stretch"
                Width="32"
                Background="Transparent"
                FontFamily="Segoe UI">
    <FontIcon Foreground="{ThemeResource ComboBoxDropDownGlyphForeground}"
                FontSize="12"
                FontFamily="Segoe MDL2 Assets"
                Glyph=""
                IsHitTestVisible="False" />
</ToggleButton>

A few classes from .NET SQL Server ecosystem were not ported to .net core. One of these is SqlDataSourceEnumerator, which allows to lookup SQL Server instances on the local network. So we can’t do this on UWP.

Maintaining the size

The UWP ContentDialog is quite stubborn when it comes to setting and resetting its size. It prefers to decide its height and width depending on its children and its host, and tends to ignore hard-coding values. We decided not to fight the dialog, and let it define its own size – based on the default look with the multiple input fields. But we don’t want the dialog to shrink when switching to direct input mode (with only one textbox). All the content is always in place so the dialog never feels the need to resize. We’re just playing with Opacity and Z-Order when switching the mode. A Grid has no ZIndex attached property for its content, so we reverse the Children collection instead. Here’s what happens when we switch from default mode to direct mode:

DefaultGrid.Opacity = 1;
DirectGrid.Opacity = 0;
Host.Children.Remove(DirectGrid);
Host.Children.Insert(0, DirectGrid);

Of course there’s similar code the other way around. It keeps the dialog the same size, and it freezes the mode switch button at its position, making it easy to rapidly check the connection string and come back.

Testing the connection

For testing the connection, we create a SqlConnection instance from the current connection string, and try to Open it:

using (SqlConnection con = new SqlConnection(builder.ConnectionString))
{
    await con.OpenAsync();
}

We’re updating the UI during the call (remember there’s a ProgressBar), so it’s a good idea to use OpenAsync here. The Using statement will make sure that we close the connection automatically.

When the connection is successful, we’ll show it to the user, with a MessageDialog:

SqlDialogTest

And when the connection is not successful, we display the error:

SqlDialogTestFail

Fetching the database list

The list of database names on a SQL Server Instance can only be fetched through a successful connection to the server. Knowing that every unsuccessful connection attempt waists at least a few seconds, we don’t want to try to connect on every property change. The list of databases is fetched in the combo box’s own DropDownOpened event:

<ComboBox x:Name="DatabaseComboBox"
          DropDownOpened="DatabaseComboBox_DropDownOpened"
          ItemsSource="{x:Bind Databases, Mode=OneWay}"
          SelectionChanged="Database_SelectionChanged" />

Here’s the code. We create a new SqlCommand on the open connection, execute it, and loop though the result with a SqlDataReader:

using (var connection = new SqlConnection(builder.ConnectionString))
{
    await connection.OpenAsync();

    using (var command = connection.CreateCommand())
    {
        command.CommandText = "SELECT [name] FROM sys.databases ORDER BY [name]";

        using (SqlDataReader reader = await command.ExecuteReaderAsync())
        {
            while (await reader.ReadAsync())
            {
                databases.Add(reader.GetString(0));
            }
        }
    }
}

Again, we used the asynchronous versions of the operations (ExecureReaderAsync and ReadAsync) to keep the UI responsive.

Achievement unlocked: connected

When the user clicks the Connect button, we validate the current connection string in just the same way as for the Test button. If the connection is successful, we store the current server name of top of the most recent servers – the list that appears in the editable combobox on top. Then we assign the dialog’s ConnectionString property for the caller to grab. As mentioned, the SqlConnectionDialog does not return a connection, but a validated connection string:

try
{
    using (SqlConnection con = new SqlConnection(builder.ConnectionString))
    {
        await con.OpenAsync();
    }

    MostRecentConnection = Server;
    ConnectionString = builder.ConnectionString;
}

How to use it

Here’s how a client app uses the dialog. It opens the dialog, waits for the result, checks whether the user cancelled or not, and finally grabs the connection string:

var dialog = new ConnectionDialog();
var result = await dialog.ShowAsync();

// User Cancelled
if (result == ContentDialogResult.None)
{
    return;
}

var connectionString = dialog.ConnectionString;

The sample client app uses the provided connection string to fetch the list of tables from the select database with their number of rows:

SqlDialogResult

The sample app with the SqlConnectionDialog lives here on GitHub.

Enjoy!

Printing with the UWP Community Toolkit

In this article we describe some advanced printing scenarios on top of the PrintHelper from the UWP Community Toolkit. This helper is specialized in interacting with the built-in print dialogs, and in printing one UI element on one page. The latter sounds pretty limited, but in the next couple of paragraphs we’ll show things like

  • wrapping the helper in an MVVM service,
  • adding a header and/or a footer to the print pages,
  • adding page numbers to the print pages,
  • printing a list of items, each on its own page, and
  • printing a more complex report.

That should suffice for most UWP apps that have printing on their list of requirements – basically all apps that don’t need dynamic page breaks.

As usual, there’s a sample app on GitHub. It comes with several pages with a large ‘Print’ button:

 ContentPage

Here are the main classes in that sample app:

  • Content pages: the app’s pages that provide content and layout of the information to be printed,
  • PrintService: a class that provides printing-as-a-service in an MVVM architecture,
  • PrintPage: a helper class that prepares the print content (a FrameworkElement) with header, footer, and page numbering, and
  • PrintHelper: the toolkit’s print helper that knows how to print a FrameworkElement on a single page.

Here’s a class diagram of the core print engine:

ClassDiagram1

Creating an MVVM PrintService

The Print Service is the central place to which the different content pages send the elements to be printed:

  • one header, one footer, and one place to put the page for the entire job, and
  • one main content per individual print page.

The service registers the handlers for the system print dialog events (to deal with success, failure, or cancellation), manipulates the content through the smart PrintPage (see further), and hands the result over to the toolkit PrintHelper.

Printing XAML –with or without the PrintHelper- requires the XAML elements to be rendered on an invisible panel in your Visual Tree before they’re moved to separate print preview pages in the system print dialog. Your app needs to provide that invisible panel.

In an MVVM environment the so-called Shell (the page that hosts the navigation panel) is an ideal place to host this panel. We’ll call it the PrintingContainer:

    <Grid>
        <!-- Required for the PrintService -->
        <Grid x:Name="PrintingContainer"
              Opacity="0" />

        <!-- SplitView -->
        <SplitView x:Name="SplitView"
        <!-- ... -->
        </SplitView>

        <!-- Hamburger Button -->
        <Button x:Name="HamburgerButton">
        <!-- ... -->
        </Button>
    </Grid>

When the app starts, it provides this field to the central print service:

// Initialize Printing Service.
PrintService.PrintingContainer = PrintingContainer;

The PrintService class takes a Header, Footer and PageNumbering property. For the rest it host all the code for working with the UWP Community Toolkit’s PrintHelper class that you find in the official documentation. In the Print method you see that the service creates a PrintPage (see further) for each page to be sent to the PrintHelper. The print service protects the content pages from all that knowledge.

Here’s the whole class:

public class PrintService
{
    private static Panel _printingContainer;

    private PrintHelper _printHelper;
    private List<FrameworkElement> _content = new List<FrameworkElement>();
    private FrameworkElement _header;
    private FrameworkElement _footer;
    private PageNumbering _pageNumbering = PageNumbering.None;

    public PrintService()
    {}

    public static Panel PrintingContainer
    {
        set { _printingContainer = value; }
    }

    public FrameworkElement Header
    {
        set { _header = value; }
    }

    public FrameworkElement Footer
    {
        set { _footer = value; }
    }

    public PageNumbering PageNumbering
    {
        set { _pageNumbering = value; }
    }

    public void AddPrintContent(FrameworkElement content)
    {
        _content.Add(content);
    }

    public void Print()
    {
        _printHelper = new PrintHelper(_printingContainer);

        PrintPage.StartPageNumber = 1;
        foreach (var content in _content)
        {
            var page = new PrintPage(content, _header, _footer, _pageNumbering);
            _printHelper.AddFrameworkElementToPrint(page);
        }

        _printHelper.OnPrintFailed += printHelper_OnPrintFailed;
        _printHelper.OnPrintSucceeded += printHelper_OnPrintSucceeded;
        _printHelper.OnPrintCanceled += printHelper_OnPrintCanceled;

        _printHelper.ShowPrintUIAsync("Print Sample");
    }

    private void printHelper_OnPrintCanceled()
    {
        ReleasePrintHelper();
    }

    private void printHelper_OnPrintSucceeded()
    {
        Toast.ShowInfo("Printed.");
        ReleasePrintHelper();
    }

    private void printHelper_OnPrintFailed()
    {
        Toast.ShowError("Sorry, printing failed.");
        ReleasePrintHelper();
    }

    private void ReleasePrintHelper()
    {
        _printHelper.Dispose();
    }
}

Here’s how a successful print notification looks like, in the sample app:

Notification

Adding headers and footers

The main job of the PrintPage class in the sample app is to transform all print content for a single page (main content, header, footer, page numbering) into a single FrameworkElement, since the toolkit’s PrintHelper only accepts single FrameworkElement instances to be printed.

The PrintPage takes all print content and lays it out in a 3-row Grid (header – main beef – content):

Grid _printArea;

public PrintPage(FrameworkElement content, FrameworkElement header = null, FrameworkElement footer = null, PageNumbering pageNumbering = PageNumbering.None)
{
    _printArea = new Grid();
    _printArea.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
    _printArea.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Star) });
    _printArea.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
    _printArea.Children.Add(new Canvas() { Width = 10000 }); // Horizontally stretches the Grid.

    Content = _printArea;

    AddContent(content);
    Header = header;
    Footer = footer;
}

When the Header is assigned, it is immediately cloned -because it will possibly be used on multiple page instances- and placed in the top row of the grid:

public FrameworkElement Header
{
    set
    {
        if (value != null)
        {
            var header = value.DeepClone();
            Grid.SetRow(header, 0);
            _printArea.Children.Add(header);
        }
    }
}

The header and footer are cloned because they will appear on each page in the print job and a UI element can only have one parent. I would have preferred to use a XamlWriter to transform the element into a XAML string, and then a XamlReader to instantiate a clone from this XAML. Unfortunately XamlWriter does not exist in UWP, so we have to rely on reflection.

The DeepClone method that we’re using, is all over the internet – it’s impossible to find the original source. It checks the origin type, creates a new instance from it, and then recursively clones its properties (except the Name) and children.

Here’s how the first content page in the sample app talks to the print service – instantiate, assign header and footer, add print pages, call Print method:

var service = new PrintService();

// Define Header, Footer, and Page Numbering.
service.Header = new TextBlock() { Text = "Header", Margin = new Thickness(0, 0, 0, 20) };
service.Footer = new TextBlock() { Text = "Footer", Margin = new Thickness(0, 20, 0, 0) };
service.PageNumbering = PageNumbering.TopRight;

// Add three pages.
service.AddPrintContent(new TextBlock() { Text = "Hello World!" });
service.AddPrintContent(new Image() { Source = new BitmapImage(new Uri("ms-appx:///Assets/world.png")) });
service.AddPrintContent(new TextBlock() { Text = "Goodbye World!" });

service.Print();

Adding page numbering

Once we know how to add a header and a footer to the print pages, adding page numbers is trivial. Let’s start with defining an enumeration for page number positions:

public enum PageNumbering
{
    None,
    TopLeft,
    TopMiddle,
    TopRight,
    BottomLeft,
    BottomMidle,
    BottomRight
}

Each time we add a new print page to the print job with AddContent(), we check if a page number is required. If so, we increment the value and place a TextBlock in the appropriate place (be careful: the page number will appear in row 0 or 2 of the print page grid, so it may clash with header or footer – it’s up to you to avoid this):

public void AddContent(FrameworkElement content)
{
    Grid.SetRow(content, 1);
    _printArea.Children.Add(content);

    if (PageNumbering != PageNumbering.None)
    {
        _pageNumber += 1;
        var pageNumberText = new TextBlock() { Text = _pageNumber.ToString() };

        switch (PageNumbering)
        {
            case PageNumbering.None:
                break;
            case PageNumbering.TopLeft:
                Grid.SetRow(pageNumberText, 0);
                pageNumberText.Margin = new Thickness(0, 0, 0, 20);
                _printArea.Children.Add(pageNumberText);
                break;
            case PageNumbering.TopMiddle:
                Grid.SetRow(pageNumberText, 0);
                pageNumberText.Margin = new Thickness(0, 0, 0, 20);
                pageNumberText.HorizontalAlignment = HorizontalAlignment.Stretch;
                pageNumberText.HorizontalTextAlignment = TextAlignment.Center;
                _printArea.Children.Add(pageNumberText);
                break;
            case PageNumbering.TopRight:
                Grid.SetRow(pageNumberText, 0);
                Grid.SetColumn(pageNumberText, 1);
                pageNumberText.Margin = new Thickness(0, 0, 0, 20);
                pageNumberText.HorizontalAlignment = HorizontalAlignment.Stretch;
                pageNumberText.HorizontalTextAlignment = TextAlignment.Right;
                _printArea.Children.Add(pageNumberText);

                break;
            case PageNumbering.BottomLeft:
                Grid.SetRow(pageNumberText, 2);
                pageNumberText.Margin = new Thickness(0, 20, 0, 0);
                _printArea.Children.Add(pageNumberText);
                break;
            case PageNumbering.BottomMidle:
                Grid.SetRow(pageNumberText, 2);
                pageNumberText.Margin = new Thickness(0, 20, 0, 0);
                pageNumberText.HorizontalAlignment = HorizontalAlignment.Stretch;
                pageNumberText.HorizontalTextAlignment = TextAlignment.Center;
                _printArea.Children.Add(pageNumberText);
                break;
            case PageNumbering.BottomRight:
                Grid.SetRow(pageNumberText, 2);
                pageNumberText.Margin = new Thickness(0, 20, 0, 0);
                _printArea.Children.Add(pageNumberText);
                break;
            default:
                break;
        }
    }
}

Here’s how all of this looks like at runtime in the sample app:

HeaderFooterPageNumbers

Printing a list on separate pages

Maybe your app needs to print a collection of items, typically displayed through some kind of ItemsControl. The UWP Community Toolkit’s PrintHelper can’t do dynamic page breaks, so we’ll start each item on a new page.

The print content instances are created from a DataTemplate, like this:

<Page.Resources>
    <DataTemplate x:Name="MoonTemplate">
        <StackPanel>
            <TextBlock Text="{Binding Name}"
                        FontSize="48"
                        Margin="60" />
            <Image Source="{Binding ImagePath}"
                    Margin="120 0" />
        </StackPanel>
    </DataTemplate>
</Page.Resources>

To print the collection, just iterate through it and create a ContentControl for each item, load the data template in its ContentTemplate, assign the DataContext to update all bindings, and add the new content to the print job:

var service = new PrintService();
service.Header = new TextBlock { Text = "List of items with page break" };
service.PageNumbering = PageNumbering.BottomMidle;

foreach (var moon in Moons)
{
    // The secret is to NOT use an ItemsControl.
    var cont = new ContentControl();
    cont.ContentTemplate = Resources["MoonTemplate"] as DataTemplate;
    cont.DataContext = moon;
    service.AddPrintContent(cont);
}

service.Print();

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

ListItems

Printing a report

Maybe your app has a more or less complex dashboard page, with different texts and images, and controls like gauges and diagrams. That page may have a background image, light text on a dark background, and/or a horizontal layout. So it’s probably not a very good idea to emulate a screenshot and send that page as-is to a printer. For printed reports we expect a white background, probably no background images, and a vertical (portrait) layout. But we still want to reuse as much as possible XAML elements in both ‘pages’. So we’re going to rely on data templates again.

Some data templates can be very simple, like this one that just displays an image:

<DataTemplate x:Name="ImageTemplate">
    <Image Source="{Binding ImagePath}"
            Stretch="Uniform"
            Margin="0" />
</DataTemplate>

But they can also be a bit more complex, like this grid that hosts a list of characteristics:

<DataTemplate x:Name="CharacteristicsTemplate">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="auto" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto" />
            <RowDefinition Height="auto" />
            <RowDefinition Height="auto" />
            <RowDefinition Height="auto" />
            <RowDefinition Height="auto" />
        </Grid.RowDefinitions>
        <TextBlock Text="Planet"
                    FontWeight="SemiBold"
                    HorizontalAlignment="Right"
                    Margin="0 0 10 10" />
        <TextBlock Text="{Binding Planet}"
                    Margin="10 0 0 10"
                    Grid.Column="1" />
        <TextBlock Text="Mass"
                    FontWeight="SemiBold"
                    HorizontalAlignment="Right"
                    Margin="0 0 10 10"
                    Grid.Row="1" />
        <TextBlock Text="{Binding Mass}"
                    Margin="10 0 0 10"
                    Grid.Row="1"
                    Grid.Column="1" />
        <TextBlock Text="Albedo"
                    FontWeight="SemiBold"
                    Margin="0 0 10 10"
                    HorizontalAlignment="Right"
                    Grid.Row="2" />
        <TextBlock Text="{Binding Albedo}"
                    Margin="10 0 0 10"
                    Grid.Row="2"
                    Grid.Column="1" />
        <TextBlock Text="Orbital Eccentricity"
                    FontWeight="SemiBold"
                    HorizontalAlignment="Right"
                    Margin="0 0 10 10"
                    Grid.Row="3" />
        <TextBlock Text="{Binding OrbitalEccentricity}"
                    Margin="10 0 0 10"
                    Grid.Row="3"
                    Grid.Column="1" />
    </Grid>
</DataTemplate>

Here’s the horizontal layout of the dashboard page in the sample app. It gets its details from the different data templates:

<ListView SelectionMode="None"
            ScrollViewer.HorizontalScrollMode="Enabled"
            ScrollViewer.IsHorizontalRailEnabled="True"
            ScrollViewer.HorizontalScrollBarVisibility="Auto"
            Grid.Row="1">
    <ListView.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
    </ListView.ItemsPanel>
    <Grid Height="500"
            Width="500">
        <ContentControl DataContext="{x:Bind SelectedMoon}"
                        ContentTemplate="{StaticResource ImageTemplate}" />
    </Grid>
    <Grid Height="500"
            Width="500">
        <ContentControl DataContext="{x:Bind SelectedMoon}"
                        ContentTemplate="{StaticResource DescriptionTemplate}" />
    </Grid>
    <Grid Height="500"
            Width="250">
        <ContentControl DataContext="{x:Bind SelectedMoon}"
                        ContentTemplate="{StaticResource CharacteristicsTemplate}" />
    </Grid>
    <Grid Height="500"
            Width="500">
        <ContentControl DataContext="{x:Bind Moons}"
                        ContentTemplate="{StaticResource BarChartTemplate}" />
    </Grid>
</ListView>

Here’s the template for the vertical print page. It reuses as much of these data templates as possible, but it hangs these in a container with a different look. The data template for the report is in the page’s resources:

<DataTemplate x:Name="ReportTemplate">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto" />
            <RowDefinition Height="auto" />
            <RowDefinition Height="auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <TextBlock DataContext="{Binding SelectedMoon}"
                    Text="{Binding Name}"
                    FontSize="36"
                    Margin="0 10"
                    Grid.ColumnSpan="2" />
        <ContentControl DataContext="{Binding SelectedMoon}"
                        ContentTemplate="{StaticResource ImageTemplate}"
                        Margin="0 0 10 10"
                        Grid.Row="1" />
        <TextBlock DataContext="{Binding SelectedMoon}"
                    Text="{Binding Description}"
                    TextWrapping="Wrap"
                    Margin="10 0 0 10"
                    Grid.Row="1"
                    Grid.Column="1" />
        <ContentControl DataContext="{Binding SelectedMoon}"
                        ContentTemplate="{StaticResource CharacteristicsTemplate}"
                        HorizontalAlignment="Center"
                        Margin="0 0 10 10"
                        Grid.Row="2" />
        <ContentControl RequestedTheme="Dark"
                        DataContext="{Binding Moons}"
                        ContentTemplate="{StaticResource BarChartTemplate}"
                        HorizontalAlignment="Center"
                        Margin="0 0 0 0"
                        Grid.ColumnSpan="2"
                        Grid.Row="3" />
    </Grid>
</DataTemplate>

I also added an example of reusing a more advanced control – a Telerik BarChart. I had to hard code the color scheme (blue with a black border) for the bars, because by default they became white or transparent in the print page:

<DataTemplate x:Name="BarChartTemplate">
    <telerikChart:RadCartesianChart>
        <telerikChart:RadCartesianChart.VerticalAxis>
            <telerikChart:LinearAxis Minimum="0"
                                        Maximum="1"
                                        Title="Albedo"
                                        FontFamily="Segoe UI" />
        </telerikChart:RadCartesianChart.VerticalAxis>
        <telerikChart:RadCartesianChart.HorizontalAxis>
            <telerikChart:CategoricalAxis />
        </telerikChart:RadCartesianChart.HorizontalAxis>
        <telerikChart:BarSeries ItemsSource="{Binding}">
            <telerikChart:BarSeries.DefaultVisualStyle>
                <Style TargetType="Border">
                    <Setter Property="Background"
                            Value="DodgerBlue" />
                    <Setter Property="BorderBrush"
                            Value="Black" />
                    <Setter Property="BorderThickness"
                            Value="1" />
                </Style>
            </telerikChart:BarSeries.DefaultVisualStyle>
            <telerikChart:BarSeries.CategoryBinding>
                <telerikChart:PropertyNameDataPointBinding PropertyName="Name" />
            </telerikChart:BarSeries.CategoryBinding>
            <telerikChart:BarSeries.ValueBinding>
                <telerikChart:PropertyNameDataPointBinding PropertyName="Albedo" />
            </telerikChart:BarSeries.ValueBinding>
        </telerikChart:BarSeries>
    </telerikChart:RadCartesianChart>
</DataTemplate>

Here are the two pages, in the sample app:

DashboardToReport

In this article we showed some easy tricks to create more complex print jobs on top of the UWP Community Toolkit. If your app needs more complexity than this, then I would suggest to take a look at my dynamic page-break solution or let your app expose its information through PDF or HTML.

The sample app lives here on GitHub.

Enjoy!

How to enumerate all installed fonts on UWP

In this article we’ll show you how a UWP app can detect and enumerate all the installed fonts on the device, and how to apply a selected font to a UI element.

It’s all extremely easy – if you know which NuGet package to use:

Win2D_UWP

Win2D is a Windows Runtime API wrapper on Direct2D that is specialized in rendering 2D graphics using hardware acceleration.

Win2D comes with API calls and XAML helper controls for:

  • manipulating and rendering bitmaps,
  • manipulating vector graphics,
  • applying color effects and filters,
  • converting text to geometry, et cetera.

If you want to dive deeper into Win2D then checkout these features and UWP samples.

Once you’re referencing the Win2D.UWP NuGet package, enumerating the installed fonts on the device is literally a one-liner. Just call the GetSystemFontFamilies on the CanvasTextFormat class. It returns the (localized!) font names as an array of strings:

public List<string> Fonts
{
    get
    {
        return CanvasTextFormat.GetSystemFontFamilies().OrderBy(f => f).ToList();
    }
}

To display these in a ComboBox, assign the list to its ItemsSource:

<ComboBox x:Name="FontsCombo"
            ItemsSource="{x:Bind Fonts}"
            SelectionChanged="FontsCombo_SelectionChanged">
    <!---... -->
</ComboBox>

When the ComboBox’s selection changes, we update the font of a TextBox. Provide the font name string to the FontFamily constructor to set the FontFamily dependency property:

private void FontsCombo_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    TextEditor.FontFamily = new FontFamily(FontsCombo.SelectedValue.ToString());
}

In the ComboBox’s item template, I used x:Bind to provide both the FontFamily and Text for the TextBlock (don’t forget to specify the item type with x:DataType).

<ComboBox.ItemTemplate>
    <DataTemplate x:DataType="x:String">
        <TextBlock FontFamily="{x:Bind}"
                    Text="{x:Bind}" />
    </DataTemplate>
</ComboBox.ItemTemplate>

Done!

Here’s how all of this looks like at runtime:

ScreenShot

The sample app lives here on GitHub.

Enjoy!

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!

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!