Getting started with the Telerik RadDataGrid on UWP

This article explains how to get started with the Telerik RadDataGrid for UWP. RadDataGrid is a tabular control with a long history (in different technology stacks including Windows Forms, WPF, and HTML) and a rich API. It displays a list of items and supports customizable columns, single and multi-column sorting, data editing, grouping, selection, filtering and so on. XAML-wise you may consider RadDataGrid as the successor of the DataGrid in WPF.

In this article we’ll focus on templating, sorting, filtering, and grouping. I built a small sample that displays a list of racing drivers with some of their properties (name, team, nationality, experience, …). As an end user of this app you can

  • change the order of the columns,
  • select which columns to display or hide,
  • sort the list on column values,
  • filter the list on column values and,
  • group list entries on column values.

Here’s how the app looks like:

Overview

RadDataGrid is part of the Telerik UI for UWP toolkit. Its source code is available for free (!) here on GitHub, the binaries are available through NuGet. For an overview of the RadDataGrid features –but without source code- check the corresponding Telerik web page. You can also download their sample Store App. It looks like this, but unfortunately again, there’s no source code available:

TelerikStoreApp

The official documentation for Telerik UI for UWP is here, and the starting point for the RadDataGrid documentation is right here. As already mentioned, the focus of this article is data visualisation (read-only). If you’re looking for an example of editing and validation, then you better check this example from Microsoft.

Off we go

First you need to install the NuGet package in your app:

NuGetPackage

On the page that’s going to host the RadDataGrid, define the necessary namespaces:

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      ...
      xmlns:grid="using:Telerik.UI.Xaml.Controls.Grid"
      xmlns:core="using:Telerik.Data.Core">

Then you just create a RadDataGrid XAML element on it. For a quick result, you can set AutoGenerateColumns to true. A default column will be created for each property in the ItemsSource’s item class.

A transparent background and no border or gridlines give the control a nice Windows 10-look. I also prefer to always display the column resize handlers – the double vertical lines in the column header. They look good and they’re really handy on a touch screen. For more details, check the properties and configurations and the visual structure documentation pages.

Here’s my initial control definition for the racing drivers grid:

<grid:RadDataGrid ItemsSource="{x:Bind ViewModel.Drivers}"
                    AutoGenerateColumns="True"
                    Background="Transparent"
                    BorderBrush="Transparent"
                    GridLinesVisibility="None"
                    CanUserChooseColumns="True"
                    ColumnResizeHandleDisplayMode="Always">

Here’s how it looks like at runtime:

AutoGenerateColumns

Default Column types

If you’re not auto-generating the columns, then you need to specify the column list yourself. RadDataGrid comes with different column types, including a set of types that allow visualization as well as editing and validation of String, Boolean, Date, Image, Numerical and Time properties, and for selection from a ComboBox. Here’s an example of a DataGridTextColumn and a DataGridDateColumn, each bound to a property in the itemssource.

As you see, you can apply your own header text, and formatting:

<grid:RadDataGrid.Columns>
    <grid:DataGridTextColumn PropertyName="Name"
                                Header="Name" />
    <!-- ... -->
    <grid:DataGridDateColumn PropertyName="MostRecentVictory"
                                Header="Last win"
                                CellContentFormat="{}{0:d}" />
    <!-- ... -->
</grid:RadDataGrid.Columns>

Template Columns

If you want complete control over the look and feel of a column, then you have to use a DataGridTemplateColumn. This allows you to provide your own data template. Here’s an example of two templated columns – the first one uses a Rating Control to visualize the the experience level (from an enumeration), the second one uses an icon to represent a Boolean value:

<grid:DataGridTemplateColumn Header="Experience">
    <grid:DataGridTemplateColumn.CellContentTemplate>
        <DataTemplate>
            <controls:Rating Maximum="5"
                                Value="{Binding ExperienceAsNumber}"
                                EmptyImage="ms-appx:///Assets/RatingIcons/wreath_empty.png"
                                FilledImage="ms-appx:///Assets/RatingIcons/wreath_full.png"
                                IsInteractive="False"
                                ItemHeight="24" />
        </DataTemplate>
    </grid:DataGridTemplateColumn.CellContentTemplate>
</grid:DataGridTemplateColumn>
<!-- No customization possible :-(-->
<!--<grid:DataGridBooleanColumn Header="Active"
            PropertyName="IsStillActive" />-->
<grid:DataGridTemplateColumn Header="Active">
    <grid:DataGridTemplateColumn.CellContentTemplate>
        <DataTemplate>
            <Path Data="{StaticResource SteeringWheelIcon}"
                    VerticalAlignment="Center"
                    HorizontalAlignment="Center"
                    Height="20"
                    Width="20"
                    Fill="{Binding IsStillActive, Converter={StaticResource BooleanToBrushConverter}}"
                    Stretch="Uniform" />
        </DataTemplate>
    </grid:DataGridTemplateColumn.CellContentTemplate>
</grid:DataGridTemplateColumn>

Sorting

According to the classic paradigm (and hence the user’s expectations) columns can be sorted by clicking on the column header. When clicking on the header of a column that is already sorted, the rows will iterate to the next stage: from sorted ascending, to sorted descending, and back to its original order (I love this last ‘unsort’ stage, it demonstrates the maturity of the API).

The built-in default column types enable sorting out of the box: they know to which property they’re bound –through PropertyName– and the underlying data types are all IComparable.

For templated columns, you need to explicitly declare that the user can sort the column via CanUserSort. Since such a column isn’t necessarily bound to a property, you have to provide a SortDescriptor yourself. Here’s how I defined that the column with the steering wheel icon can be sorted on the IsStillActive property of the racing driver class:

<grid:DataGridTemplateColumn Header="Active"
                                CanUserSort="True">
    <grid:DataGridTemplateColumn.SortDescriptor>
        <core:PropertySortDescriptor PropertyName="IsStillActive" />
    </grid:DataGridTemplateColumn.SortDescriptor>
    <grid:DataGridTemplateColumn.CellContentTemplate>
        <!-- ... -->
    </grid:DataGridTemplateColumn.CellContentTemplate>
</grid:DataGridTemplateColumn>

As you would expect, a sorted column is decorated with a triangle in its header. Here’s the sample data grid, reverse alphabetically sorted by the Name column:

Sorting

Filtering

Columns headers can be decorated with a control that allows filtering. Here’s how to enable this feature:

<grid:RadDataGrid ItemsSource="{x:Bind ViewModel.Drivers}"
                    AutoGenerateColumns="False"
                    UserFilterMode="Enabled">

With UserFilterMode enabled, all non-templated columns are decorated with a filter icon. When that icon is clicked, a data type specific mini UI pops open, and allows the user to specify a filter to apply on the column values. When the filter is activated, the rows that don’t comply disappear, and the column header is underlined to visually indicate that a filter is in place. Here’s how all of this looks like in the sample app. We’re filtering the drivers with their name ending on ‘son’:

Filtering

As mentioned, the filter UI is specific to the data type of the column. Here’s a screenshot of the date filter on the ‘most recent victory’ property:

FilterOnDate

If you want, you can even create your own custom filter UI control. And for the sake of completeness: filters can also be applied programmatically.

Grouping

The most powerful feature in the RadDataGrid is grouping: the ability to let the user group the data by column values. All the user needs to do is drag a column header to the grouping bar at the left.

Again it is a feature that you have to enable:

<grid:RadDataGrid ItemsSource="{x:Bind ViewModel.Drivers}"
                    ...
                    UserGroupMode="Enabled">

You can then selectively turn it of again, e.g. for columns with relatively unique values, like the Name in the sample app:

<grid:DataGridTextColumn PropertyName="Name"
                            Header="Name"
                            CanUserGroup="False" />

For template-type columns, you need to specify the property name and the group name through a GroupDescriptor. Here’s how I allow grouping on the values in the Active column:

<grid:DataGridTemplateColumn Header="Active">
    <grid:DataGridTemplateColumn.GroupDescriptor>
        <core:PropertyGroupDescriptor PropertyName="ActiveDescription"
                                        DisplayContent="Active" />
    </grid:DataGridTemplateColumn.GroupDescriptor>
    <!-- ... -->
</grid:DataGridTemplateColumn>

I did not not want to show true and false in the group header, so I created a new property in the racing driver class. This is not the only property that I defined just for the data grid, but after all, that’s what ViewModels are made for:

public string ActiveDescription => IsStillActive ? "Active" : "Retired";

When the icon on top of the grouping bar is clicked, a panel slides open that allows to change the nesting order, sort the group headers, and remove columns from the grouping hierarchy. Here’s how the UI looks like in the sample app. We group the drivers by nationality, and then ungroup again:

Grouping

When user grouping is enabled, it also makes sense to enable column selection. After all, the user will want to hide the columns on which the data is grouped on – their values are already displayed in the group headers. Column selection is enabled through the CanUserChooseColumns property. It displays a triangular button in the top right corner that triggers a panel with a checkbox for all the columns:

ColumnSelection

Combining the features

All RadDataGrid features (sorting, grouping, filtering) can be combined. Here’s the grid from the sample app, sorted and filtered by name and grouped by nationality of the driver:

GroupedFiltering

Theming

Every part of the RadDataGrid is themeable, but some parts are easier than other. Telerik provides the classic light and dark theme resources (different shades of grey, and an accent color). They also provide a UserThemeResource markup extension that enables you to easily override resources. Just create your own theme and register it, like this:

<ResourceDictionary.MergedDictionaries>
    <!-- Theme colors and icons -->
    <ResourceDictionary Source="Services/Icons/Icons.xaml" />
    <ResourceDictionary Source="Services/Theming/Theme.xaml" />
    <ResourceDictionary>
        <telerik:UserThemeResources x:Key="TelerikLightResources"
                                    LightResourcesPath="ms-appx:///Services/Theming/Telerik/TelerikTheme.xaml" />
    </ResourceDictionary>
</ResourceDictionary.MergedDictionaries>

In your custom theme, just override the Telerik named brushes:

<Color x:Key="TelerikSelectedColor">#B1560F</Color>
<Color x:Key="TelerikHighlightedColor">#75390A</Color>

<SolidColorBrush x:Key="TelerikGridHeaderBackgroundBrush"
                    Color="#7A6F41" />
<SolidColorBrush x:Key="TelerikGridGroupHeaderBackgroundBrush"
                    Color="#7A6F41" />
<SolidColorBrush x:Key="TelerikGridServiceColumnBackgroundBrush"
                    Color="#7A6F41" />
<SolidColorBrush x:Key="TelerikGridHeaderForegroundBrush"
                    Color="White" />
<SolidColorBrush x:Key="TelerikGridGroupHeaderForegroundBrush"
                    Color="White" />
<SolidColorBrush x:Key="TelerikGridServiceColumnForegroundBrush"
                    Color="White" />

Some of the theme assets are images, like the buttons to open and close panels (because it’s hard to draw a triangle in XAML?). If you want to create custom versions of these, then just download these from the source code in GitHub:

TelerikAssets

DefaultCloseButton

You can then modify the images (or replace them entirely) and refer to these in your resources dictionary:

<BitmapImage x:Key="TelerikGridColumnChooserOpenMouseOver"
                UriSource="ms-appx:///Services/Theming/Telerik/Assets/column_chooser_btn_themed.png" />
<BitmapImage x:Key="TelerikGridColumnChooserCloseMouseOver"
                UriSource="ms-appx:///Services/Theming/Telerik/Assets/close_btn_themed.png" />
<BitmapImage x:Key="TelerikGridFilterFlyoutExpanderIcon"
                UriSource="ms-appx:///Telerik.UI.Xaml.Grid.UWP/Assets/FilterFlyout/ic_arrow_down_white.png" />

Here’s a custom panel button in the sample app (it’s the triangle in the upper right corner):

ThemedCloseButton

Personal Experience

I’ve been using this control for a while now. Here’s a screenshot from one of the RadDataGrids that I’m building in another app. It shows a list of possible ingredients for brewing a beer:

AppSample

I have no idea which criteria the user is going to apply to find the ingredient(s) he’s looking for. But I’m sure that the control’s capabilities of presenting the data in a clear way and allowing him to sort, filter, and group the rows on any column or combination of columns will rapidly narrow down the search list.

Here are my personal observations on the Telerik UI controls for UWP, and the RadDataGrid in particular:

Thumbs up Thumbs down
Very rich and mature API and implementation. Shallow reference documentation.
Good quickstart documentation. Lack of detailed sample projects.
It’s for free! Occasional bugs*.

(*) I relatively often need to work around a “Layout cycle detected” error when using more advanced templated columns.

RadDataGrid for UWP is a tremendously powerful and useful control that you may consider for a large number of scenarios.

Source Code

My sample app lives here in GitHub.

Enjoy!

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s