Category Archives: Windows Community Toolkit

Upgrading Radial Gauge from UWP to WinUI 3

In this article we describe the process of migrating a user control from UWP to WinUI 3. The subject is the Radial Gauge that we wrote many years ago and is currently part of Windows Community Toolkit. For its UI the radial gauge uses XAML as well as the Composition API. To successfully migrate the control from UWP to WinUI3

  • we had to remove some UWP calls that don’t exist in WinUI 3,
  • we replaced some UWP calls by their WinUI 3 counterpart, and
  • we decided to give the control a more rounded Windows 11 look-and-feel.

Setting up the environment

When we started this journey, the most recent version of Windows App SDK was the experimental preview of v1.0, so the list of required NuGet packages looked like this:

We installed the new Visual Studio templates:

After the upgrade to the official Windows App SDK 1.0 release, the dependencies list conveniently shrunk to this:

We created a sample app wherein all relevant UWP Radial Gauge source files from Windows Community Toolkit were copy-pasted.

Here’s the taxonomy of the current Windows 8 -style Radial Gauge control:

There was no need to change these properties, just as there was no need to change the control’s XAML template:

<ControlTemplate TargetType="local:RadialGauge">
    <Viewbox>
        <Grid x:Name="PART_Container"
              Width="200"
              Height="200">
 
            <!--  Scale  -->
            <Path Name="PART_Scale" />

            <!--  Trail  -->
            <Path Name="PART_Trail" />

            <!--  Value and Unit  -->
            <StackPanel HorizontalAlignment="Center"
                        VerticalAlignment="Bottom">
                <TextBlock Name="PART_ValueText" />
            </StackPanel>
        </Grid>
    </Viewbox>
</ControlTemplate>

The scale and trail of the gauge are Path elements, and then there are text boxes for value and unit. The rest of the UI parts -needle, ticks, and scale ticks- are drawn by the Composition API.

Goodbye Windows.UI namespace

The first step in migrating a code base from UWP to WinUI would be changing the namespace from Windows.UI.* to Microsoft.UI.* in a zillion places. All compiled well after this change…

Goodbye UI Events

… but at runtime the Toolkit’s ThemeListener crashed the app. It’s a known issue and the reason is that UWP’s UISettings.ColorValuesChanged Event and AccessibilitySettings.HighContrastChanged Event are no longer supported in desktop apps. Unlike UWP apps, WinUI 3 desktop apps are not notified when the user changes the theme, the contrast color, or high contrast mode. This is not a showstopper – as long as you stick to ThemeResources in your XAML. Since theming support is a popular feature these days, we assume that the majority of recent UWP apps is already using theme resource dictionaries. Make sure you don’t forget one for HighContrast. You don’t really need a notification when the theme changes at runtime: all XAML and Composition elements that get their color from a ThemeResource will immediately and automatically change color.

Here’s how we configured the Radial Gauge instances on the Home page of the sample app:

<ResourceDictionary.ThemeDictionaries>
    <ResourceDictionary x:Key="HighContrast">
        <!-- This makes the background disappear in High Contrast mode -->
        <x:Double x:Key="BackgroundOpacity">0</x:Double>
        <SolidColorBrush x:Key="TenPercentContrastBrush"
             Color="{ThemeResource SystemColorWindowTextColor}" />
        <SolidColorBrush x:Key="SystemAccentColorBrush"
             Color="{StaticResource SystemAccentColor}" />
        <SolidColorBrush x:Key="AppNeedleBrush"
             Color="{ThemeResource SystemAccentColor}" />
    </ResourceDictionary>
    <ResourceDictionary x:Key="Dark">
        <x:Double x:Key="BackgroundOpacity">.075</x:Double>
        <SolidColorBrush x:Key="TenPercentContrastBrush"
             Color="White"
             Opacity=".1" />
        <Color x:Key="SystemAccentColor">CadetBlue</Color>
        <SolidColorBrush x:Key="SystemAccentColorBrush"
             Color="{StaticResource SystemAccentColor}"
             Opacity=".5" />
        <SolidColorBrush x:Key="AppNeedleBrush"
             Color="OrangeRed" />
    </ResourceDictionary>
    <ResourceDictionary x:Key="Light">
        <x:Double x:Key="BackgroundOpacity">.15</x:Double>
        <SolidColorBrush x:Key="TenPercentContrastBrush"
             Color="Black"
             Opacity=".1" />
        <Color x:Key="SystemAccentColor">CadetBlue</Color>
        <SolidColorBrush x:Key="SystemAccentColorBrush"
             Color="{StaticResource SystemAccentColor}"
             Opacity=".5" />
        <SolidColorBrush x:Key="AppNeedleBrush"
             Color="OrangeRed" />
    </ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>

Here’s that page in Light, Dark, and HighContrast theme:

As it turned out that all the Toolkit’s ThemeListener related code in the Radial Gauge is actually obsolete in a WinUI 3 desktop context, we removed that code.

Goodbye CoreWindow

Radial Gauge supports keyboard input. The Value property can be changed via the arrow keys, with the CTRL key to manage the change interval. To detect the virtual key press Radial Gauge was using CoreWindow.GetKeyState():

var ctrl = Window.Current.CoreWindow.GetKeyState(VirtualKey.Control);
if (ctrl.HasFlag(CoreVirtualKeyStates.Down))
{
    step = LargeChange;
}

Since UWP’s CoreWindow is not available in WinUI 3 desktop apps, we had to look for another way to detect key presses. We found it in the appropriately named KeyboardInput class. Here’s the new code:

if (KeyboardInput.GetKeyStateForCurrentThread(VirtualKey.Control) == CoreVirtualKeyStates.Down)
{
    step = LargeChange;
};

Goodbye KeyboardInput

Just a few days after that last modification, we upgraded the project to Windows App SDK v1.0 only to observe that the KeyboardInput class was not there anymore. We abandoned the keyboard events and went for Keyboard Accelerators. In hindsight that would always have been the proper approach. We created an extension method to facilitate the declaration:

public static void AddKeyboardAccelerator(this UIElement element,
  VirtualKeyModifiers keyModifiers,
  VirtualKey key,
  TypedEventHandler<KeyboardAccelerator, KeyboardAcceleratorInvokedEventArgs> handler)
{
    var accelerator =
      new KeyboardAccelerator()
      {
          Modifiers = keyModifiers,
          Key = key
      };
    accelerator.Invoked += handler;
    element.KeyboardAccelerators.Add(accelerator);
}

Then we replaced the keypress event handler by eight keyboard accelerators (one for each arrow key, with and without CTRL). Here are two of those:

this.AddKeyboardAccelerator(
    VirtualKeyModifiers.Control,
    VirtualKey.Left,
    (ka, kaea) =>
    {
        Value = Math.Max(Minimum, Value - LargeChange);
        kaea.Handled = true;
    });
this.AddKeyboardAccelerator(
    VirtualKeyModifiers.None,
    VirtualKey.Left,
    (ka, kaea) =>
    {
        Value = Math.Max(Minimum, Value - SmallChange);
        kaea.Handled = true;
    });

Goodbye DesignMode

One of the major differences between UWP and Win32 Desktop is the application model. Unsurprisingly the Windows.ApplicationModel namespace did not survive into Windows App SDK v1.0. As a result, the DesignMode to detect whether the control is hosted by a Visual Designer is not available anymore. It is used in the Toolkit’s DesignTimeHelper class. There seem to be no plans for a WinUI 3 Desktop XAML Designer, and with features like XAML Live Preview and XAML Hot Reload there’s no urgent need for one. Again, we happily removed another part of the Radial Gauge code.

Goodbye Windows 8 style

The original looks of the Radial Gauge were a product of the Windows 8 design style: sharp (“rounded corners, shadows, and gradients are bad for battery life”) and plump (“touch first: designed for fingers”). We decided it was time for a make-over to bring the UI closer to Windows 11 design. We made another copy of the control (“RadialGauge2”) where we

  • decreased the default scale width,
  • rounded the Scale and Trail shapes by changing their PenLineCaps in the XAML template,
  • rounded the Tick, ScaleTick and Needle elements, and
  • provided support for Opacity in these elements.

Rounding the shapes was not a trivial job, since we were relying on SpriteVisual instances – unrounded rectangles filled with a non-transparent CompositionColorBrush. Here’s the old code for the ticks:

SpriteVisual tick;
for (double i = radialGauge.Minimum; i <= radialGauge.Maximum; i += radialGauge.TickSpacing)
{
    tick = radialGauge._compositor.CreateSpriteVisual();
    tick.Size = new Vector2((float)radialGauge.TickWidth, (float)radialGauge.TickLength);
    tick.Brush = radialGauge._compositor.CreateColorBrush(radialGauge.TickBrush.Color);
    tick.Offset = new Vector3(100 - ((float)radialGauge.TickWidth / 2), 0.0f, 0);
    tick.CenterPoint = new Vector3((float)radialGauge.TickWidth / 2, 100.0f, 0);
    tick.RotationAngleInDegrees = (float)radialGauge.ValueToAngle(i);
    radialGauge._root.Children.InsertAtTop(tick);
}

The new Radial Gauge uses a CompositionRoundedRectangleGeometry to fill a CompositionSpriteShape for each tick, and then groups all the ticks into a single ShapeVisual. Transparent brushes are not possible in this part of the API (well, at least not in a simple way). As a work-around we applied the opacity of the source brush to the Opacity of the Visual. Here’s the -much longer- new code:

var ticks = radialGauge._compositor.CreateShapeVisual();
ticks.Size = new Vector2((float)radialGauge.Height, (float)radialGauge.Width);
ticks.BorderMode = CompositionBorderMode.Soft;
ticks.Opacity = (float)radialGauge.TickBrush.Opacity;
 
var roundedTickRectangle = radialGauge._compositor.CreateRoundedRectangleGeometry();
roundedTickRectangle.Size = new Vector2((float)radialGauge.TickWidth, (float)radialGauge.TickLength);
roundedTickRectangle.CornerRadius = new Vector2((float)radialGauge.TickWidth / 2, (float)radialGauge.TickWidth / 2);
 
var tssFillBrush = radialGauge._compositor.CreateColorBrush(radialGauge.TickBrush.Color);
var tssOffset = new Vector2(100 - ((float)radialGauge.TickWidth / 2), 0.0f);
var tssCenterPoint = new Vector2((float)radialGauge.TickWidth / 2, 100.0f);
 
for (double i = radialGauge.Minimum; i <= radialGauge.Maximum; i += radialGauge.TickSpacing)
{
    var tickSpriteShape = radialGauge._compositor.CreateSpriteShape(roundedTickRectangle);
    tickSpriteShape.FillBrush = tssFillBrush;
    tickSpriteShape.Offset = tssOffset;
    tickSpriteShape.CenterPoint = tssCenterPoint;
    tickSpriteShape.RotationAngleInDegrees = (float)radialGauge.ValueToAngle(i);
 
    ticks.Shapes.Add(tickSpriteShape);
}
 
radialGauge._root.Children.InsertAtTop(ticks);

The Home page of our sample app compares the new look to the original one:

The Gallery page displays two sets of controls: the top row has some gauge configurations using the old style, the second row has the same gauges but is using the new style:

We believe that the second row looks better in any configuration.

Here’s how it looks like with the official v1.0.0. of Windows App SDK, bringing the Windows 11 style into the equation:

Here’s how the upgraded Radial Gauge looks like in a candidate production app that is in the middle of its migration to WinUI 3:

For the sake of completion: that other control in the screenshot is a Radial Range Indicator.

The Verdict

Migrating controls and apps from UWP to WinUI 3 involves more than a namespace change, and we’re OK with that. Some API’s have disappeared, but none of these was crucial – not to this user control and not to the apps we’re currently migrating.

We are happy with the result: Radial Gauge now has better looks and less source code to maintain.

The sample app lives here on GitHub.

Enjoy!

Pagination with Entity Framework Core and Microsoft MVVM in WinUI 3

In this article we present a LINQ-based pagination solution for list controls as well as a pager user interface, all in a WinUI 3 application. We use SQLite as data provider and a Windows Community Toolkit DataGrid as host control, but the solution applies to any Entity Framework Core (EF Core) store and any WinUI 3 ItemsControl. For the implementation of the MVVM pattern, we chose the usual suspect: Microsoft MVVM Toolkit.

Here’s how the sample page looks like:

This is a new XAML page that we added to the sample app for our previous article on using the DataGrid in WinUI 3.

The heart of our pagination infrastructure is PaginatedList<T> – a subclass of List<T>.

It holds a specific page from a query result as a list of items can be bound to any ItemsControl as ItemsSource. A PaginatedList<T> instance not only embeds the (partial) result of the query but it also exposes the current page number, and the total number of pages for the whole query (quite convenient for a pager UI). The page size (number of records wanted) is not a property but is provided to the constructor.

Here’s how the class definition looks like:

public class PaginatedList<T> : List<T>
{
    public int PageIndex { get; private set; }

    public int PageCount { get; private set; }

    private PaginatedList(List<T> items, int count, int pageIndex, int pageSize)
    {
        PageIndex = pageIndex;
        PageCount = (int)Math.Ceiling(count / (double)pageSize);
        AddRange(items);
    }

    public static async Task<PaginatedList<T>> CreateAsync(
	IQueryable<T> source, 
	int pageIndex, 
	int pageSize)
    {
        int count = await source.CountAsync();
        List<T> items = await source
	.Skip((pageIndex - 1) * pageSize)
	.Take(pageSize)
	.ToListAsync();

        return new PaginatedList<T>(items, count, pageIndex, pageSize);
    }
}

We’re using some of the asynchronous EF Core IQueryable Extensions here, but feel free to add a synchronous version if that better fits your use case.

The PaginatedList is used inside the XAML page’s ViewModel (a Microsoft MVVM Toolkit’s ObservableObject) to produce a List<Mountain> to which the DataGrid is bound. The ViewModel also exposes the current page number and the total number of pages. These are used by the pager on top. Here’s the ViewModel’s code:

public class PaginationPageViewModel : ObservableObject
{
    private int _pageSize = 10;
    private int _pageNumber;
    private int _pageCount;
    private List<Mountain> _mountains;

    public int PageNumber
    {
        get => _pageNumber;
        private set => SetProperty(ref _pageNumber, value);
    }

    public int PageCount
    {
        get => _pageCount;
        private set => SetProperty(ref _pageCount, value);
    }

    public List<Mountain> Mountains
    {
        get => _mountains;
        private set => SetProperty(ref _mountains, value);
    }

    private async Task GetMountains(int pageIndex, int pageSize)
    {
        using MountainDbContext dbContext = new();
        PaginatedList<Mountain> pagedMountains = await PaginatedList<Mountain>.CreateAsync(
            dbContext.Mountains
                .OrderBy(m => m.Rank),
            pageIndex,
            pageSize);
        PageNumber = pagedMountains.PageIndex;
        PageCount = pagedMountains.PageCount;
        Mountains = pagedMountains;
    }
}

Here’s how the ‘current page of Mountains’ is bound to the DataGrid:

<ctWinUI:DataGrid x:Name="DataGrid"
                    ItemsSource="{x:Bind ViewModel.Mountains, Mode=OneWay}"
                    AutoGenerateColumns="False"
                    CanUserSortColumns="False"
                    SelectionMode="Single"
                    IsReadOnly="True"
                    RowDetailsVisibilityMode="Collapsed">
    <ctWinUI:DataGrid.Columns>
        <ctWinUI:DataGridTextColumn Header="Rank"
                                    Binding="{Binding Rank}" />
        <ctWinUI:DataGridComboBoxColumn Header="Mountain"
                                        Binding="{Binding Name}" />
        <!-- More columns -->
    </ctWinUI:DataGrid.Columns>
</ctWinUI:DataGrid>

The ViewModel also exposes 4 commands -implementors of IAsyncRelayCommand– to allow refreshing the DataGrid with a new logical page:

public IAsyncRelayCommand FirstAsyncCommand { get; }

public IAsyncRelayCommand PreviousAsyncCommand { get; }

public IAsyncRelayCommand NextAsyncCommand { get; }

public IAsyncRelayCommand LastAsyncCommand { get; }

We would have loved to use one of the new WinUI Pager controls for user interface, but tody these are available in WinUI 2 only. Therefor we brewed our own CommandBar-based pagination control with the canonical navigation buttons to the first, previous, next, and last pages:

<CommandBar DefaultLabelPosition="Right">
    <AppBarButton ToolTipService.ToolTip="First"
                    Icon="Previous"
                    Command="{x:Bind ViewModel.FirstAsyncCommand, Mode=OneWay}" />
    <AppBarButton ToolTipService.ToolTip="Previous"
                    Icon="Back"
                    Command="{x:Bind ViewModel.PreviousAsyncCommand, Mode=OneWay}" />
    <AppBarElementContainer>
        <TextBlock Text="Page" />
    </AppBarElementContainer>
    <AppBarElementContainer>
        <TextBlock Text="{x:Bind ViewModel.PageNumber, Mode=OneWay}" />
    </AppBarElementContainer>
    <! -- And so on ... -->

Here’s how the AsyncRelayCommands are initialized in the ViewModel with their respective Execute and CanExecute logic:

FirstAsyncCommand = new AsyncRelayCommand(
    async () => await GetMountains(1, _pageSize),
    () => _pageNumber != 1
);
PreviousAsyncCommand = new AsyncRelayCommand(
    async () => await GetMountains(_pageNumber - 1, _pageSize),
    () => _pageNumber > 1
);
NextAsyncCommand = new AsyncRelayCommand(
    async () => await GetMountains(_pageNumber + 1, _pageSize),
    () => _pageNumber < _pageCount
);
LastAsyncCommand = new AsyncRelayCommand(
    async () => await GetMountains(_pageCount, _pageSize),
    () => _pageNumber != _pageCount
);

Each time a new page is fetched and displayed, we need to tell the commands that their CanExecute property was updated so that the corresponding buttons in the pager will enable or disable themselves:

FirstAsyncCommand.NotifyCanExecuteChanged();
PreviousAsyncCommand.NotifyCanExecuteChanged();
// And so on ...

To improve the user experience, we enhanced PaginatedList<T> to implement some edge cases. When the result of the full query is empty (page count is zero), we set the current page number to zero:

int count = await source.CountAsync();
if (count == 0)
{
   // No results -> return page 0.
   return new PaginatedList<T>(new List<T>(), 0, 0, pageSize);
}

This is how the pager then looks like:

When the requested page is out of range (has no records) then PaginatedList<T> returns the last page:

List<T> items = await source.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync();
if (items.Count == 0)
{
    // Requested page is out of range -> return last page.
    pageIndex = (int)Math.Ceiling(count / (double)pageSize);
    items = await source.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync();
}

return new PaginatedList<T>(items, count, pageIndex, pageSize);

Here’s how the pager looks like when we try to navigate to page 1000:

Last but not least, we allow the user to change the page size. We first added the property and a list of possible values to the ViewModel:

public List<int> PageSizes => new() { 5, 10, 20, 50, 100 };

public int PageSize
{
    get => _pageSize;
    set
    {
        SetProperty(ref _pageSize, value);
        Refresh();
    }
}

Then we added a ComboBox and a TextBlock to the AppBar, via AppBarElementContainer instances:

<AppBarSeparator />
<AppBarElementContainer VerticalContentAlignment="Center">
    <ComboBox ItemsSource="{x:Bind ViewModel.PageSizes}"
                SelectedItem="{x:Bind ViewModel.PageSize, Mode=TwoWay}" />
</AppBarElementContainer>
<AppBarElementContainer VerticalContentAlignment="Center">
    <TextBlock Text="rows per page"
                Margin="8 0" />
</AppBarElementContainer>

Here’s how that part of the UI looks like:

paginationpagesize

Finally we implemented the Refresh() method – triggered by a change of the PageSize property. We simply navigate to the first page. Before that we make sure that the command can execute by setting the page number to zero:

private void Refresh()
{
    _pageNumber = 0;
    FirstAsyncCommand.Execute(null);
}

With a handful lines of code and a little help from our friends Microsoft MVVM Toolkit and EF Core we just implemented a WinUI 3 pagination use case. Our sample app lives here on GitHub.

Enjoy!

Using the Windows Community Toolkit DataGrid with WinUI 3 and Entity Framework Core

In this article we demonstrate the Windows Community Toolkit DataGrid in a desktop application powered by the Windows App SDK and a Sqlite relational database. We’ll cover

  • populating the DataGrid,
  • sorting rows via a click on a column header,
  • filtering rows on predefined criteria,
  • grouping rows,
  • searching for rows,
  • instant theme switching,

Here’s how our sample app looks like on Windows 10:

 DatabaseSearch

Recently we started migrating some UWP apps to WinUI 3. Some of these apps have 3rd party DataGrid controls, and we wanted to know whether Community Toolkit DataGrid is a decent candidate to replace these – after all: it’s free. We had no idea how this DataGrid control would behave in a WinUI 3 desktop app, since there are no official samples yet: 

WinUIControlsGallery

On top of that the Community Toolkit DataGrid control is still in its first version which was a port from Silverlight to UWP. When you look at its source you’ll notice that a lot of the code is already 3 years old. Would it run on the brand new Windows App SDK?

For all these reasons we were a bit reluctant to immediately start using this DataGrid in a production WinUI 3 desktop application. So we decided to test drive it first in a more representative setting. This test drive became the sample app that we’re describing in this article.

Migrating the Community Toolkit Sample app

We started our adventure by migrating the UWP DataGrid sample page from the Community Toolkit Sample app to WinUI 3. It has all the functionality we need (filtering, grouping, sorting, theming) and more (editing), and it’s Open Sourced. Here’s how the original looks like:

CommunityToolkitSampleApp

The migration was easier than expected and basically boiled down to updating the “windows.ui.” namespace references to “microsoft.ui.” all over the place. We then applied some cosmetic changes, like adding transparency to the column header background and adding elegance to the CommandBar on top. We also couldn’t resist modernizing the C# syntax here and there.

The Home page of our sample app is the result of the migration from an UWP/WinRT XAML page to WinUI 3/.NET 5:

HomeSort

All features of the original Toolkit demo were successfully ported to our own sample app. You can for example apply a filter to the displayed records:

HomeFilter

You can group records:

HomeGroup

You can sort the records by clicking on a column header:

HomeSearch

The icon in the top right corner op the page allows you to immediately switch between light and dark theme. As long as you stick to ‘lightweight styling’ (i.e. just overriding theme color resources) the following one-liner will do the trick:

Root.RequestedTheme = Root.RequestedTheme == ElementTheme.Light 
	? ElementTheme.Dark 
	: ElementTheme.Light;

From the moment you start to programmatically modify resources, or retemplate (parts of) a control, this instant theme-switching becomes problematic. Not only the control’s XAML but also the defined animations refer to expected colors, opacities, and more – and it’s super hard to override all of these. But let’s focus on DataGrid’s core features.

It takes some development and design effort to implement sorting, filtering, and especially grouping with the Community Toolkit DataGrid. In third party control toolkits such as the ones from DevExpress, Syncfusion, or Telerik [no ranking, just alphabetic order] such features can be configured declaratively and they come with a built-in UI. Nevertheless we were happy with the result of this first page, and decided to build a more modern/representative version of it by bringing some new components to the equation, like

  • Microsoft MVVM Toolkit to replace the custom change propagation code in Models and ViewModels,
  • a Sqlite relational database to replace the CSV file, and
  • Entity Framework Core as an Object-Relational Mapper to run LINQ queries against the data.

Here’s an overview of the NuGet packages – ignore the version numbers, they were all upped multiple times since we made the screenshot:

NuGetPackages

We skipped editing and validation in our sample app, but still all Models and ViewModels were renamed and became children of MVVM Toolkit’s ObservableObject class:

public class Mountain : ObservableObject
{
    private uint _rank;
    private string _name;
    // more fields ...

    // Key

    [Key]
    public int Id { get; set; }

    // Fields

    public uint Rank
    {
        get => _rank;
        set => SetProperty(ref _rank, value);
    }

    // more properties ...

}

For more details on Microsoft MVVM Toolkit, check this introduction. In the rest of this article we’ll focus on Entity Framework (EF) Core, since that is most probably new to UWP developers who are migrating to Windows App SDK.

Configuring Entity Framework Core

For the enterprise sample we replaced the .csv file with a relational Sqlite database. An Entity Framework DbContext was defined to host a table with Mountain entities – a DbSet<Mountain>. Everything is persisted in the app’s local folder:

public class MountainDbContext : DbContext
{
    public DbSet<Mountain> Mountains { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        string path = Path.Combine(
	ApplicationData.Current.LocalFolder.Path, 
	"mountains.db");

        string connectionStringBuilder = new
            SqliteConnectionStringBuilder()
        {
            DataSource = path
        }
            .ToString();

        SqliteConnection connection = new SqliteConnection(connectionStringBuilder);
        optionsBuilder.UseSqlite(connection);
    }
}

Before accessing it, the ViewModel ensures that the database is created:

dbContext.Database.EnsureCreated();

This checks whether the database exists -it may of may not have been deployed with your app- and if not it creates an empty one. Our sample app then reads the original .CSV file and populates the Mountains table with it. Now we can write LINQ queries against the data, such as this one to get all of the Mountains:

public async Task<IEnumerable<Mountain>> AllMountainsAsync()
{
    using (MountainDbContext dbContext = new())
    {
        return await dbContext.Mountains
	.OrderBy(m => m.Rank)
	.AsNoTracking()
	.ToListAsync();
    }
}

Observe that EF Core comes with an asynchronous version of ToList(). When you’re not modifying the content, then it’s a good idea to disable EF change tracking, that’s what the AsNoTracking() does.

Making a read-only DataGrid

The DataGrid definition is similar to the one in the Home page, except that we made the grid read-only since we’re not huge fans of editable DataGrids:

<ctWinUI:DataGrid x:Name="DataGrid"
                    AutoGenerateColumns="False"
                    CanUserSortColumns="True"
                    Sorting="DataGrid_Sorting"
                    LoadingRowGroup="DataGrid_LoadingRowGroup"
                    SelectionMode="Single"
                    IsReadOnly="True">
    <ctWinUI:DataGrid.Columns>
        <ctWinUI:DataGridTextColumn Header="Rank"
                                    Binding="{Binding Rank}"
                                    Tag="Rank" />
        <ctWinUI:DataGridComboBoxColumn Header="Mountain"
                                        Binding="{Binding Name}"
                                        Tag="Name" />
        <!-- More columns ... -->
    </ctWinUI:DataGrid.Columns>
</ctWinUI:DataGrid>

It does not make sense to allow selecting individual cells, so we implemented “row-selection mode” by turning the focus brushes for individually selected cells transparent:

<SolidColorBrush x:Key="DataGridCellFocusVisualPrimaryBrush">Transparent</SolidColorBrush>
<SolidColorBrush x:Key="DataGridCellFocusVisualSecondaryBrush">Transparent</SolidColorBrush>

Be aware that Community Toolkit DataGrid does not support the {x:Bind} syntax for column property bindings, even when you provide bindings for DataContext and ItemsSource:

xBind

Drawing a Template Column

The apps that we’re migrating use templated columns, so we looked for an excuse to define a DataGridTemplateColumn in this sample app. We decided to display the height of the Mountain as a Slider. Here’s the template, observe that the use of {x:Bind} is supported, at least when you declare the DataType :

<ctWinUI:DataGridTemplateColumn Header="Height"
                                Tag="Height">
    <ctWinUI:DataGridTemplateColumn.CellTemplate>
        <DataTemplate x:DataType="models:Mountain">
            <Grid Background="Transparent"
                    ToolTipService.ToolTip="{x:Bind HeightDescription}">
                <Slider Minimum="7200"
                        Maximum="8848"
                        Value="{x:Bind Height}"
                        IsHitTestVisible="False"
                        IsTabStop="False" />
            </Grid>
        </DataTemplate>
    </ctWinUI:DataGridTemplateColumn.CellTemplate>
</ctWinUI:DataGridTemplateColumn>

Here’s how the page now looks like:

DatabaseTemplate

We kept IsEnabled to true to allow the Slider to keep its accent color instead of being grayed out, and set both IsHitTestVisible and IsTabStop to false to prevent user interaction.

Applying a Filter

Here are the LINQ queries that correspond to the filter options:

case FilterOptions.Rank_High:
    return await dbContext.Mountains
	.Where(m => m.Rank > 50)
	.OrderBy(m => m.Rank)
	.AsNoTracking()
	.ToListAsync();

case FilterOptions.Height_High:
    return await dbContext.Mountains
	.Where(m => m.Height > 8000)
	.OrderBy(m => m.Rank)
	.AsNoTracking()
	.ToListAsync();

As already mentioned, third party libraries have built-in UI to allow your end user to define and apply his own filters. Check this article for an example. Here’s how a filtered dataset looks like in our sample app – with less rows, and an extra indicator on the command button to notify the user that a filter is applied:

DatabaseFilter

Sorting by clicking a column header

For the column sort feature, we wanted to avoid a huge switch statement with a different LINQ expression for each column – as in the original sample. We went for a solution that takes the name of the column and the sort direction as parameter:

public async Task<IEnumerable<Mountain>> SortedMountainsAsync(
	string sortBy, 
	bool ascending)
{
    using (MountainDbContext dbContext = new())
    {
        return await dbContext.Mountains
	.OrderBy(sortBy, !ascending)
	.AsNoTracking()
	.ToListAsync();
    }
}

The OrderBy() in the previous code is an -admittedly cryptic- extension method that builds the appropriate LINQ expression:

public static IOrderedQueryable<TEntity> OrderBy<TEntity>(
    this IQueryable<TEntity> source,
    string orderByProperty,
    bool desc)
{
    string command = desc ? "OrderByDescending" : "OrderBy";
    Type type = typeof(TEntity);
    PropertyInfo property = type.GetProperty(orderByProperty);
    ParameterExpression parameter = Expression.Parameter(
            type,
            "p");
    MemberExpression propertyAccess = Expression.MakeMemberAccess(
            parameter,
            property);
    LambdaExpression orderByExpression = Expression.Lambda(
            propertyAccess,
            parameter);
    MethodCallExpression resultExpression = Expression.Call(
            typeof(Queryable),
            command,
            new Type[] { type, property.PropertyType },
            source.Expression, Expression.Quote(orderByExpression));
    return (IOrderedQueryable<TEntity>)source
            .Provider
            .CreateQuery<TEntity>(resultExpression);
}

When working with EF or EF Core, it’s always good to have IQueryable extensions like this hanging around.

Implementing the Mode

Clicking on a column header (or on one of the command bar buttons) changes the ItemsSource of the DataGrid but also changes its UI (arrow indicators in the column header, and command bar decorators above the grid). You have to make sure that all ‘old’ arrow indicators are removed when you apply a filter -something that was overlooked in the official Toolkit Sample App.

We centralized the UI logic behind a “mode switch” in a PropertyChangedCallback for ItemsSourceProperty:

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    _token = DataGrid.RegisterPropertyChangedCallback(
	ctWinUI.DataGrid.ItemsSourceProperty,
	DataGridItemsSourceChangedCallback);
    base.OnNavigatedTo(e);
}

protected override void OnNavigatedFrom(NavigationEventArgs e)
{
    DataGrid.UnregisterPropertyChangedCallback(
	ctWinUI.DataGrid.ItemsSourceProperty, 
	_token);
    base.OnNavigatedFrom(e);
}

private void DataGridItemsSourceChangedCallback(DependencyObject sender, DependencyProperty dp)
{
    // Remove Sort Indicators.
    if (dp == ctWinUI.DataGrid.ItemsSourceProperty)
    {
        foreach (var column in (sender as ctWinUI.DataGrid).Columns)
        {
            column.SortDirection = null;
        }
    }

    // Other display mode dependent UI logic
    // ...
}

Here’s how we implemented the button decorators in the command bar to indicate the active mode – as an Icon in an AppBarElementContainer that has a negative margin:

<CommandBar DefaultLabelPosition="Right"
            Background="Transparent"
            VerticalAlignment="Center">
    <AppBarButton Icon="Filter"
                    Label="Filter"
                    Width="80">
        <AppBarButton.Flyout>
            <MenuFlyout>
                <!-- Menu items -->
            </MenuFlyout>
        </AppBarButton.Flyout>
    </AppBarButton>
    <AppBarElementContainer x:Name="FilterIndicator"
                            Visibility="Collapsed"
                            Margin="-16 0 0 0">
        <FontIcon Glyph=""
                    FontSize="12"
                    Foreground="Coral"
                    VerticalAlignment="Top" />
    </AppBarElementContainer>

    <!-- More buttons and indicators -->

</CommandBar>

In the future InfoBadge might be a nice alternative but that control is not yet pushed to WinUI 3.

Searching for records

Here’s our initial LINQ query behind the search feature:

return await dbContext.Mountains
            .Where(m => m.Name.Contains(queryText))
            .OrderBy(m => m.Rank)
            .AsNoTracking()
            .ToListAsync();

At first sight no surprises here, except that … it’s case sensitive:

DatabaseSearchWithContains

The LINQ Provider for Sqlite (in contrast to the one for SQL Server) translates Contains() to a case sensitive comparison. The following modification to the query only makes things worse:

return await dbContext.Mountains
            .Where(m => m.Name.Contains(queryText, StringComparison.InvariantCulture)) // Crashes at runtime
            .OrderBy(m => m.Rank)
            .AsNoTracking()
            .ToListAsync();

It will crash at runtime since the LINQ Provider does not know how to translate this C# to its SQL syntax. Again you’ll find enough extension methods to solve this … but in this case EF Core itself has one: EF.Functions.Like(). Here’s how it’s used to generate a SQL LIKE:

return await dbContext.Mountains
            .Where(m => EF.Functions.Like(m.Name, $"%{queryText}%"))
            .OrderBy(m => m.Rank)
            .AsNoTracking()
            .ToListAsync();

Here’s how the result of the non-case-sensitive search looks like in the sample app:

DatabaseSearch

Grouping rows

This is the first version of our LINQ query for the grouping feature:

IEnumerable<GroupInfoCollection<string, Mountain>> query = dbContext.Mountains
                .OrderBy(m => m.Range)
                .ThenBy(m => m.Rank)
                .AsNoTracking()
                .GroupBy(m => m.Range, (key, list) => new GroupInfoCollection<string, Mountain>(key, list));

Bad luck: the LINQ Provider for Sqlite does not know how to translate this C# into SQL syntax, and crashes at runtime:

MissingGroupByLinq

We opted to bail out of the Sqlite Provider with a ToList() in the middle of the expression. The GroupBy() is then not applied to the query (an IQueryable) but to the result of the query (an IEnumerable). The responsibility was passed to the native .NET 5 LINQ provider, who knows how to handle this:

IEnumerable<GroupInfoCollection<string, Mountain>> query = dbContext.Mountains
                .OrderBy(m => m.Range)
                .ThenBy(m => m.Rank)
                .AsNoTracking()
                .ToList()
                .GroupBy(m => m.Range, (key, list) => new GroupInfoCollection<string, Mountain>(key, list));

Here’s how grouping looks like in our sample app:

DatabaseGroup

Showing Row Details

The command bar has a button to reveal (or hide) the details of the selected row:

DatabaseDetails

We prefer this pattern over the ‘every-click-opens-details-row’ that’s built into the DataGrid. Firstly because you cannot unselect a row – clicking on the selected row does not unselect it. The only way to close the details row is selecting another row – which then opens a new details row. Secondly we believe that in most cases it’s better to display the details not inside the DataGrid but in a separate place (navigate to another page, open a dialog, …).

Stability

Running V1 of a ported Silverlight control in an application ecosystem that’s only in v0.8: what could possibly go wrong? Smile 

When browsing the open DataGrid related issues on GitHub, you encounter some stability issues. When we started building the sample app, we ran into some of these. When rapidly scrolling, switching mode, and clicking column headers, the DataGrid control gave up rather quickly. For the sake of completeness: with the same behavior we also managed to crash all of the 3rd party sample apps.

We were relieved to observe that most if not all of the performance and stability issues were solved with the release of Windows App SDK 0.8.2! From that release on the DataGrid is behaving as expected.

Conclusion

As far as we are concerned, Community Toolkit DataGrid on WinUI 3 has passed the tests, and is ready for prime time. Some of the features -like filtering and grouping- require more design and development effort than you would have with third party components. This is a challenge, but it’s also an opportunity for you to come up with a friendly non-technical user experience for these scenarios. Here are a couple of examples (NOT included in the sample app) of custom filtering and grouping that would even be hard with third party grids.

  • Removing the Lagers from a list of beer styles. This is a filter on a substring in a hidden column:

Sample

  • Grouping a list of hops by origin. This is a grouping on an n-to-n relation:

Sample2

It’s great for the end user to see the most relevant filtering and groupings of the data and just select one from a menu.

Our sample app lives here on GitHub.

Enjoy!

Data Validation with the Microsoft MVVM Toolkit

In this article we will walk through a handful of scenarios and techniques for input validation with the ObservableValidator class of Microsoft MVVM Toolkit. We will cover

  • canonical property validation,
  • comparing two (or more) properties,
  • comparing the new value of a property to its previous one,
  • delaying the validation, and
  • preventing to assign an invalid value to a property.

We created a sample app in UWP, it looks like this:

ComparingProperties

Input Validation in UWP

The System.Component.DataAnnotations is almost as old as the .NET Framework itself. It contains attribute classes to decorate ViewModels and Models with metadata for validation purposes – among other. These attributes describe property validation rules. When the rules are broken, the instance exposes its validation errors via its INotifyDataError members. This validation technique is intensively used in several ASP.NET frameworks and also made its way to Silverlight and WPF. Until very recently, data validation in UWP did not get much attention from Microsoft. Most development teams embedded third-party solutions such as Prism, Template10, or Calcium into their UWP apps, or rolled their own custom solution.

With Microsoft MVVM toolkit there now is a Microsoft provided alternative, and it’s even ready for Reunion. Now that we’re talking about the future: WinUI 3 controls will come with templates that react upon the INotifyDataErrorInfo status of the (View)Model that they are bound to. There is currently a bug that inhibits a deeper dive into this. Nevertheless, the WinUI3 Controls Gallery app already contains a sample page. It’s currently broken, but it reveals a glimpse of the near future of input validation in WinUI:

WinuiControlsGallery

That’s not a spectacular screenshot, so for reference here’s an example of similar control templates in WPF:

customerrortemplateWPF

While the UI parts of UWP Data Validation are not yet ready for prime time, the supporting Microsoft MVVM Toolkit is fully operational. Welcome to ObservableValidator.

ObservableValidator

The great official documentation teaches us that

‘The ObservableValidator is a base class implementing the INotifyDataErrorInfo interface, providing support for validating properties exposed to other application modules. It also inherits from ObservableObject, so it implements INotifyPropertyChanged and INotifyPropertyChanging as well. It can be used as a starting point for all kinds of objects that need to support both property change notifications and property validation.’.

Microsoft MVVM Toolkit is fully developed in the open, the source code for ObservableValidator is right here. Models and ViewModels that require validation just need to inherit from it, like this:

public class Suspect : ObservableValidator
{
    private string _name;
    private string _socialSecurityNumber;

    // ... there's more
}

The instance will expose its error status through its INotifyDataErrorInfo members. The Views in our sample app have bindings to ErrorsChanged and HasErrors. Check our previous blog post to see how this was done. Were’ reusing its ‘error popup’ approach. Here’s its XAML definition:

<SymbolIcon Symbol="ReportHacked"
            Foreground="Red"
            Visibility="{x:Bind ViewModel.Suspect.HasErrors, Mode=OneWay}">
    <ToolTipService.ToolTip>
        <TextBlock Text="{x:Bind ViewModel.Suspect.Errors, Mode=OneWay}"
                    Foreground="Red" />
    </ToolTipService.ToolTip>
</SymbolIcon>

Using existing Validation Attributes

The System.Component.DataAnnotations namespace hosts a huge list of attributes available for the validation of individual properties: required, minimum and maximum length, range, Enum, Regex … These cover most of the usual suspects. There are not too much XAML examples on the market, so when you search for sample code, you’ll probably end up in ASP.NET MVC projects. Don’t worry about that: MVC Models are very similar to MVVM ViewModels.

To implement validation in a class, it suffices to decorate its properties with one or more of these validation attributes and call one of its SetProperty() overloads with true as the third parameter in the property setter. Here’s how our sample app evaluates whether Keyser Söze has a required Name of minimum length and has his SocialSecurityNumber checked against a regular expression:

[Required(
	ErrorMessage = "Name is Required")]
[MinLength(
	2, 
	ErrorMessage = "Name should be longer than one character")]
public string Name
{
    get => _name;
    set => SetProperty(ref _name, value, true);
}

[RegularExpression(
	@"^(?!000)(?!666)(?!9)\d{3}([- ]?)(?!00)\d{2}\1(?!0000)\d{4}$", 
	ErrorMessage = "Invalid Social Security Number.")]
public string SocialSecurityNumber
{
    get => _socialSecurityNumber;
    set => SetProperty(ref _socialSecurityNumber, value, true);
}

The validation is triggered whenever the property gets a new value. All we need in the View is a two-way binding to the property:

<TextBox Text="{x:Bind ViewModel.Suspect.Name, Mode=TwoWay}"
            PlaceholderText="Name" />
<TextBox Text="{x:Bind ViewModel.Suspect.SocialSecurityNumber, Mode=TwoWay}"
            PlaceholderText="Social Security Number" />

Here’s how our sample app reacts to an evil social security number:

ValidationAttributes

The regular expression correctly refuses a number that starts with 666.

Rolling your own Validation Attributes

It’s easy to roll your own reusable validation attribute: inherit from ValidationAttribute and provide your own implementation of the IsValid() method. The method gets the ValidationContext injected as a parameter, exposing the whole instance that is being validated, not only the decorated property. This allows you to write validation rules over more than one property, like:

  • property a should be less than property b, or
  • if property a has a value, then property b becomes required.

Allow us to mention that there already *is* a validation attribute that compares two properties -the CompareAttribute– but it only checks for equality. It’s used in the confirmation fields for email addresses and passwords (and probably nowhere else)

Our sample app contains a validation rule to compare two dates. It is used in the common ‘if the EndDate is filled out it then should come after StartDate’ scenario.

Let’s first show how the GreaterThan attribute is applied in the ViewModel class:

[GreaterThan (
	nameof(StartDate), 
	"End date should come after start date.")]
public DateTime? EndDate
{
    get => _endDate;
    set { 
        SetProperty(ref _endDate, value, true);
    }
}

Here’s the implementation of the validation attribute itself. It can be reused across applications:

public sealed class GreaterThanAttribute : ValidationAttribute
{
    private string _errorMessage;

    public GreaterThanAttribute(string propertyName, string errorMessage)
    {
        PropertyName = propertyName;
        _errorMessage = errorMessage;
    }

    public string PropertyName { get; }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (value == null)
        {
            return ValidationResult.Success;
        }

        var instance = validationContext.ObjectInstance;
        var otherValue = instance.GetType().GetProperty(PropertyName).GetValue(instance);

        if (((IComparable)value).CompareTo(otherValue) > 0)
        {
            return ValidationResult.Success;
        }

        return new ValidationResult(_errorMessage);
    }
}

Since we’ve created a dependency between the values of Start- and EndDate in the ViewModel, we need to make sure that the validation is triggered by both properties’ changes. That’s why we make a call to ValidateProperty() in the setter of StartDate:

public DateTime? StartDate
{
    get => _startDate;
    set { SetProperty(ref _startDate, value, true);
        ValidateProperty(EndDate, nameof(EndDate));
    }
}

In the View, we bound both properties to a Date in a CalendarDatePicker:

<CalendarDatePicker Date="{x:Bind ViewModel.NoDelorean.GetStartDate(), BindBack=ViewModel.NoDelorean.SetStartDate, Mode=TwoWay}"
                    PlaceholderText="Start Date" />
<CalendarDatePicker Date="{x:Bind ViewModel.NoDelorean.GetEndDate(), BindBack=ViewModel.NoDelorean.SetEndDate, Mode=TwoWay}"
                    PlaceholderText="End Date" />

[We used {x:Bind} with function bindings to plug in a transformation between the DateTime of the properties and the DateTimeOffset values of the controls.]

Here’s how an invalid instance looks like in the sample app:

ComparingProperties

Also, please note that this rule does not apply to all ViewModels. Sometimes it should be possible to go back in time:

delorean

Using a CustomValidation method

Not every validation rule should be cast in a universally reusable validation attribute class. For a local rule, you can get away with writing a static validation method and applying it to a property via a CustomValidation attribute. Our sample app uses this technique to compare a new value of a property to its old value. The ViewModel represents a CountDown class – the validation rule ensures that we don’t ‘count up’.

The values to compare must have their own fields:

private int _value = 10;
private int _previousValue;

We created a static method that takes the property’s type (int in our Counter case) and a ValidationContext, and returns the result of the validation as a ValidationResult:

public static ValidationResult ValidateValue(
	int value, 
	ValidationContext context)
{
    var instance = (Countdown)context.ObjectInstance;
    var isValid = value < instance._previousValue;

    if (isValid)
    {
        return ValidationResult.Success;
    }

    return new ValidationResult("We're not supposed to count up.");
}

Again the validation context gives us access to the instance being validated, so it allows us to compare the new counter value to the old. Here’s how the rule is applied to the Value property:

[CustomValidation(typeof(Countdown), nameof(ValidateValue))]
public int Value
{
    get => _value;
    set
    {
        _previousValue = _value;
        SetProperty(ref _value, value, true);
    }
}

And this is how violating the counter rule looks like in the sample app:

ComparingNewToOld

Delaying Validation

Up until now, we always triggered the validation on the assignment of the property. This is not needed or wanted in every scenario or for every property. The third parameter in the SetProperty() call was always set to true in the previous examples. In our next sample, the validation will be triggered by a button click, so we start with a false in the property setter:

[Required(
	ErrorMessage = "Name is Required")]
[MinLength(
	2, 
	ErrorMessage = "Name should be longer than one character")]
public string Name
{
    get => _name;
    set => SetProperty(ref _name, value, false);
}

[RegularExpression(
	@"^(?!000)(?!666)(?!9)\d{3}([- ]?)(?!00)\d{2}\1(?!0000)\d{4}$", 
	ErrorMessage = "Invalid Social Security Number.")]
public string SocialSecurityNumber
{
    get => _socialSecurityNumber;
    set => SetProperty(ref _socialSecurityNumber, value, false);
}

For the sake of simplicity we validate all properties together – there’s a call for this: ValidateAllProperties(). The call is hooked to the button with an instance of MVVM Toolkit’s RelayCommand:

public ICommand ValidateCommand => 
	new RelayCommand(() => ValidateAllProperties());

Here’s the binding:

<Button Content="Validate"
        Command="{x:Bind ViewModel.SuspectWithDelayedValidation.ValidateCommand, Mode=OneWay}" />

And this is how the result looks like in the app:

DelayedValidation

There is a Try

In the previous examples we started the validation after the assignment of a property. We were continuously breaking an ancient object oriented programming principle:

it should not be possible to bring a properly encapsulated object into an invalid state via the public interface.

In some scenarios or parts of your app (e.g. in the Models) you should indeed prevent the assignment of invalid values to properties. Fortunately Microsoft MVVM Toolkit comes with TrySetProperty() … there *is* a Try.

notry

TrySetProperty inspects the new value that you (try to) assign, and only succeeds when that value is a valid one. On the upside you’ll never have instances in an invalid state, on the downside you need to provide you own Errors store – instances will never have ‘official’ errors in their INotifyDataErrorInfo members.

In our sample app we decorated the ViewModel with alternative members – a list of ValidationResult instances to store the errors per property and a Boolean that returns whether that list has members:

public class NotYoda : ObservableValidator
{
    private List<ValidationResult> _errors = new List<ValidationResult>();

    public string Errors => string.Join(Environment.NewLine, from ValidationResult e in _errors select e.ErrorMessage);

    // Since HasErrors is not virtual:
    public bool ErrorsHaveI => Errors.Length > 0;

    // More, there is...
}

In the property setters we first clean up the previous messages for the property, then call the TrySetProperty, use its output parameter to update our custom error list, and then notify the custom error property changes:

[Required(
	ErrorMessage = "Name is Required")]
[MinLength(
	2, 
	ErrorMessage = "Name should be longer than one character")]
public string Name
{
    get => _name;
    set
    {
        _errors.RemoveAll(v => v.MemberNames.Contains(nameof(Name)));

        TrySetProperty(ref _name, value, out IReadOnlyCollection<ValidationResult> errors);

        _errors.AddRange(errors);
        OnPropertyChanged(nameof(Errors));
        OnPropertyChanged(nameof(ErrorsHaveI));
    }
}

[RegularExpression(
	@"^(?!000)(?!666)(?!9)\d{3}([- ]?)(?!00)\d{2}\1(?!0000)\d{4}$", 
	ErrorMessage = "Invalid Social Security Number.")]
public string SocialSecurityNumber
{
    get => _socialSecurityNumber;
    set
    {
        _errors.RemoveAll(v => v.MemberNames.Contains(nameof(SocialSecurityNumber)));

        TrySetProperty(ref _socialSecurityNumber, value, out IReadOnlyCollection<ValidationResult> errors);

        _errors.AddRange(errors);
        OnPropertyChanged(nameof(Errors));
        OnPropertyChanged(nameof(ErrorsHaveI));
    }
}

In the View, the bindings for the properties are not different from the other samples:

<TextBox Text="{x:Bind ViewModel.NotYoda.SocialSecurityNumber, Mode=TwoWay}"
            PlaceholderText="Social Security Number" />
<TextBlock Text="{x:Bind ViewModel.NotYoda.SocialSecurityNumber, Mode=TwoWay}" />

The error icon is of course bound to the custom error properties:

<SymbolIcon Symbol="ReportHacked"
            Foreground="Red"
            Visibility="{x:Bind ViewModel.NotYoda.ErrorsHaveI, Mode=OneWay}"
            HorizontalAlignment="Right">
    <ToolTipService.ToolTip>
        <TextBlock Text="{x:Bind ViewModel.NotYoda.Errors, Mode=OneWay}"
                    Foreground="Red" />
    </ToolTipService.ToolTip>
</SymbolIcon>

Our sample app displays the current (valid) value next to the input boxes:

TrySetProperty

The shape of things to come

If you compare the different ViewModels in our sample app, you’ll definitely observe the copy/paste patterns around most of the calls to SetProperty() and OnPropertyChanged(). In a future version, MVVM Toolkit will be enhanced with property attributes that will generate the source code for these – as illustrated in this tweet from the author:

WhatsNext

We’ll keep you informed on this. In mean time, our sample app lives here on GitHub.

Enjoy!

A lap around the Microsoft MVVM Toolkit

In this article we’ll walk through a UWP sample app to experiment with the features of the new Microsoft.Toolkit.Mvvm package that is part of the Microsoft Community Toolkit.

MVVM

MVVM is a software architectural pattern introduced by Microsoft in 2005 to support the development of XAML apps, originally in WPF and later on in Silverlight. MVVM stays relevant to the more recent XAML environments such as UWP, Xamarin (MAUI), the Uno platform, and WinUI.

In a nutshell MVVM allows you to separate UI logic from business logic by dividing your code into

  • Models that represent data or information – think ‘domain objects’ or ‘entities’,
  • Views that represent the structure and layout that the user interacts with – think ‘pages’ and ‘controls’, and
  • ViewModels that express Model data and business logic through methods, properties and commands that are accessible to the Views,  preferably via declarative data-binding.

MVVMCore

MVVM requires the strong data-binding capabilities that we see in XAML through its {Binding} and {x:Bind} markup extensions. The pattern was also implemented in other technology stacks such as AngularJS/Angular.io, Ext JS and Vue.js.

Microsoft started recommending MVVM for XAML 15 years ago and they still do. Oddly enough, they only provided ‘bindable controls’ and never came up with official helper classes (like base classes that implement INotifyPropertyChanged or ICommand) or an MVVM development framework (with event aggregation, messaging, or viewmodel location). The only exception is the Composite Application Library, which later grew into Prism. Regarding MVVM, Microsoft developers always had to rely on (Open Source) third parties, of which the most popular (in alphabetical order) are/were Caliburn, MVVM Light, and Prism.

We had great experiences with each of these frameworks. However -except for Prism- none of them are still actively maintained. We assume that the ecosystem for XAML apps is evolving too rapidly for the maintainers of larger Open Source libraries. Indeed none of the existing MVVM frameworks was ever designed with .NET Core, Uno, MAUI or WinUI 3 in mind…

Maybe it’s time for a new wind to blow.

Enter Windows MVVM Toolkit

The Microsoft.Toolkit.Mvvm package is a modern, fast, and modular MVVM library that is part of the Windows Community Toolkit (WCT). The package targets .NET Standard 2.* so it can be used on

  • any .NET app platform: UWP, WinForms, WPF, Xamarin, Uno, WinUI and more, and on
  • any .NET runtime: .NET Native, .NET Core, .NET Framework, or Mono.

Its API surface is the same in all environments, making it perfect for building shared libraries.

The object model and terminology are definitely inspired by MVVM Light and the development team is aiming to provide a smooth migration path from MVVM Light to the new toolkit. Apart from functionality WCT Toolkit also pays high attention to performance. Many benchmarks like this one (on the Messenger class) are continuously run during the development:

perf2

The package comes with documentation and a nice sample app. WCT MVVM is currently in ‘preview 4’ so everything is still work in progress.

A UWP Sample App

A few months ago this GitHub issue revealed the initial feature set of Microsoft MVVM Toolkit, preliminary documentation, and even an operational preview package. We decided to create a little UWP app to test that package. Here’s how the home page looks like – standard clean WinUI 2.5:

HomePage

We’ll use this app throughout this article to explore the features of the new MVVM Toolkit in town.

Core classes

The Building Blocks page of the sample app illustrates the core classes for data binding and commanding:

BuildingblocksPage

ObservableObject

ObservableObject provides a base class for types to implement INotifyPropertyChanged and INotifyPropertyChanging – typically Models and ViewModels. You may have encountered similar helpers in other frameworks under the name ObservableBase, BindableBase, or NotifyPropertyChanged. Typically such a class comes with an easy way to raise the PropertyChanged event in property Setters, and that’s exactly what SetProperty() does.

Here’s what it looks like in one of our Model classes:

public class SuperHero : ObservableObject
{
    private string _name;

    public string Name
    {
        get => _name;
        set => SetProperty(ref _name, value);
    }

    // ...
}

Here’s another example from the sample app, this time for a ViewModel – the one that is bound to the BuildingBlocksPage View:

public class BuildingBlocksPageViewModel : ObservableObject
{
    private SuperHero _superHero;

    public SuperHero SuperHero
    {
        get => _superHero;
        set => SetProperty(ref _superHero, value);
    }

    // ...

}

Here’s how the ViewModel is declaratively bound to the View as its DataContext:

<Page.DataContext>
    <viewModels:BuildingBlocksPageViewModel x:Name="ViewModel" />
</Page.DataContext>

When we change a property on the SuperHero, the UI will update:

ViewModel.SuperHero.Nemesis = _nemeses[rnd.Next(0, 5)];

When the property that you want to monitor is a Task<T>, then you can use SetPropertyAndNotifyOnCompletion() instead of SetProperty(). It wil set the property but with the help of an internal TaskNotifier<T> it will delay the notification to when the task was completed:

private TaskNotifier<string> _saveTheUniverseTask;

public Task<string> SaveTheUniverseTask
{
    get => _saveTheUniverseTask;
    private set
    {
        SetPropertyAndNotifyOnCompletion(ref _saveTheUniverseTask, value);
    }
}

There’s even an overload that allows you to register a callback for when the task finishes. Here’s the ViewModel code triggered by the save button on the sample page. It assigns a new value to the task, and then starts it:

public async Task SaveTheUniverse()
{
    SaveTheUniverseTask = new Task<string>(
        () =>
        {
            Task.Delay(2000).Wait();

            if (rnd.Next(2) > 0)
            {
                return $"We're doomed, I lost my {SuperHero.Tool}.";
            }

            return "We're saved ... this time.";
        }
    );

    _saveTheUniverseTask.Start();
}

The task was made observable, so you can monitor its status and result. A simple binding suffices to follow up on the Status [note: The sample app has some extra code to reveal more statuses than ‘initial’ and ‘completed’.]:

<Run Text="{x:Bind ViewModel.SaveTheUniverseTask.Status, Mode=OneWay}" />

We needed to add some extra code to bind to the Result of the task, since UWP XAML does not allow you to bind to a generic. Here’s a ‘wrapper’ property for the result:

public string SaveTheUniverseTaskResult => 
	_saveTheUniverseTask.Status == TaskStatus.RanToCompletion 
	? _saveTheUniverseTask.Result 
	: "(hold your breath)";

And again, the declarative binding:

<Run Text="{x:Bind ViewModel.SaveTheUniverseTaskResult, Mode=OneWay}" />

RelayCommand

The RelayCommand class – a.k.a. DelegateCommand in some frameworks- and its generic and asynchronous siblings provide a default implementation of the ICommand interface. It’s used to declaratively bind events in UI controls to methods in the viewmodel. In the sample app the BuildingBlocksPageViewModel has the following method to toggle its data provider:

private void SwitchDataProvider()
{
    if (_dataProvider is RedDataProvider)
    {
        DataProvider = new BlueDataProvider();
    }
    else
    {
        DataProvider = new RedDataProvider();
    }

    SuperHero = _dataProvider.SuperHero();
}

To trigger this method from a button, we declare a property of the ICommand type:

public ICommand SwitchDataProviderCommand { get; }

Then we let a RelayCommand refer to it:

SwitchDataProviderCommand = new RelayCommand(SwitchDataProvider);

In the view we can now bind the button’s Command property to the ViewModel’s property of type ICommand:

<Button Command="{x:Bind ViewModel.SwitchDataProviderCommand}" />

AsyncRelayCommand extends the ICommand behavior with support for asynchronous operations. Here’s an example of an asynchronous data provider switch:

private async Task SwitchDataProviderAsync()
{
    await Task.Delay(1000);

    SwitchDataProvider();
}

The corresponding property is defined as IAsyncRelayCommand:

public IAsyncRelayCommand SwitchDataProviderAsyncCommand { get; }

And assigned to an AsyncRelayCommand instance:

SwitchDataProviderAsyncCommand = new AsyncRelayCommand(SwitchDataProviderAsync);

IAsyncRelayCommand inherits from ICommand, so you can bind it to a Button’s Command:

<Button Command="{x:Bind ViewModel.SwitchDataProviderAsyncCommand}" />

The ExecutionTask property gives you access to the underlying Task, so you can monitor it. There’s also a convenient IsRunning property that indicates when the task is … running. You can use this to display a busy indicator, such as a ProgressRing. Here’s how such binding looks like:

<winui:ProgressRing
   IsActive="{x:Bind 
	ViewModel.SwitchDataProviderAsyncCommand.IsRunning, 
	FallbackValue=False, 
	Mode=OneWay}" />

ObservableValidator

ObservableValidator is an ObservableObject that hosts a default implementation of INotifyDataErrorInfo. This enables Models and ViewModels to implement validation rules and expose validation results. INotifyDataErrorInfo used to be an important interface some years ago, when all out-of-the-box controls in e.g. Windows Forms, ASP.NET Forms, and WPF came with error templates that implemented the UI part of this interface. It looks like the built-in class comments in the validation annotation attributes are still living in that era – not really reassuring for today’s .NET Client developers:

RegexValidator

In the modern XAML stacks you need to do all of the control templating manually or rely on a third-party control library. But here’s the good news: rumor has it that WinUI 3 will bring back error templates for XAML controls, so we welcome this WCT MVVM Toolkit’s ObservableValidator very much.

The ObservableValidator class comes with

  • members that implement the INotifyDataErrorInfo interface (HasErrors, GetErrors(), ErrorsChanged, …), 
  • overloads of SetProperty() that allow you to specify whether or not validation should run on the assignment of a new property value,
  • a TrySetProperty() that does not assign the value if it induces validation errors, and 
  • support for all kinds of validation attributes from the System.Component.DataAnnotations namespace.

Here’s the StudyGroup class from our sample app. Its properties are decorated with validation rules on requirement, length, numerical range, and regular expression pattern:

public class StudyGroup : ObservableValidator
{
    [Required(ErrorMessage = "Topic is Required")]
    [MinLength(2, ErrorMessage = "Topic should be longer than one character")]
    public string Topic
    {
        get => _topic;
        set => SetProperty(ref _topic, value, true);
    }

    [Range(2009, 2015, ErrorMessage = "Class should be from 2009 to 2015")]
    public int Class
    {
        get => _class;
        set => SetProperty(ref _class, value, true);
    }

    [RegularExpression(@".*[pP]aintball.*", ErrorMessage = "Hobbies should contain 'Paintball'.")]
    public string Hobbies
    {
        get => _hobbies;
        set => SetProperty(ref _hobbies, value, true);
    }

    // ...
}

Many more validation attributes exist. Some allow you to compare the new value of a property to the old one, or compare the value of two properties within the instance. It’s also very easy to roll your own custom validation attribute.

Using the INotifyDataErrorInfo members a View can react appropriately to the the validation state of its ViewModels. In our sample app we decided to let StudyGroup expose an Errors string with the concatenated list of validation errors. A symbol icon with a tooltip displays the messages:

<SymbolIcon Symbol="ReportHacked"
            Foreground="Red"
            Visibility="{x:Bind ViewModel.StudyGroup.HasErrors, Mode=OneWay}"
            HorizontalAlignment="Right"
            Margin="0 4">
    <ToolTipService.ToolTip>
        <TextBlock Text="{x:Bind ViewModel.StudyGroup.Errors, Mode=OneWay}"
                    Foreground="Red" />
    </ToolTipService.ToolTip>
</SymbolIcon>

Here’s how it looks like in action:

Validation

Messaging

In an MVVM application, ViewModels as well as other components may need to communicate with each other in a loosely coupled way. Most MVVM libraries have a Messenger infrastructure for this purpose.

MVVMMessenger

Microsoft MVVM Toolkit’s messaging API allows independent modules to exchange information via messages through a publish/subscribe mechanism. Our sample app hosts two scenario’s. Both scenario’s have different View/ViewModel pairs (a.k.a. “Modules”) on the same page. They are unaware of each other, but need to exchange information about the current ‘theme’.

Here’s the first messaging scenario:

  • the ViewModel of the Shell hosts the current ‘Theme’ (just a color),
  • when the sample page opens, all modules request the current theme and adapt their UI,
  • a ‘Theme Module’ allows to update this current theme through a ToggleSwitch,
  • the other modules update their UI immediately, and
  • the ‘Theme’ is not a global variable (and neither is the ShellViewModel).

Here’s how the page looks like:

MessengerPage

Messages

In this scenario we use two of the message base classes that come with MVVM Toolkit. Here’s the definition of the message that is sent by the theme module when the theme changed, a ValueChangedMessage<T>:

public class ThemeChangedMessage : ValueChangedMessage<Theme>
{
    public ThemeChangedMessage(Theme value) : base(value)
    {
    }
}

Here’s the definition of the message that all modules use to get the current theme, a RequestMessage<T>:

public class ThemeRequestMessage : RequestMessage<Theme>
{
}

ObservableRecipient and Messenger

All ViewModels in this scenario inherit from ObservableRecipient  (which was called ViewModelBase in Preview 1) to get access to an IMessenger instance via the Messenger property.

Here’s the ShellViewModel from our sample app. It switches to the default theme, and starts listening for the ThemeRequestMessage (which it answers with the theme) and the ThemeChangedMessage (which updates the theme). In a production app, the theme would probably be persisted in the Settings.

Here’s the definition of the ShellViewModel:

public class ShellViewModel : ObservableRecipient
{
    private Theme _theme = Theme.Default;

    public ShellViewModel()
    {
        Messenger.Register<ThemeRequestMessage>(this, m =>
        {
            m.Reply(_theme); 
        });

        Messenger.Register<ThemeChangedMessage>(this, m =>
        {
            _theme = m.Value;
        });
    }
}

Here’s the call that the theme-aware modules make to fetch the current theme when they are displayed:

_theme = Messenger.Send<ThemeRequestMessage>();

Just like the ShellViewModel they also subscribe to the ThemeChangedMessage to update:

Messenger.Register<ThemeChangedMessage>(this, m =>
   {
      // ...
   }

Sending a message is as easy as calling Send() on the Messenger:

Messenger.Send(new ThemeChangedMessage(_theme));

Under the hood, the messaging infrastructure is using classic .NET Events and Delegates. It’s important that ViewModels unsubscribe their callbacks when they stop listening for messages. The IMessenger interface comes with several Unregister() members, of which this one is the most radical:

Messenger.UnregisterAll(this);

Generally a ViewModel should only send messages and respond to messages when it is in an operational state – i.e. when it is bound to a loaded View. This operational state can be defined with the IsActive property. When the property becomes true, the OnActivated() method is called, so that’s the appropriate place to register your callbacks:

protected override void OnActivated()
{
    base.OnActivated();

    Messenger.Register<ThemeChangedMessage>(this, m =>
    {
        // ...
    });
}

When IsActive becomes false, OnDeactivated() is called. Its default implementation unregisters all callbacks, so in most cases you need to do … nothing.

Here’s how a View in the sample app marks out the operational state of its ViewModel:

private void ColorModule_Loaded(object sender, RoutedEventArgs e)
{
    _colorModuleViewModel.IsActive = true;
}

private void ColorModule_Unloaded(object sender, RoutedEventArgs e)
{
    _colorModuleViewModel.IsActive = false;
}

The default Messenger in the current version of WCT MVVM uses WeakReferences under the hood, so dangling ViewModels with non-unregistered callbacks will eventually be cleaned up by the Garbage Collector. If you’re sure that your app nicely unregisters all messaging handlers, then you may switch to the original (faster!) Messenger that relies on strong references. Here’s how to do this:

public class ShellViewModel : ObservableRecipient
{
    public ShellViewModel() : base(StrongReferenceMessenger.Default)
    {}

    // ...

}

Message Tokens

Some apps may host groups of modules that listen to different variations of messages. Message tokens can be very useful to reduce the communication overhead. Here’s a screenshot of our sample app – the page is based of a real-life scenario and shows four modules:

  • one that broadcasts all pillow-and-blanket war casualties,
  • one that is only interested in pillow victims,
  • one that is only interested in blanket victims, and
  • one that is interested in all casualty messages.

MessengerWithTokenPage

The message itself is empty – it’s good to see that no specific base class is needed:

public class CasualtyMessage // No specific base class needed.
{
}

When a casualty is reported, the broadcast module sends the message, and uses the victim’s party (pillow or blanket) as token:

Messenger.Default.Send<CasualtyMessage, string>(new CasualtyMessage(), "pillow");
// OR
Messenger.Default.Send<CasualtyMessage, string>(new CasualtyMessage(), "blanket");

The next to modules register a callback for CasualtyMessage, but only for their own token:

Messenger.Register<CasualtyMessage, string>(this, "blanket", m => { OnCasualtyMessageReceived(); });

The fourth module registers twice, once for each token. It’s impossible to receive tokenized messages without tokenized registration. So in out sample app, the following will not receive a single message:

// Does not see the messages with a token.
Messenger.Register<CasualtyMessage>(this, m => { OnCasualtyMessageReceived(); });

In our sample app –and many other- Enumations would make an ideal candidate for tokens. After all: the use of hardcoded strings is risky business. Unfortunately token classes are required to implement IEquatable<T> as you see in the definition:

void Register<TMessage, TToken>(object recipient, TToken token, Action<TMessage> action)
            where TMessage : class
            where TToken : IEquatable<TToken>;

This constraint rules out the use of Enumerations. So we created the Party class that looks and feels like an Enum, but implements the interface:

public sealed class Party : IEquatable<Party>
{
    public static readonly Party Pillow = new Party(1, nameof(Pillow));
    public static readonly Party Blanket = new Party(2, nameof(Blanket));

    public string Name { get; private set; }

    public int Id { get; private set; }

    private Party(int id, string name)
    {
        Id = id;
        Name = name;
    }

    public bool Equals(Party other)
    {
        return Id == other.Id;
    }
}

The class can be used as token, instead of String, and we ended up with a much better maintainable code:

Messenger.Register<CasualtyMessage, Party>(this, Party.Blanket, m => { OnCasualtyMessageReceived(); });
Messenger.Default.Send<CasualtyMessage, Party>(new CasualtyMessage(), Party.Pillow);

Dependency Injection

In an MVVM architecture your code base is divided into Views, ViewModels, and Models. Any other reusable code should be grouped into Services. There should be a way to locate and call these services from any component.

MVVMServices

ServiceLocator and DependencyInjection are two (related) common patterns to implement this. These patterns are independent from MVVM, but having a service container available in an MVVM app is useful/required in many cases, like

  • when you want to cache expensive ViewModels instead of recreating them every time a View is instantiated, or
  • when you want to access the messenging infrastructure from a non-ObservableRecipient (like a View).

WCT MVVM comes with an Ioc helper class around the IServiceProvider interface. It supports creating and using a service container, but does not come itself with another service provider. This allows you to stick to your favorite dependency injection framework: Autofac, Ninject, Castle Windsor, Microsoft.Extensions.DependencyInjection or any other. Our sample app uses that last one – very popular in ASP.NET Core:

DependencyInjectionNuGet

Here’s a screenshot of the test page, it demonstrates fetching services from the container, and constructor injection:

InversionOfControlPage

When the app starts up, it registers its services in the container (the Messenger instance, an expensive ViewModel, a service for Logging, and one for Dialogs) and builds the provider:

Ioc.Default.ConfigureServices
        (new ServiceCollection()
            .AddSingleton<IMessenger>(WeakReferenceMessenger.Default)
            .AddSingleton<ILoggingService, DebugLoggingService>()
            .AddSingleton<ColorModuleViewModel>()
            .AddSingleton<ModalView>()
            .BuildServiceProvider()
        );

At runtime, the app can now pull services out of the container with a call to one of the GetService() family members. Here’s how the expensive ViewModel is fetched by a View:

var viewModel = Ioc.Default.GetService<ColorModuleViewModel>();

And here’s a View getting a reference to the Messenger to send a message:

Ioc.Default.GetService<IMessenger>()
	.Send<CasualtyMessage, Party>(new CasualtyMessage(), Party.Pillow);

For the sake of completeness (and unrelated to MVVM) the sample app also demonstrates constructor injection. Here’s how a ViewModel fetches the Logging and the Dialog services when it’s instantiated:

public ColorModuleViewModel(ILoggingService loggingService, ModalView modalView)
{
    // ...
}

Wait, there’s more!

The new WCT MVVM library is familiar, fast, and flexible. But there’s more coming your way than just the NuGet package. In the near future you may also expect:

In mean time our sample UWP app lives here on Github.

Enjoy!