XAML Back to Basics #16: Custom Grouping

How to implement custom grouping


XAML Basics Series Index Page

The next post in the series originally written by Beatriz Stollnitz. Original post available on Github.

How to implement custom grouping

The previous post in this series shows how to group items based on the value of a certain property. In a real-world scenario you may want to group your items based on some other logic. With this in mind, WPF Data Binding provides a way for you to write custom code and specify how you want to group your items. This allows maximum flexibility; you can group your items pretty much any way you can think of.

In this post I’ll look at how to group items based on their type and an example of how to do custom Grouping.

My data source in this sample is of type ObservableCollection<object>, and contains some objects of type GreekGod and others of type GreekHero. My goal is to group all the items of type GreekGod in a group called “Greek Gods” and group all GreekHero items under the group “Greek Heroes”. This is what the markup looks like:

<Window.Resources>
    <local:GreekGodsAndHeroes x:Key="GodsAndHeroes" />
    <local:GroupByTypeConverter x:Key="GroupByTypeConverter"/>

    <CollectionViewSource x:Key="cvs" Source="{Binding Source={StaticResource GodsAndHeroes}}">
        <CollectionViewSource.GroupDescriptions>
            <PropertyGroupDescription Converter="{StaticResource GroupByTypeConverter}"/>
        </CollectionViewSource.GroupDescriptions>
    </CollectionViewSource>
</Window.Resources>

Notice that this time, instead of setting PropertyName in PropertyGroupDescription, I set the Converter property. This Converter is defined in the code behind and contains the logic to divide the data items in groups.

public class GroupByTypeConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is GreekGod)
        {
            return "Greek Gods";
        }
        else if (value is GreekHero)
        {
            return "Greek Heroes";
        }
        return null;
    }
}

All the items that return the same value in the Converter will be grouped together. In this scenario I am grouping the items based on their type and my groups are of type string. Remember that you can use a Converter to group your items some other way. Notice also that the groups don’t have to be a string, they can be any object you want.

Just like in the previous post, I want to display the groups and items in a TreeView.

<TreeView ItemsSource="{Binding Source={StaticResource cvs}, Path=Groups}" Width="200">
</TreeView>

In this case, however, templating the items is not as obvious. When the items are all of the same type this is really easy to achieve with a chain of HierarchicalDataTemplates and a DataTemplate for the leaf nodes. In this scenario we need a HierarchicalDataTemplate for the groups and one of two DataTemplates for the leaf nodes, depending on their type.

My first approach to this was to have those 3 templates in the resources and set their DataType property instead of giving them a key (with x:Key). This does not work because when you use a HierarchicalDataTemplate to template a group and do not set its ItemTemplate property, that same template is used for the lower levels of the hierarchy. This behavior is useful when all the levels have items of the same type (for example, when using a TreeView to display a hierarchy of directories in a computer).

My second approach was to set the ItemTemplateSelector property of the HierarchicalDataTemplate to a template selector that decides the correct template to use based on the type of the leaf item. Unfortunately there is a bug in the ItemTemplateSelector property of HierarchicalDataTemplate that prevents this from working. Once the bug is fixed, this will be the correct way to specify the templates.

My third and final approach was to move the template selector to the TreeView and add one more “if” branch to deal with deciding what type to return for the groups (which are of type CollectionViewGroup).

public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
    string templateKey;
    if (item is CollectionViewGroup)
    {
        templateKey = "GroupTemplate";
    }
    else if (item is GreekGod)
    {
        templateKey = "GreekGodTemplate";
    }
    else if (item is GreekHero)
    {
        templateKey = "GreekHeroTemplate";
    }
    else
    {
        return null;
    }
    return (DataTemplate)((FrameworkElement)container).FindResource(templateKey);
}

<Window.Resources>
    <local:GodHeroTemplateSelector x:Key="GodHeroTemplateSelector" />
    (...)
</Window.Resources>

<TreeView ItemsSource="{Binding Source={StaticResource cvs}, Path=Groups}" ItemTemplateSelector="{StaticResource GodHeroTemplateSelector}" Width="200">
</TreeView>

For each of the items displayed in the TreeView, this template selector looks up the appropriate (Hierarchical)DataTemplate in the resources.

Here is a screenshot of the completed sample:

WPF Source Code

WPF

UWP/WinUI Notes
GroupDescriptions aren’t supported on UWP/WinUI so the Greek Gods and Heros are grouped using Linq in the codebehind of the page.

The TreeView isn’t supported on Uno at the moment – due in v3.1

The Treview on UWP/WinUI doesn’t use a HierarchicalDataTemplate to define the hierarchy. Instead it uses TreeViewItem within a DataTemplate to define where there are child nodes.

UWP Source Code

UWP

WinUI with Uno and WinUI Desktop Source Code

WinUI – Desktop

Zero Installer, Zero MSIX, Zero Packaging with .NET Single File Apps

A feature that was added to .NET Core apps was the ability to publish as a single file. As we approach the release of .NET 5 I thought it worthwhile taking a look at the options for publishing Windows Forms and WPF applications with dotnet publish. For this post we’re going to work with a … Continue reading “Zero Installer, Zero MSIX, Zero Packaging with .NET Single File Apps”

A feature that was added to .NET Core apps was the ability to publish as a single file. As we approach the release of .NET 5 I thought it worthwhile taking a look at the options for publishing Windows Forms and WPF applications with dotnet publish.

For this post we’re going to work with a very basic Windows Forms and WPF application: WinFormsSingleFileSample and WpfSingleFileSample. To create these applications I used the Windows Forms (WinForms) Application and WPF Application project templates in Visual Studio 16.8 preview 2 (with .NET 5 RC1 installed). After creating the applications I ran them from within Visual Studio just to confirm there was no issue with the creation process – I always recommend doing this otherwise you end up chasing your tail if something is broken and you only realise after doing hours of work.

dotnet publish

We’ll start of by calling dotnet publish using the Release configuration (typically the Debug configuration will be used if the Configuration parameter isn’t specified):

dotnet publish -r win-x64 /p:Configuration=Release

Here’s the output for this command. Note that if this is the first time you’ve called dotnet build/publish for a specific architecture (using the -r win-x64 flag), it may take a few minutes to restore some of the dependencies.

C:\temp\WinFormsSingleFileSample>dotnet publish -r win-x64 /p:Configuration=Release
Microsoft (R) Build Engine version 16.8.0-preview-20451-02+51a1071f8 for .NET
Copyright (C) Microsoft Corporation. All rights reserved.
Determining projects to restore…
Restored C:\temp\WinFormsSingleFileSample\WinFormsSingleFileSample\WinFormsSingleFileSample.csproj (in 86 ms).
You are using a preview version of .NET. See: https://aka.ms/dotnet-core-preview
WinFormsSingleFileSample -> C:\temp\WinFormsSingleFileSample\WinFormsSingleFileSample\bin\Release\net5.0-windows\win-x64\WinFormsSingleFileSample.dll
WinFormsSingleFileSample -> C:\temp\WinFormsSingleFileSample\WinFormsSingleFileSample\bin\Release\net5.0-windows\win-x64\publish\

The final line includes the output folder for published application. If we look in this folder there are 293 items (280 files and a number of language folders). You can easily zip this folder and copy it to a different machine and run the application but it would be nice to have just a single output.

Self Contained

One option to reduce the number of files to be deployed is to provide the SelfContained parameter. The default value for the SelfContained parameter is true which means that you can copy the output folder to any machine without worrying about whether .NET has been installed.

dotnet publish -r win-x64 /p:Configuration=Release /p:SelfContained=false

Setting SelfContained to false results in a folder containing only 5 items.

Of course, you now need to manage the deployment of .NET dependencies (More information at https://docs.microsoft.com/en-us/dotnet/core/deploying/deploy-with-cli#self-contained-deployment)

PublishSingleFile

Let’s back up and remove the SelfContained parameter, since we’re really interested in distributing an app and not having to worry about any dependencies. This time we’re going to include the PublishSingleFile parameter

dotnet publish -r win-x64 /p:Configuration=Release /p:PublishSingleFile=true

The output on Windows isn’t exactly a single file. There are 11 files in the output folder – these are the native dependencies required in order to run the application.

For more information on why there are multiple files on Windows, check out the preview 8 blog post by Richard Lander from the dotnet team. This is also covered in the comments of this github issue.

IncludeAllContentForSelfExtract

There is still a mechanism where you can achieve a single file output, which is to include the IncludeAllContentForSelfExtract parameter.

dotnet publish -r win-x64 /p:Configuration=Release /p:PublishSingleFile=true /p:IncludeAllContentForSelfExtract=true

The output of this command is two files, one of which is the symbols file (i.e. the pdb file). To deploy this application you can just copy the .exe to the target machine.

One thing to note about the IncludeAllContentForSelfExtract parameter is that when you run the application for the first time, the native dependencies will be extracted which can result in a small delay in launching the app. The managed libraries will be loaded directly from the exe.

PublishTrimmed

Our single file application is currently ~146Mb, which seems a lot for an application that is literally an empty window. Let’s include the PublishedTrimmed file to see if we can optimise the output.

dotnet publish -r win-x64 /p:Configuration=Release /p:PublishSingleFile=true /p:IncludeAllContentForSelfExtract=true /p:PublishTrimmed=true

This command takes a little longer to run but now the output size is just ~83Mb which is a significant improvement. More information on application trimming

PublishReadyToRun

The last parameter we’re going to add is PublishReadyToRun. This essentially invokes AOT compilation, which in theory improves startup performance for the app. I say in theory because given the incredibly simple app we’re dealing with here, it’s unlikely we’ll see any actual performance improvement.

dotnet publish -r win-x64 /p:Configuration=Release /p:PublishSingleFile=true /p:IncludeAllContentForSelfExtract=true /p:PublishTrimmed=true /p:PublishReadyToRun=true  

Now our application has ballooned back up to ~138Mb.

Hopefully in this post you’ll have seen some of the options available to you when publishing Windows Forms (WinForms) and/or WPF applications.

Note: At the time of writing there is a bug with WPF applications where the PublishSingleFile parameter generates a binary that won’t launch in some cases. According to the dotnet team this is to be fixed with RC2 of .NET 5.

XAML Back to Basics #15: TreeView

How to display grouped data in a TreeView

XAML Basics Series Index Page

The next post in the series originally written by Beatriz Stollnitz. Original post available on Github.

How to display grouped data in a TreeView

The TreeView control is great at displaying structured data using the HierarchicalDataTemplate (see Karsten’s blog post on this topic). But what do you do if the data you’re given is not structured hierarchically? In this post, I will show you how to create that hierarchy from a flat list of data items, using the grouping feature of data binding.

I am using the same Animal data source I used in my last post. Grouping the Animals by Category is done the same way as in my last sample:

<local:Animals x:Key="animals"/>

<CollectionViewSource x:Key="cvs" Source="{Binding Source={StaticResource animals}, Path=AnimalList}">
    <CollectionViewSource.GroupDescriptions>
        <PropertyGroupDescription PropertyName="Category"/>
    </CollectionViewSource.GroupDescriptions>
</CollectionViewSource>

We now have the data in a hierarchical form. In this particular case it has only one level of groups, and another level with the animals. You can easily imagine that by adding more GroupDescriptions you would end up with a deeper hierarchy.

When binding to a CollectionViewSource, the Binding object knows to grab the CollectionViewSource’s View property. This property returns the custom view (of type ICollectionView) that CollectionViewSource creates on top of the data collection (where the grouping is applied). In our scenario, we want to bind to the hierarchy we created with grouping, or in other words, we want to bind to the groups. We can get to this data by binding to the Groups property in ICollectionView:

<TreeView ItemsSource="{Binding Source={StaticResource cvs}, Path=Groups}" ItemTemplate="{StaticResource categoryTemplate}" Width="200">
</TreeView>

When using data binding’s grouping feature, each group of items is wrapped in a CollectionViewGroup object. We can access the name of the group (the property we’re grouping by) by using CollectionViewGroup’s Name property, and we can get to the items that belong to the group through the Items property. This is all the information we need in order to make a HierarchicalDataTemplate that will display the Category of each animal and specify the animals that belong to it:

<HierarchicalDataTemplate x:Key="categoryTemplate" ItemsSource="{Binding Path=Items}" ItemTemplate="{StaticResource animalTemplate}">
    <TextBlock Text="{Binding Path=Name}" FontWeight="Bold"/>
</HierarchicalDataTemplate>

Finally we need a DataTemplate for the leaf nodes, which specifies how we want the Animal data to be displayed. In this case, we are interested in displaying the Name property of each Animal. Notice that the HierarchicalDataTemplate’s ItemTemplate property points to this template.

<DataTemplate x:Key="animalTemplate">
    <TextBlock Text="{Binding Path=Name}"/>
</DataTemplate>

Here is the result of the completed sample:

WPF Source Code

WPF

UWP/Uno Notes
Since UWP (and thus Uno and WinUI) doesn’t support grouping in the CollectionViewSource, we’ve provided an alternative implementation that makes use of Linq’s IGrouping and an ItemTemplateSelector to switch between templates based on whether it’s a Category or an Animal node in the tree.

Uno doesn’t currently support the TreeView, but it’s expected to land in the v3.1 timeframe.

UWP Source Code

UWP

WinUI with Uno and WinUI Desktop Source Code

WinUI – Desktop

XAML Back to Basics #14: Sorting and Grouping

How to sort groups of data items

XAML Basics Series Index Page

The next post in the series originally written by Beatriz Stollnitz. Original post available on Github.

How to sort groups of data items

With the introduction of CollectionViewSource, we are now able to do basic grouping of data items in an ItemsControl without using code. In this post I will show you how to group items and sort those groups.

The data source of this sample consists of a list of objects of type Animal. Animal has a Name and a Category (which is an enumeration). I want to group the items depending on their Category. This is easily done in markup by using CollectionViewSource:

<Window.Resources>
    <local:Animals x:Key="animals"/>

    <CollectionViewSource x:Key="cvs" Source="{Binding Source={StaticResource animals}, Path=AnimalList}">
        <CollectionViewSource.GroupDescriptions>
            <PropertyGroupDescription PropertyName="Category"/>
        </CollectionViewSource.GroupDescriptions>
    </CollectionViewSource>

    <DataTemplate x:Key="animalTemplate">
        <TextBlock Text="{Binding Path=Name}" Foreground="MediumSeaGreen"/>
    </DataTemplate>
</Window.Resources>

<ItemsControl ItemsSource="{Binding Source={StaticResource cvs}}" ItemTemplate="{StaticResource animalTemplate}"/>

As I explained in a previous post, CollectionViewSource creates a custom View over the source list through markup. A view is a layer on top of a source data list that allows us to group, sort, and filter items, as well as keep track of the currently selected item.

If you try the sample markup above, you will see the names of the animals, but no information about the groups. The next step is to provide a template to display the group titles. CollectionViewSource wraps each group of items in an object of type CollectionViewGroup, and we are interested in its “Name” property, which we can display using the following template:

<DataTemplate x:Key="categoryTemplate">
    <TextBlock Text="{Binding Path=Name}" FontWeight="Bold" Foreground="ForestGreen" Margin="0,5,0,0"/>
</DataTemplate>

In order to use this template for the group titles, we have to add it to the GroupStyle property of ItemsControl (which takes a collection of GroupStyle objects):

<ItemsControl ItemsSource="{Binding Source={StaticResource cvs}}">
    <ItemsControl.GroupStyle>
        <GroupStyle HeaderTemplate="{StaticResource categoryTemplate}" />
    </ItemsControl.GroupStyle>
</ItemsControl>

We could add more GroupStyles to the collection, in which case they would be applied to different levels of groups. (For simplicity, we just have one level of grouping in this sample.)

At this point, the groups and items display correctly, but we would like to sort the groups and the items within the groups. I’ve seen a few people approach this by looking for a specific “SortGroups” method or something similar. We didn’t design a special API to sort groups because you can accomplish that simply by sorting the items by the same property by which you are grouping:

<CollectionViewSource x:Key="cvs" Source="{Binding Source={StaticResource animals}, Path=AnimalList}">
    <CollectionViewSource.GroupDescriptions>
        <PropertyGroupDescription PropertyName="Category"/>
    </CollectionViewSource.GroupDescriptions>
    <CollectionViewSource.SortDescriptions>
        <scm:SortDescription PropertyName="Category" />
        <scm:SortDescription PropertyName="Name" />
    </CollectionViewSource.SortDescriptions>
</CollectionViewSource>

Adding two sort descriptions allows us to sort the groups first and then the items within the groups. Notice that because Category is an enumeration, sorting by that property will display the groups in the order they are defined in the enumeration (which may or may not be alphabetically). Name is of type string, so the leaf items will be displayed alphabetically.

This is a screenshot of the completed sample:

WPF Source Code

WPF

UWP Notes
The UWP CollectionViewSource doesn’t support grouping or sort, requiring the underlying data source to be grouped and sorted in advance.

UWP Source Code

UWP

Uno Notes
The Uno CollectionViewSource doesn’t handle grouped data source. Instead it presents the items in a single list.

WinUI Notes
The WinUI CollectionViewSource for both desktop and UWP is similar to the UWP implementation. As such it requires the data source to be grouped and sorted in advance.

WinUI with Uno and WinUI Desktop Source Code

WinUI – Desktop

XAML Back to Basics #13: DataTemplateSelector

How to display items in an ItemsControl using different templates

XAML Basics Series Index Page

The next post in the series originally written by Beatriz Stollnitz. Original post available on Github.

How to display items in an ItemsControl using different templates

I will show you two ways to display some items of a data bound collection differently from others. The rule of thumb is straightforward: if you want to differentiate items that are of the same type based on one of their properties, you should use DataTemplateSelector; if your data items are of different types and you want to use the types to differentiate them, then using implicit data templating is a simpler way to do this.

Let us consider the scenario where the source collection has elements that are all of the same type. In this case, the goal is to change the way they are displayed based on some property in the data element, and using a DataTemplateSelector is the way to go. In the sample code below, the ListBox is bound to a collection of Places, where Place is an object with properties Name and State. I want places in Washington state to be displayed differently from other places, so I defined two DataTemplates in the resources. Then I wrote a PlaceTemplateSelector that picks the correct DataTemplate based on the State property of a Place. Finally, I instantiated a ListBox whose ItemTemplateSelector DependencyProperty is set to the selector I defined.

<Window.Resources>    
    <local:Places x:Key="places" />

    <DataTemplate x:Key="washingtonTemplate">
        <Border Background="Lavender">
            <TextBlock Text="{Binding Path=Name}" Foreground="CornFlowerBlue" FontWeight="Bold"/>
        </Border>
    </DataTemplate>

    <DataTemplate x:Key="notWashingtonTemplate">
        <TextBlock Text="{Binding Path=Name}" Foreground="DarkSeaGreen" />
    </DataTemplate>

    <local:PlaceTemplateSelector WashingtonTemplate="{StaticResource washingtonTemplate}" NotWashingtonTemplate="{StaticResource notWashingtonTemplate}" x:Key="placeTemplateSelector" />
</Window.Resources>

<ListBox ItemsSource="{Binding Source={StaticResource places}}" ItemTemplateSelector="{StaticResource placeTemplateSelector}" Margin="10"/>

Here is the code for the PlaceTemplateSelector:

public class PlaceTemplateSelector : DataTemplateSelector
{
    private DataTemplate washingtonTemplate;

    public DataTemplate WashingtonTemplate
    {
        get { return washingtonTemplate; }
        set { washingtonTemplate = value; }
    }

    private DataTemplate notWashingtonTemplate;

    public DataTemplate NotWashingtonTemplate
    {
        get { return notWashingtonTemplate; }
        set { notWashingtonTemplate = value; }
    }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        Place place = (Place)item;

        if (place.State == "WA")
        {
            return washingtonTemplate;
        }
        else
        {
            return notWashingtonTemplate;
        }
    }
}

Consider now the scenario where the collection has objects with different types added to it. In this case, the goal is to template items differently depending on their type. In the sample code below, the ListBox is bound to a heterogeneous collection that contains both GreekGod and GreekHero objects.

<Window.Resources>
    <local:GreekGodsAndHeros x:Key="godsAndHeros" />
</Window.Resources>

<ListBox ItemsSource="{Binding Source={StaticResource godsAndHeros}}" Margin="10"/>

Sure, a DataTemplateSelector could be used to template the items by picking the correct DataTemplate depending on the type of the item passed to the SelectTemplate method, as I have seen a few people do. However, implicit data templating is a better way to do this because it accomplishes the same thing all in xaml (no need for code behind). To use a DataTemplate implicitly, instead of setting its key (with x:Key), I set the DataType property to the type I want it to be applied to.

<DataTemplate DataType="{x:Type local:GreekGod}">
    <Grid>
        <ColumnDefinition Width="100"/>
        <ColumnDefinition Width="*"/>
        <RowDefinition Height="Auto"/>
        <TextBlock Text="{Binding Path=GodName}" Grid.Column="0" Grid.Row="0" Foreground="Brown"/>
        <TextBlock Text="{Binding Path=GodDescription}" Grid.Column="1" Grid.Row="0" Foreground="Brown"/>
    </Grid>
</DataTemplate>

<DataTemplate DataType="{x:Type local:GreekHero}">
    <TextBlock Text="{Binding Path=HeroName}" FontWeight="Bold" Foreground="Red"/>
</DataTemplate>

Here is a screen shot of the completed sample:

WPF Source Code

WPF

UWP/Uno Notes

There is no support for implicit templating based on the type of data object. I’ve added an additional template selector which uses the type of the object to determine which template to use. The DataType attribute on the templates has been used to support x:Bind instead of Binding.

UWP Source Code

UWP

WinUI with Uno and WinUI Desktop Source Code

WinUI – Desktop

XAML Back to Basics #12: Dialogs

How to implement a data bound dialog box

XAML Basics Series Index Page

The next post in the series originally written by Beatriz Stollnitz. Original post available on Github.

How to implement a data bound dialog box

In this post I will show you how to implement a dialog box using data binding. While this may seem like a straightforward task at first glance, when using data binding it can be tricky to get the “OK” button of a dialog to commit the user’s changes and the “Cancel” button to discard them.

One possible approach is to allow the bindings to update the data source as the user is typing information into the dialog box, then undo the work done by the bindings if the user happens to press the “Cancel” button. I don’t like the “Cancel” scenario of this approach because the data source acquires values that are only kept temporarily. Besides, it requires additional logic in the application to remember the data when the dialog box opens and to revert back to that data if the user presses “Cancel”. This is a lot of work and quite confusing. Fortunately, there is an easier way to get the job done – by changing the value of UpdateSourceTrigger in your Bindings.

The main Window in this sample has a Button that launches the dialog box, and Labels that show the contents of the data source. When this app is loaded the Labels are empty. When the user opens the dialog box, enters data in the TextBoxes and presses OK, the Labels in the main Window display the data just entered. If the user presses Cancel instead, the Labels should remain empty.

<Button Click="ShowDialog" Width="100" Height="30">Show Dialog</Button>
<Label Grid.Row="0" Grid.Column="1" Name="Name" Margin="5" Content="{Binding Source={StaticResource source}, Path=Name}"/>
<Label Grid.Row="1" Grid.Column="1" Name="Comment" Margin="5" Content="{Binding Source={StaticResource source}, Path=Comment}"/>

private void ShowDialog(object sender, RoutedEventArgs args) { Dialog1 dialog = new Dialog1(); dialog.Owner = this; dialog.ShowDialog(); }

The dialog box contains TextBoxes data bound to the same data as the Labels and OK/Cancel Buttons. This is the markup that goes in the dialog box:

<TextBox Grid.Row="0" Grid.Column="1" Name="Name" Margin="5" Text="{Binding Source={StaticResource source}, Path=Name, UpdateSourceTrigger=Explicit}"/>
<TextBox Grid.Row="1" Grid.Column="1" Name="Comment" Margin="5" Text="{Binding Source={StaticResource source}, Path=Comment, UpdateSourceTrigger=Explicit}"/>
<Button Click="OKHandler" IsDefault="true" Margin="5">OK</Button>
<Button IsCancel="true" Margin="5">Cancel</Button>

The Binding object allows us to specify how to trigger updates to the data source through its UpdateSourceTrigger property. The default update trigger for the TextBox’s Text DP is “LostFocus”, which means that the data the user types is updated to the source when the TextBox loses focus. This is not what we want for this scenario though; we want the data to be updated only when the user presses the “OK” button. By changing the update trigger to “Explicit”, the data will not be updated to the source until we explicitly call the “UpdateSource()” method on the BindingExpression, which we can do in the handler for the “OK” button:

private void OKHandler(object sender, RoutedEventArgs args)
{
    BindingExpression bindingExpressionName = BindingOperations.GetBindingExpression(Name, TextBox.TextProperty);
    bindingExpressionName.UpdateSource();
    BindingExpression bindingExpressionComment = BindingOperations.GetBindingExpression(Comment, TextBox.TextProperty);
    bindingExpressionComment.UpdateSource();
    this.DialogResult = true;
}

The logic for the “OK” button is simple, but the “Cancel” is even simpler. Because we never allowed the values typed to update to the source, all we have to do is close the Window. This can be done by simply setting IsCancel=true on the Cancel button, no event handler necessary.

Here is a screen shot of the completed sample:

WPF Source Code

WPF

UWP Notes
The WPF code relies on what seems like magic in order to update the content on the Main page. For those familiar with XAML binding you may be surprised that this example works given that the DataSource class doesn’t implement INotifyPropertyChanged. There are definitely smarts built into WPF that will update all elements bound to the same source if one of its properties are updated, such as the case in this example. This does NOT work with UWP where you have to be explicit about raising PropertyChanged event in order for any elements bound to the source to update.

UWP also requires that the Mode of the Binding for the two TextBox elements be set to TwoWay

Additionally, the UWP ContentDialog has built in primary and secondary buttons to encourage a standard look and feel for dialogs.

Uno Notes
Currently the UpdateSourceTrigger attribute of the Binding expression isn’t respected. This means that any changes made in the dialog will be updated in the main page.

UWP Source Code

UWP

WinUI Notes

WinUI for Desktop, whilst respecting the UpdateSourceTrigger attribute, ends up looking more like UWP than WPF. The dialog needs to inherit from ContentDialog. There’s a need to explicitly set the XamlRoot and for some reason typing in the TextBox elements doesn’t work.

WinUI for UWP has issues with databound properties being changed in a ContentDialog and having to update on the main page. This is most likely a prerelease issue. Ironically the Uno platforms all update the content but again ignore the UpdateSourceTrigger attribute.

WinUI with Uno and WinUI Desktop Source Code

WinUI – Desktop

XAML Back to Basics #11: Multiple Linked Lists

How to synchronize ListBoxes displaying three levels of hierarchical data

XAML Basics Series Index Page

The next post in the series originally written by Beatriz Stollnitz. Original post available on Github.

How to synchronize ListBoxes displaying three levels of hierarchical data

The master-detail scenario with more than 2 levels is very common, and we made sure we have good support for it in WPF. I will show in this post three ways to sync selection of three ListBoxes, each displaying a different level of a hierarchy of data. In this sample, the first ListBox displays a list of mountain ski resorts. When the user selects a ski resort, the second ListBox gets updated with several lifts from that mountain. By selecting a particular lift, the third ListBox gets updated with ski runs that can be taken down from the top of that lift.

Here is the approach some developers might take when trying to get this scenario to work:

<Window.Resources>
    <local:Mountains x:Key="mountains" />
    <CollectionViewSource Source="{StaticResource mountains}" x:Key="cvs" />
</Window.Resources>
<ListBox ItemsSource="{Binding Source={StaticResource cvs}}" DisplayMemberPath="Name" Name="lb1" />
<ListBox ItemsSource="{Binding Source={StaticResource cvs}, Path=Lifts}" DisplayMemberPath="Name" Name="lb2" />
<ListBox ItemsSource="{Binding Source={StaticResource cvs}, Path=Lifts/Runs}" Name="lb3" />

Unfortunately this does not work as expected: lb1 and lb2 are in sync but lb3 is not. When creating a custom view on top of a collection by using CollectionViewSource, selection and currency are in sync by default. This is why lb1 and lb2 are in sync in this scenario. This markup does not use a custom view for the Lifts collection though – a default view is created internally instead. Default views do not have currency and selection in sync by default, which is the reason why lb2 and lb3 don’t sync.

There are at least three ways to have the three ListBoxes in sync.

The most obvious solution is to create a second CollectionViewSource for the Lifts collection and bind lb2 and lb3 to it:

<Window.Resources>
    (...)
    <CollectionViewSource Source="{Binding Source={StaticResource cvs}, Path=Lifts}" x:Key="cvs2"/>
</Window.Resources>
<ListBox ItemsSource="{Binding Source={StaticResource cvs}}" DisplayMemberPath="Name" Name="lb1" />
<ListBox ItemsSource="{Binding Source={StaticResource cvs2}}" DisplayMemberPath="Name" Name="lb2" />
<ListBox ItemsSource="{Binding Source={StaticResource cvs2}, Path=Runs}" Name="lb3" />

The second solution is to ignore CollectionViewSource, and let WPF create default views internally for us. Because default views don’t sync selection and currency by default, we have to override the default behavior by setting IsSynchronizedWithCurrentItem to true:

<ListBox ItemsSource="{Binding Source={StaticResource mountains}}" DisplayMemberPath="Name" IsSynchronizedWithCurrentItem="True" Name="lb1" />
<ListBox ItemsSource="{Binding Source={StaticResource mountains}, Path=Lifts}" DisplayMemberPath="Name" IsSynchronizedWithCurrentItem="True" Name="lb2" />
<ListBox ItemsSource="{Binding Source={StaticResource mountains}, Path=Lifts/Runs}" IsSynchronizedWithCurrentItem="True" Name="lb3" />

The third solution is to rely simply on the items displayed in the previous ListBox. Binding allows us to link not only to XML and objects, but also to other elements in the logical tree. To accomplish this scenario, we set the ElementName property of Binding to the Name of the source element (instead of setting Binding’s Source property), and the Path to the property of the element we’re interested in.

<ListBox ItemsSource="{Binding Source={StaticResource mountains}}" DisplayMemberPath="Name" Name="lb1" IsSynchronizedWithCurrentItem="True"/>
<ListBox DataContext="{Binding ElementName=lb1, Path=Items}" ItemsSource="{Binding Path=Lifts}" DisplayMemberPath="Name" Name="lb2" IsSynchronizedWithCurrentItem="True"/>
<ListBox DataContext="{Binding ElementName=lb2, Path=Items}" ItemsSource="{Binding Path=Runs}" Name="lb3" IsSynchronizedWithCurrentItem="True"/>

In the markup above, we set the DataContext of the second ListBox to the first ListBox’s Items property. Because DataContext is not expecting a collection, internally the binding engine returns the current item of that collection. We can then bind the ItemsSource to the Lifts property of the current Mountain, which returns the list we want.

This sample uses CLR objects as the data source. When using an XML data source, note that only the third solution above will work (for reasons I won’t go into here).

Here is a screen shot of the completed sample:

WPF Source Code

WPF

UWP/Uno/WinUI Notes

It’s highly recommended that you do NOT use the ISynchronizedWithCurrentItem as it’s likely to cause runtime errors. The Items collection doesn’t maintains a CurrentItem, instead use SelectedItem on the ListBox/ListView instead. It’s recommended to use the ListView control rather than the older ListBox control

UWP/Uno Source Code

UWP
WASM

WinUI with Uno and WinUI Desktop Source Code

WinUI – Desktop

XAML Back to Basics #10: List and Details

List-detail scenario

XAML Basics Series Index Page

The next post in the series originally written by Beatriz Stollnitz. Original post available on Github. Original post used terminology of Master-Detail, which has been changed to List-Detail to more accurately reflect what it represents.

List-detail scenario

In the simplest list-detail scenario, clicking a particular item of an ItemsControl causes the details about that item to be displayed in another control. For example, an application may display a list of customer names in a ListBox, and clicking a particular customer causes TextBlocks to be updated with the address, phone number and date of birth of that customer.

In this post I will use a data source with the planets of the solar system: clicking on the name of a planet in the ListBox causes its picture and information to be displayed in a templated ContentControl. The ListBox plays the role of the list and the ContentControl presents the detail.

In the resources section of the Window, I have an XmlDataProvider with the planet data and a CollectionViewSource with the Source property bound to the provider. Here is the markup for the ListBox bound to the CollectionViewSource:

<!-- list -->
<ListBox ItemsSource="{Binding Source={StaticResource cvs}}" DisplayMemberPath="@Name" Padding="5" Margin="0,0,5,0"/>

I also need a ContentControl, which is used to display the details of the selected item. The markup below may seem a little strange at first: we are binding a ContentControl (which displays a single item) to a collection of items? (Notice that its Content’s Binding is the same as the Binding in the ListBox’s ItemsSource.) This markup works fine because the data binding engine is smart enough to distinguish between the two targets. When binding an ItemsControl to a collection we get the collection; when binding a ContentControl to a collection we get the current item of that collection. This is what makes the list-detail scenario so simple in WPF.

<!-- detail -->
<ContentControl ContentTemplate="{StaticResource detailTemplate}" Content="{Binding Source={StaticResource cvs}}"/>

To specify how the details of the planet data should be displayed in the ContentControl, we use a DataTemplate. The following markup shows the data-binding specific parts of the DataTemplate. Notice that because I am binding to XML, the Binding is using XPath instead of Path.

<DataTemplate x:Key="detailTemplate">
    (...)
    <Image Source="{Binding XPath=Image, Converter={StaticResource stringToImageSource}}" />
    (...)
    <StackPanel Orientation="Horizontal" Margin="5,5,5,0">
        <TextBlock Text="Orbit: " FontWeight="Bold" />
        <TextBlock Text="{Binding XPath=Orbit}" />
    </StackPanel>
    <StackPanel Orientation="Horizontal" Margin="5,0,5,0">
        <TextBlock Text="Diameter: " FontWeight="Bold"/>
        <TextBlock Text="{Binding XPath=Diameter}" />
    </StackPanel>
    <StackPanel Orientation="Horizontal" Margin="5,0,5,5">
        <TextBlock Text="Mass: " FontWeight="Bold"/>
        <TextBlock Text="{Binding XPath=Mass}" />
    </StackPanel>
    (...)
</DataTemplate>

Here is a screen shot of the completed sample:

WPF Source Code

WPF

Uno Notes

Because the CollectionViewSource isn’t support across the different Uno platforms, I’ve data bound the SelectedItem on the ListView to a property on the MainPage, which in turn updates the Content property on the ContentControl. This only applies to the Non-UWP platforms.

You’ll also note that unlike in my previous post, where I used an XmlElementConverter, in this example I’ve used an XmlWrapper. This leads to binding expressions that are closer to what’s in the original post as it allows for traversing the element and attributes on the Xml that’s loaded from the associated data file.

UWP Source Code

UWP

WinUI Notes

Whilst WinUI for Desktop is very close to WPF, it doesn’t include the XmlDataProvider. Similar to the Uno project, we’ve used an embedded xml file instead of the inline data.

WinUI with Uno and WinUI Desktop Source Code

WinUI-Desktop

XAML Back to Basics #9: CollectionViewSource

How to sync selection of two data bound ListBoxes

XAML Basics Series Index Page

The next post in the series originally written by Beatriz Stollnitz. Original post available on Github.

How to sync selection of two data bound ListBoxes

I will show you two ways of syncing the selection of two data bound ListBoxes.

In the first solution, I will create a custom view over the collection and bind both ListBoxes to it. Views track the current item of their underlying collection, and allow us to sort, group and filter their items. CollectionViewSource is a new class that makes it possible to create a custom view in markup. Because the custom view created tracks the current item of the collection, and currency and selection are in sync in this scenario, binding both ListBoxes to the same view causes their selected items to be in sync.

<Window.Resources>
    <local:GreekGods x:Key="source" />
    <CollectionViewSource Source="{StaticResource source}" x:Key="cvs"/>
</Window.Resources>

<ListBox ItemsSource="{Binding Source={StaticResource cvs}}" DisplayMemberPath="Name"/>
<ListBox ItemsSource="{Binding Source={StaticResource cvs}}" DisplayMemberPath="Name"/>

I will write about how to use CollectionViewSource to sort, group and filter items in a future post.
An alternative way to achieve the same behavior is to set both ItemsSource properties to the data source and set the IsSynchronizedWithCurrentItem properties to true:

<ListBox ItemsSource="{StaticResource source}" IsSynchronizedWithCurrentItem="True" DisplayMemberPath="Name"/>
<ListBox ItemsSource="{StaticResource source}" IsSynchronizedWithCurrentItem="True" DisplayMemberPath="Name"/>

This markup works because when binding to a collection, a view is always created. If you don’t specify one, a default view is created for you internally. Although this view tracks current item the same way the custom one did, when you have a default view currency and selection do not sync by default. The way to override this behavior is by setting the IsSynchronizedWithCurrentItem property to true.

The data team made the default synchronization behavior be different for custom views and default views based on customer feedback. This way, users that are aware of the concept of view and are explicit about it get the synchronization they expect, and the rest of the users don’t.

In the image below, the first and second ListBoxes are bound to the CollectionViewSource and the third and fourth ones have InSynchronizedWithCurrentItem set to true.

WPF Source Code

WPF

Uwp/Uno/WinUI Notes

Whilst the InSynchronizedWithCurrentItem property still exists on the ListBox, attempting to set this causes either a runtime exception (UWP) or a XAML parsing error (WinUI).

CollectionViewSource is supported by UWP and WinUI for UWP but is currently not supported across other platforms via Uno. The application will build and run on those platforms. However, selection on the ListBox will not work and won’t be synchronised across the ListBoxes

UWP Source Code

UWP

WinUI with Uno and WinUI Desktop Source Code

WinUI – Desktop

XAML Back to Basics #8: Simple Bar Graph

How to make a data bound bar graph

XAML Basics Series Index Page

The next post in the series originally written by Beatriz Stollnitz. Original post available on Github.

How to make a data bound bar graph

A very simple bar graph can be created by combining the styling and templating features with a data bound ItemsControl. An ItemsControl is simply a control that displays a list of items. Those items can be anything you want: people, numbers, controls, and so on. If you template each item of an ItemsControl to be a rectangle whose height is bound to numerical data, you have a data bound bar graph.

The data source for this sample is a class with a property called ValueCollection of type ObservableCollection. ObservableCollection implements INotifyCollectionChanged, which means that if items are added/removed/replaced from that collection, the binding engine will be notified of that and the UI will be updated.

This is the markup for the ItemsControl:

<ItemsControl ItemsSource="{Binding Source={StaticResource source}, Path=ValueCollection}" ItemTemplate="{StaticResource template}" Height="130">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

The default Panel for ItemsControl has vertical orientation, but we want the items to be displayed horizontally – each bar should be to the right of the previous one. To change the panel, we set the ItemsControl’s ItemsPanel property (see my previous blog post for more details on changing the Panel of an ItemsControl).

The template for each item has a rectangle with height bound to the corresponding integer in the data source and a second rectangle with no fill to add some blank space between the bars:

<DataTemplate x:Key="template">
    <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom">
        <Rectangle Height="{Binding}" Width="20" Fill="Red" />
        <Rectangle Width="5" />
    </StackPanel>
</DataTemplate>

This is a very simple bar graph but it will hopefully give you ideas and serve as the base for more elaborate representations of data. This is the result:

WPF Source Code

WPF

UWP/Uno Source Code

UWP

WinUI with Uno and WinUI Desktop Source Code

WinUI – Desktop

XAML Basics for WPF, UWP, Uno and WinUI

This is an index post for a series of blog posts covering some XAML basics. The original content came from a series of posts that Beatriz Stollnitz made on WPF/Silverlight that had been moved to a github repository. Unfortunately most of the samples don’t work out of the box with the latest version of Visual Studio … Continue reading “XAML Basics for WPF, UWP, Uno and WinUI”

This is an index post for a series of blog posts covering some XAML basics. The original content came from a series of posts that Beatriz Stollnitz made on WPF/Silverlight that had been moved to a github repository. Unfortunately most of the samples don’t work out of the box with the latest version of Visual Studio but with some minor adjustments they’re easily fixed and updated to include cross platform support via Uno and WinUI

I took a fork of the repository where I’ve been updating the content: Updated Code Samples. The main changes are:

  • Updating from .NET FX 3.5 to .NET FX 4.7.2 for the WPF project
  • Added support for .NET Core 3.1 and .NET 5 using multi-targeting for the WPF project
  • Removing any Silverlight projects and content (apologies if you’re still stuck maintaining/working on a Silverlight project!)
  • Added new UWP + Uno solution that targets: iOS, Android, MacOS, UWP and WASM
  • Added new WinUI with Uno and Desktop solution that targets: iOS, Android, MacOS, UWP, WASM and Desktop

I’ll update this index with links to each post as they’re made available.

01-DataContext

02-EmptyBinding

03-GetListBoxItem

04-BindToComboBox

05-DisplayMemberPath

06-SelectedValue

07-ChangePanelItemsControl

08-BarGraph

09-CollectionViewSourceSample

10-MasterDetail

11-MasterDetailThreeLevels

12-DataBoundDialogBox

13-TemplatingItems

14-SortingGroups

15-GroupingTreeView

16-GroupByType

17-BoundListView

18-ThreeLevelMasterDetailADO

19-ObjectDataProviderSample

20-InsertingSeparators

21-CustomSorting

24-AsynchronousBinding

25-BindToEnum

26-DataTriggerSample

27-ConvertXaml

28-FilterSample

29-MultipleFilters

30-MultiBindingConverter

31-ChangesMultithreading

32-PolygonBinding

33-PolygonBinding2

34-PolygonBinding3

35-CommonQuestions

36-ADOIndependentView

37-PlanetsListBox

38-UpdateExplicit

39-TreeViewPerformancePart1

40-TreeViewPerformancePart2

41-TreeViewPerformancePart3

42-WPFPresenter

43-BindToXLinq

44-XLinqXMLMasterDetail

45-DebuggingDataBinding

46-DragDropListBox

47-ExpandTreeViewPart1

48-ExpandTreeViewPart2

49-ExpandTreeViewPart3

51-UIVirtualization

52-DataVirtualization

54-PieChartWithLabels

55-PieChartWithLabelsSilverlight

56-PieChartWithLabelsSilverlight

57-DataVirtualization

58-MultipleStyles

59-WPFCollectionViewSource

60-SLCollectionViewSource

61-OredevComputerWeekly

62-DataVirtualizationFiltering

64-DataVirtualizationFilteringSorting

66-SortingHierarchy

67-PieChartWithLabelsUpdates

69-BindRadioButtonsToEnumsPart1

70-BindRadioButtonsToEnumsPart2

71-BindRadioButtonsToEnumsPart3

72-BindRadioButtonsToEnumsPart4

73-BindRadioButtonsToEnumsPart5

74-PositioningDataBoundItems

75-SimultaneousEnableDisable

76-FocusWatcher

77-CaptureWatcher

78-BetterBindableBase

79-BooleanConverters

XAML Back to Basics #7: ItemsPanel

How to change the layout of an ItemsControl

XAML Basics Series Index Page

The next post in the series originally written by Beatriz Stollnitz. Original post available on Github.

How to change the layout of an ItemsControl

I will show in this sample two ways to change the layout of an ItemsControl. This sample uses XmlDataProvider, which allows binding to XML data.

The easiest way to change the layout of an ItemsControl is simply by setting the ItemsPanel property to the Panel that will contain the items:

<ListBox ItemsSource="{Binding Source={StaticResource xmlData}}" (...) >
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
</ListBox>

Alternatively, for more extensive customizations, you can create a ControlTemplate. This ControlTemplate allows you to replace the whole VisualTree, including picking a new Panel to hold the items. For example, the following markup shows a ControlTemplate that adds a Border and changes the Panel on the ItemsControl:

<ControlTemplate x:Key="listBoxTemplate">
    <Border BorderBrush="Orange" 
            BorderThickness="2" 
            Margin="10,0,10,10">
        <StackPanel Orientation="Horizontal"
            IsItemsHost="True" />
    </Border>
</ControlTemplate>

<ListBox 
    ItemsSource="{Binding Source={StaticResource xmlData}}" 
    Template="{StaticResource listBoxTemplate}" (...) />

Most people get this far in this scenario, but often forget to set the IsItemsHost property in the Panel. IsItemsHost is a property that says “Use this Panel to lay out the items in the ItemsControl.” Notice that selection still works as usual.

If you want your items to wrap onto multiples lines, you can use a WrapPanel in place of the StackPanel. In this scenario, bear in mind that the default template for ListBox contains a ScrollViewer, so your items won’t wrap. To make them wrap, you can either provide your own ControlTemplate or, if you don’t need selection to work, use an ItemsControl instead of a ListBox.

As I mentioned before, I am using XmlDataProvider to bind to XML data. This is how I converted the GreekGods CLR data source I’ve used in previous samples:

<Window.Resources>
    <XmlDataProvider XPath="/GreekGods/GreekGod" x:Key="xmlData">
        <x:XData>
            <GreekGods xmlns="">
                <GreekGod>
                    <Name>Aphrodite</Name>
                    <Description>Goddess of love, beauty and fertility</Description>
                    <RomanName>Venus</RomanName>
                </GreekGod>
                (...)
            </GreekGods>
        </x:XData>
    </XmlDataProvider>
</Window.Resources>

The only thing to keep in mind when binding to XML is that instead of using the Path property in the Binding object, you should use the XPath property. You can use either Path or XPath syntax for DisplayMemberPath.

WPF Source Code

WPF

UWP/Uno Notes

The XmlDataProvider doesn’t exist for UWP applications. Instead the GreekGods XML data has been added as an XML file with build action of Embedded Resource. The data is loaded on startup and set as the ItemsSource for each ListBox.

There is also no support for binding using an XPath expression. For this a simple XmlElementConverter has been added.

UWP/Uno Source Code

UWP
WebAssembly (WASM)

Update 31st August 2020

Uno sample has been updated to v3 of Uno and supports iOS, Android, Windows and MacOS.

WinUI with Uno and WinUI for Desktop samples added.

WinUI with Uno and WinUI Desktop Source Code

XAML Back to Basics #6: SelectedValue v SelectedItem

What is the difference between SelectedValue and SelectedItem?

XAML Basics Series Index Page

The next post in the series originally written by Beatriz Stollnitz. Original post available on Github.

What is the difference between SelectedValue and SelectedItem?

When they are used by themselves, these two properties are very similar. The need for both and the difference between the two becomes apparent when SelectedValuePath is also set.

For example, consider our well-known GreekGods data source. I set the DataContext of the StackPanel to be that collection through code:

GreekGods items;
items = new GreekGods();
mainStackPanel.DataContext = items;

And used an empty Binding to bind that collection to the ListBox. I know that I want to select the GreekGod with description “Messenger of the Gods” (even though I am only displaying the Name of each God). This is when SelectedValuePath becomes useful. Each item in the ListBox is a GreekGod object, so by setting SelectedValuePath to “Description” I am able to drill down into the Description property of each GreekGod. Then I just have to set SelectedValue to the description I am looking for and the item becomes selected.

<StackPanel Name="mainStackPanel">
    <ListBox ItemsSource="{Binding}" DisplayMemberPath="Name" SelectedValue="Messenger of the Gods" SelectedValuePath="Description" Name="listBox1" (...) />
</StackPanel>

The difference between SelectedValue and SelectedItem should be obvious now. SelectedValue returns the string it was set to (“Messenger of the Gods”), while SelectedItem returns the actual GreekGod object with that description.

string messengerOfGods = (string)(listBox1.SelectedValue);
GreekGod hermes = (GreekGod)(listBox1.SelectedItem);

SelectedValue is particularly useful when only part of your item is stored in the model you are data binding to. In this scenario, you would data bind the SelectedValue property to the partial information in your model but the ListBox can show a lot more information about that item.

If you have ideas of how to combine these two properties in one, we would love to hear it.

WPF Source Code

WPF

UWP/Uno Source Code

UWP

Update 31st August 2020

Uno sample has been updated to v3 of Uno and supports iOS, Android, Windows and MacOS.

WinUI with Uno and WinUI for Desktop samples added.

WinUI with Uno and WinUI Desktop Source Code

XAML Back to Basics #5: DisplayMemberPath

DisplayMemberPath

XAML Basics Series Index Page

The next post in the series originally written by Beatriz Stollnitz. Original post available on Github.

DisplayMemberPath

As I’ve shown in previous posts, binding an ItemsControl to an IEnumerable data source is really easy (remember that ListBox and ComboBox derive from ItemsControl). With DisplayMemberPath it’s even easier for the scenario where you want to display only one property of each data item as text. Before DisplayMemberPath, this scenario required the use of a DataTemplate that would specify the property we’re interested in, like in the following xaml:

<Window.Resources>
    <DataTemplate x:Key="itemTemplate">
        <TextBlock Text="{Binding Path=Name}" />
    </DataTemplate>
</Window.Resources>

<ItemsControl ItemsSource="{StaticResource greekGods}" ItemTemplate="{StaticResource itemTemplate}" />

The Data Binding team realized that this was a very common scenario and could be simplified, which was the motivation for introducing the DisplayMemberPath property in ItemsControl. The scenario above can now be done in a single line of xaml:

<ItemsControl ItemsSource="{StaticResource greekGods}" DisplayMemberPath="Name" />

It’s that easy 🙂

The image below shows both versions of the ItemsControl, the one on the left is using DataTemplate and the one on the right is using DisplayMemberPath.

WPF Source Code

WPF

UWP/Uno Source Code

t whose value you’re interested … Continue reading“XAML Back to Basics #2: Binding Markup”

The next post in the series originally written by Beatriz Stollnitz. Original post available on Github.

What does “{Binding}” mean?

Most Bindings you see in samples have the Source and Path properties set. The Source property specifies the object you’re binding to and the Path specifies a property in that object whose value you’re interested in. I’ve seen several people get confused when encountering an empty Binding for the first time – “{Binding}”. It seems at first sight that we’re not giving the Binding enough information to do anything useful. This is not true and I will explain why. If you read my previous post you should understand that it is not necessary to set a Source in a Binding, as long as there is a DataContext set somewhere up in the tree. As for the Path, it should be left out when you want to bind to a whole object, and not only to a single property of an object. One scenario is when the source is of type string and you simply want to bind to the string itself (and not to its Length property, for example).

<Window.Resources>
    <system:String x:Key="helloString">Hello</system:String>
</Window.Resources>

<Border DataContext="{StaticResource helloString}">
    <TextBlock TextContent="{Binding}"/>
</Border>

Another common scenario is when you want to bind some element to an object with several properties.

<Window.Resources>
    <local:GreekGod Name="Zeus" Description="Supreme God of the Olympians" RomanName="Jupiter" x:Key="zeus"/>
</Window.Resources>

<Border DataContext="{StaticResource zeus}">
    <ContentControl Content="{Binding}"/>
</Border>

In this case, ContentControl does not know how to display the GreekGod data. Therefore you will only see the results of a ToString(), which is typically not what you want. Instead, you can use a DataTemplate, which allows you to specify the appearance of your data.

<Window.Resources>
    <local:GreekGod Name="Zeus" Description="Supreme God of the Olympians" RomanName="Jupiter" x:Key="zeus"/>
    <DataTemplate x:Key="contentTemplate">
        <DockPanel>
            <TextBlock Foreground="RoyalBlue" TextContent="{Binding Path=Name}"/>
            <TextBlock TextContent=":" Margin="0,0,5,0" />
            <TextBlock Foreground="Silver" TextContent="{Binding Path=Description}" />
        </DockPanel>
    </DataTemplate>
</Window.Resources>

<Border DataContext={StaticResource zeus}">
    <ContentControl Content="{Binding}" ContentTemplate="{StaticResource contentTemplate}"/>
</Border>

Notice that none of the Binding statements inside the DataTemplate has a Source. That is because a DataContext is automatically set to the data object being templated.

WPF Source Code

WPF

UWP/Uno Source Code

UWP

Update 31st August 2020

Uno sample has been updated to v3 of Uno and supports iOS, Android, Windows and MacOS.

WinUI with Uno and WinUI for Desktop samples added.

WinUI with Uno and WinUI Desktop Source Code

WinUI-Desktop

XAML Back to Basics #4: ComboBox Binding

How to bind the items of a ComboBox (and get its ComboBoxItems

XAML Basics Series Index Page

The next post in the series originally written by Beatriz Stollnitz. Original post available on Github.

How to bind the items of a ComboBox (and get its ComboBoxItems)

Binding the items of a ComboBox is pretty much the same as binding the items of a ListBox:

<Window.Resources>
    <local:GreekGods x:Key="greekGods"/>

    <DataTemplate x:Key="itemTemplate">
        <TextBlock Text="{Binding Path=Name}" />
    </DataTemplate>
</Window.Resources>

<ComboBox ItemsSource="{StaticResource greekGods}" ItemTemplate="{StaticResource itemTemplate}" Width="200" Name="comboBox"/>

The reason for this similarity is that both ComboBox and ListBox derive from ItemsControl, and ItemsSource and ItemTemplate are properties on ItemsControl.

If you read my previous post about how to get a ListBoxItem from a data bound ListBox, you’re probably thinking that you don’t need to keep reading to know how to do the same thing for a ComboBox. There is a little trick that you should be aware of, though.

If you use similar code to the solution of my previous post, you will notice that the ComboBoxItems are null:

GreekGod greekGod = (GreekGod)(comboBox.Items[0]);
ComboBoxItem cbi1 = (ComboBoxItem)(comboBox.ItemContainerGenerator.ContainerFromIndex(0));
ComboBoxItem cbi2 = (ComboBoxItem)(comboBox.ItemContainerGenerator.ContainerFromItem(comboBox.Items.CurrentItem));

This is because the generation of items for the ComboBox only happens when you open it. So the trick is to open the ComboBox before calling ContainerFromIndex/ContainerFromItem:

GreekGod greekGod = (GreekGod)(comboBox.Items[0]);
comboBox.IsDropDownOpen = true;
ComboBoxItem cbi1 = (ComboBoxItem)(comboBox.ItemContainerGenerator.ContainerFromIndex(0));
ComboBoxItem cbi2 = (ComboBoxItem)(comboBox.ItemContainerGenerator.ContainerFromItem(comboBox.Items.CurrentItem));
comboBox.IsDropDownOpen = false;

WPF Source Code

WPF

UWP/Uno Source Code

UWP

Update 19th August 2020

Uno sample has been updated to v3 of Uno and supports iOS, Android, Windows and MacOS.

WinUI with Uno and WinUI for Desktop samples added.

WinUI with Uno and WinUI Desktop Source Code

WinUI-Desktop

XAML Back to Basics #3: ListBox/ListView Binding

How to get a ListBoxItem from a data bound ListBox

XAML Basics Series Index Page

The next post in the series originally written by Beatriz Stollnitz. Original post available on Github.

How to get a ListBoxItem from a data bound ListBox

Data binding a list box to an enumeration of items could not be easier in WPF:

<Window.Resources>
    <local:GreekGods x:Key="greekGods"/>
    <DataTemplate x:Key="itemTemplate">
        <TextBlock Text="{Binding Path=Name}" />
    </DataTemplate>
</Window.Resources>

<ListBox ItemsSource="{StaticResource greekGods}" ItemTemplate="{StaticResource itemTemplate}" Name="listBox"/>

The ItemsSource property of ListBox takes an IEnumerable, which is the list of items you want to display. In this case, the GreekGods data source is of type ObservableCollection, which implements IEnumerable. The ItemTemplate property specifies the DataTemplate that will be used to control how the data is displayed. In this case, we will have a TextBlock for each item that will display the GreekGod’s name.

Some of you might find surprising, however, that doing listBox.Items[i] in code returns the data we’re binding to, and not the TextBlock or the ListBoxItem. In my opinion, it is actually pretty cool that retrieving the data in a particular position of the list box is so easy, because most of the time this is exactly what you want.

GreekGod greekGod = (GreekGod)(listBox.Items[0]);

But what about when you want to have access to the actual ListBoxItem generated? This is a bit tricky to discover but can be just as easily done with the following code:

ListBoxItem lbi1 = (ListBoxItem)(listBox.ItemContainerGenerator.ContainerFromIndex(0));

There is also a listBox.ItemContainerGenerator.ContainerFromItem(object item) that returns the ListBoxItem given the corresponding data item. This method is frequently used, for example, to retrieve the ListBoxItem for the current item:

ListBoxItem lbi2 = (ListBoxItem)(listBox.ItemContainerGenerator.ContainerFromItem(listBox.Items.CurrentItem));

I will talk about selection and current item in detail in some other post, but for this sample it is sufficient to know that to keep the selection and current item in sync, I set IsSynchronizedWithCurrentItem=”true” in the ListBox.

WPF Source Code

WPF

UWP/Uno Notes

There are a couple of changes to the code for UWP/Uno:

  • Whilst the ListBox control still exists, it’s more common to use the ListView as it has a nice set of built in styles
  • The listBox.Items collection doesn’t have a CurrentItem property. Instead we can use listBox.SelectedItem
  • Attempting to set the IsSynchronizedWithCurrentItem property on the ListView (or even ListBox) throws an exception and is generally not required since the SelectedItem property is in sync with what is selected in the ListView.

UWP/Uno Source Code

UWP

XAML Note
The structure of the XAML has been left the same from the original post. However, you should really avoid embedding a ListView or ListBox within a StackPanel. This layout will limit the ability of the view to resize without the button being pushed off screen.

Update 15th August 2020

Uno sample has been updated to v3 of Uno and supports iOS, Android, Windows and MacOS.

WinUI with Uno and WinUI for Desktop samples added.

WinUI with Uno and WinUI Desktop Source Code

WinUI – Desktop

XAML Back to Basics #2: Binding Markup

What does “{Binding}” mean?

XAML Basics Series Index Page

The next post in the series originally written by Beatriz Stollnitz. Original post available on Github.

What does “{Binding}” mean?

Most Bindings you see in samples have the Source and Path properties set. The Source property specifies the object you’re binding to and the Path specifies a property in that object whose value you’re interested in. I’ve seen several people get confused when encountering an empty Binding for the first time – “{Binding}”. It seems at first sight that we’re not giving the Binding enough information to do anything useful. This is not true and I will explain why. If you read my previous post you should understand that it is not necessary to set a Source in a Binding, as long as there is a DataContext set somewhere up in the tree. As for the Path, it should be left out when you want to bind to a whole object, and not only to a single property of an object. One scenario is when the source is of type string and you simply want to bind to the string itself (and not to its Length property, for example).

<Window.Resources>
    <system:String x:Key="helloString">Hello</system:String>
</Window.Resources>

<Border DataContext="{StaticResource helloString}">
    <TextBlock TextContent="{Binding}"/>
</Border>

Another common scenario is when you want to bind some element to an object with several properties.

<Window.Resources>
    <local:GreekGod Name="Zeus" Description="Supreme God of the Olympians" RomanName="Jupiter" x:Key="zeus"/>
</Window.Resources>

<Border DataContext="{StaticResource zeus}">
    <ContentControl Content="{Binding}"/>
</Border>

In this case, ContentControl does not know how to display the GreekGod data. Therefore you will only see the results of a ToString(), which is typically not what you want. Instead, you can use a DataTemplate, which allows you to specify the appearance of your data.

<Window.Resources>
    <local:GreekGod Name="Zeus" Description="Supreme God of the Olympians" RomanName="Jupiter" x:Key="zeus"/>
    <DataTemplate x:Key="contentTemplate">
        <DockPanel>
            <TextBlock Foreground="RoyalBlue" TextContent="{Binding Path=Name}"/>
            <TextBlock TextContent=":" Margin="0,0,5,0" />
            <TextBlock Foreground="Silver" TextContent="{Binding Path=Description}" />
        </DockPanel>
    </DataTemplate>
</Window.Resources>

<Border DataContext={StaticResource zeus}">
    <ContentControl Content="{Binding}" ContentTemplate="{StaticResource contentTemplate}"/>
</Border>

Notice that none of the Binding statements inside the DataTemplate has a Source. That is because a DataContext is automatically set to the data object being templated.

WPF Source Code

WPF

UWP/Uno Source Code

UWP
Uno – Wasm

Update 15th August 2020

Uno sample has been updated to v3 of Uno and supports iOS, Android, Windows and MacOS.

WinUI with Uno and WinUI for Desktop samples added.

WinUI with Uno and WinUI Desktop Source Code

WinUI Desktop

XAML Back to Basics #1: Data Context

How should I decide whether to use DataContext or Source?

XAML Basics Series Index Page

Last year I posted about a series of posts that Beatriz Stollnitz made on WPF/Silverlight that had been moved to GitHub. Unfortunately most of the samples don’t work out of the box with the latest version of Visual Studio but with some minor adjustments they’re easily fixed.

I took a fork of the repository and have started to a) update the wpf projects to work with VS2019 b) remove the Silverlight content and c) add equivalent examples that work cross platform using UWP and the Uno Platform.

Updated Code Samples

Importantly, as I go through each of the posts I’m going to reprint the majority of the original post with edits to bring them up to date with both WPF and UWP/Uno. I want to make sure the Beatriz is recognised as the original author of this content and that I just want to make sure her contributions live on to benefit the next generation of XAML developers.

Original post available on Github

How should I decide whether to use DataContext or Source?

The DataContext is one of the most fundamental concepts in Data Binding.

The Binding object needs to get its data from somewhere, and there are a few ways to specify the source of the data. In this post I talk about setting the Source property directly in the Binding vs inheriting a DataContext from the nearest element when traversing up in the tree. The other two alternatives are setting the ElementName and RelativeSource properties in the Binding object, but I will leave that for a future post.

For example, let’s assume we have the following data sources (GreekGod being a class defined in the code behind):

<Window.Resources>
    <local:GreekGod Name="Zeus" Description="Supreme God of the Olympians" RomanName="Jupiter" x:Key="zeus"/>
    <local:GreekGod Name="Poseidon" Description="God of the sea, earthquakes and horses" RomanName="Neptune" x:Key="poseidon"/>
</Window.Resources>

<StackPanel DataContext="{StaticResource poseidon}">
    <TextBlock TextContent="{Binding Source={StaticResource zeus}, Path=Name}"/>
    <TextBlock TextContent="{Binding Path=Description}"/>
    <TextBlock TextContent="{Binding Path=RomanName}"/>
</StackPanel>

The first TextBlock inherits the DataContext from the parent StackPanel and has a Source set in the Binding object too. In this case, Source takes priority, causing the TextBlock to bind to the Name property of the resource with key “zeus” – this displays “Zeus”.

The second TextBlock does not have a Source set directly in the Binding object, so it inherits the DataContext from the StackPanel. As you might guess, this binds to the Description property of the resource with key “poseidon”, displaying “God of the sea, earthquakes and horses”.

The third TextBlock should be straightforward – it displays “Neptune”.

Most data bound applications I see from users tend to use DataContext much more heavily than Source. My recommendation is to use DataContext when you need to bind more than one property to a particular source. When binding only one property, it may be better to use the Source attribute . The reason for this is ease of debugging – I would rather see all the information about the Binding in one place than search for the nearest DataContext to understand what is going on. In a small sample like the one above there is no big advantage, but in complex applications this could save you some time.

WPF Source Code

WPF

UWP/Uno Notes

In UWP it’s not very common to reference the Windows of the application directly. Instead you can define static resources (in this case the instances of the GreekGod class) at the Application, Page or even Control level. For example, to make the static resource available throughout a given page, we would define them as Page Resources.

<Page.Resources>
    <local:GreekGod Name="Zeus" Description="Supreme God of the Olympians" RomanName="Jupiter" x:Key="zeus"/>
    <local:GreekGod Name="Poseidon" Description="God of the sea, earthquakes and horses" RomanName="Neptune" x:Key="poseidon"/>
</Page.Resources>

UWP/Uno Source Code

UWP

Update 15th August 2020

Uno sample has been updated to v3 of Uno and supports iOS, Android, Windows and MacOS.

WinUI with Uno and WinUI for Desktop samples added.

WinUI with Uno and WinUI Desktop Source Code

WinUI Desktop

Content from Former Microsoft WPF and Silverlight Team Member

Someone pointed me in the direction of a series of great blog posts that have recently been migrated to a github repository. The posts are quite old, dating back to a period between 2005 and 2013 when Beatriz Stollnitz worked for Microsoft as part of the WPF and Silverlight teams. Here are the links to … Continue reading “Content from Former Microsoft WPF and Silverlight Team Member”

Someone pointed me in the direction of a series of great blog posts that have recently been migrated to a github repository. The posts are quite old, dating back to a period between 2005 and 2013 when Beatriz Stollnitz worked for Microsoft as part of the WPF and Silverlight teams. Here are the links to each of the posts – happy reading!

Update 11th August: I’ve forked the repository and have started to work my way through the sample code to a) update it to WPF on .NET 4.7.2 and b) provide a similar example for UWP + Uno (iOS, Android, WASM). Feel free to check it out and help out!

01-DataContext

02-EmptyBinding

03-GetListBoxItem

04-BindToComboBox

05-DisplayMemberPath

06-SelectedValue

07-ChangePanelItemsControl

08-BarGraph

09-CollectionViewSourceSample

10-MasterDetail

11-MasterDetailThreeLevels

12-DataBoundDialogBox

13-TemplatingItems

14-SortingGroups

15-GroupingTreeView

16-GroupByType

17-BoundListView

18-ThreeLevelMasterDetailADO

19-ObjectDataProviderSample

20-InsertingSeparators

21-CustomSorting

24-AsynchronousBinding

25-BindToEnum

26-DataTriggerSample

27-ConvertXaml

28-FilterSample

29-MultipleFilters

30-MultiBindingConverter

31-ChangesMultithreading

32-PolygonBinding

33-PolygonBinding2

34-PolygonBinding3

35-CommonQuestions

36-ADOIndependentView

37-PlanetsListBox

38-UpdateExplicit

39-TreeViewPerformancePart1

40-TreeViewPerformancePart2

41-TreeViewPerformancePart3

42-WPFPresenter

43-BindToXLinq

44-XLinqXMLMasterDetail

45-DebuggingDataBinding

46-DragDropListBox

47-ExpandTreeViewPart1

48-ExpandTreeViewPart2

49-ExpandTreeViewPart3

51-UIVirtualization

52-DataVirtualization

54-PieChartWithLabels

55-PieChartWithLabelsSilverlight

56-PieChartWithLabelsSilverlight

57-DataVirtualization

58-MultipleStyles

59-WPFCollectionViewSource

60-SLCollectionViewSource

61-OredevComputerWeekly

62-DataVirtualizationFiltering

64-DataVirtualizationFilteringSorting

66-SortingHierarchy

67-PieChartWithLabelsUpdates

69-BindRadioButtonsToEnumsPart1

70-BindRadioButtonsToEnumsPart2

71-BindRadioButtonsToEnumsPart3

72-BindRadioButtonsToEnumsPart4

73-BindRadioButtonsToEnumsPart5

74-PositioningDataBoundItems

75-SimultaneousEnableDisable

76-FocusWatcher

77-CaptureWatcher

78-BetterBindableBase

79-BooleanConverters

MVX=0 WPF/Mac: A first MvvmCross Application (MVX+1 days of MvvmCross)

MVX=0 WPF/Mac: A first MvvmCross Application (MVX+1 days of MvvmCross)

Further to some feedback on the first couple of posts in the MVX+1 series (MVX=0, MVX=0F and MVX=1), I’ve gone back and added WPF and Mac support to the FirstDemo to show just how powerful MvvmCross is. I’ll cover very briefly here how to add these project types and then I’ll be updating the TipCalc post to include the basics for WPF and Mac setup in there too.

Let’s start with WPF:

  1. Add a WPF App (.NET Framework) called FirstDemo.Wpf
    image
  2. Add a reference to MvvmCross NuGet package
  3. Add reference to FirstDemo.Core project
  4. Add ProxyMvxApplication to App.xaml.cs
    public abstract class ProxyMvxApplication : MvxApplication<MvxWpfSetup<Core.App>, Core.App> { }
  5. Update App class in both App.xaml and App.xaml.cs to inherit from ProxyMvxApplication
  6. Remove all code in the App class (in App.xaml.cs) except for the constructor with call to InitializeComponent
    public App()
    {
         InitializeComponent();
    }
  7. Update MainWindow in both MainWindow.xaml and MainWindow.xaml.cs to inherit from MvxWindow
  8. Create Views folder
  9. Add new User Control (WPF) called FirstView.xaml
  10. Update FirstView in both FirstView.xaml and FirstView.xaml.cs to inherit from MvxWpfView
  11. Add XAML to FirstView.xaml
    <StackPanel Margin=”12,12,12,12″>
         <TextBox Text=”{Binding FirstName, Mode=TwoWay}”></TextBox>
         <TextBox Text=”{Binding LastName, Mode=TwoWay}”></TextBox>
         <TextBlock Text=”{Binding FullName}”></TextBlock>
    </StackPanel>

You should now be able to build and run the WPF application – notice how little code we have to add/change in order to get MvvmCross to work!

Next up is Mac which at the moment can only be done on a Mac (almost no surprises there – it’s the same as not being able to do UWP development on a Mac I guess):

  1. Add a Cocoa App called FirstDemo.Mac
    image
  2. Add a reference to MvvmCross NuGet package
  3. Add reference to FirstDemo.Core project
  4. At this point I would recommend unloading your project, editing the csproj file manually to removed the legacy nuget reference and add the following ItemGroup. Also remove the reference to package.config, remove the actual package.config file and delete both bin and obj folders. Reload the Mac project and force a rebuild.
    <ItemGroup>
       <PackageReference Include=”MvvmCross” Version=”6.0.0″ />
    </ItemGroup>
  5. Update AppDelegate to inherit from MvxApplicationDelegate
    [Register(“AppDelegate”)]
    public class AppDelegate: MvxApplicationDelegate<MvxMacSetup<App>, App>
    {
         public override void DidFinishLaunching(NSNotification notification)
         {
             MvxMacSetupSingleton.EnsureSingletonAvailable(this, MainWindow).EnsureInitialized();
             RunAppStart();
            // Due to a bug, do not call base DidFinishLaunching
             //base.DidFinishLaunching(notification);
         }
    }
    Note: There is a bug at the moment where if you don’t override DidFinishLaunching the application will crash on startup
  6. Open main.storyboard – this should open the storyboard in the XCode designer
  7. Select the existing view controller and set the Class and Storyboard ID to FirstView
    image
  8. Make sure the FirstView name change has been saved; return to VS for Mac and confirm that files FirstView.cs and FirstView.designer.cs have been created. If these have not been created, I would suggest doing a rebuild of your project to make sure the changes to the storyboard have been processed and the appropriate designer files created.
  9. From the Object Library drag two TextField and a Label across onto the design surface
    image
  10. Open Project navigator and make sure you have FirstView.h and FirstView.m. If you don’t I would suggest closing both XCode and VS for Mac, deleting the bin and obj folder from within the FirstDemo.Mac folder and reopening the solution in VS for Mac. Rebuild the Mac project and then launch XCode by double clicking on main.storyboard.
    image
  11. Hide both Project navigator (left pane) and Utilities (right pane) and show the Assistant Editor (the icon button that has linked circles in top right corner of XCode)
  12. From the navigator bar in the Assistant Editor, select Manual –> FirstView.Mac –> FirstView.h
    image
  13. Right-click on the first TextField
    image
  14. Click and drag the circle next to New Referencing Outlet across onto the FirstView.h immediately before the @End. When you release, you should be prompted to complete information about the new Outlet where you can specify the Name, textEditFirst, which will be the name of the backing variable you’ll be able to use to reference the TextField in code
    image
  15. Repeat the previous step for the second TextField, textEditSecond, and the Label, labelFull.
  16. Update FirstView.cs to add the MvxFromStoryboard attribute, change the base class to MvxViewController and add data binding using the CreateBindingSet extension
    [MvxFromStoryboard(“Main”)]
    public partial class FirstView : MvxViewController<FirstViewModel>
    {
         public FirstView(IntPtr handle) : base(handle)
         {
         }

  17.     public override void ViewDidLoad()
         {
             base.ViewDidLoad();
             var set = this.CreateBindingSet<FirstView, FirstViewModel>();
             set.Bind(textEditFirst).To(vm => vm.FirstName);
             set.Bind(textEditSecond).To(vm => vm.LastName);
             set.Bind(labelFull).To(vm => vm.FullName);
             set.Apply();
         }
    }

And there you have it – build and run your Mac FirstDemo application