Navigate back home
GalaSoft Laurent Bugnion
WPF: Getting, sorting and filtering information in pure XAML (well almost)

One question on the WPF forum caught my attention. It was a nice challenge, so I decided to give it a try. It turned out not bad, so I thought I would post it here for future reference.

The question is: How to display all the cultures in a ListBox, and filter to display only these starting with "en-". Good news is: you can do a lot of that in pure XAML. Bad news is: If you want to filter, you need code-behind.

Binding to CultureInfo.GetCultures

To display all the Cultures, you can create an ObjectDataProvider and initialize it using the static method CultureInfo.GetCultures. However, this method takes a parameter, so you must call it in the correct way:

<Window x:Class="WindowsApplication1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="WindowsApplication1" Height="300" Width="300" xmlns:global="clr-namespace:System.Globalization;assembly=mscorlib" > <Window.Resources> <ObjectDataProvider x:Key="CulturesProvider" ObjectType="{x:Type global:CultureInfo}" MethodName="GetCultures"> <ObjectDataProvider.MethodParameters> <global:CultureTypes>AllCultures</global:CultureTypes> </ObjectDataProvider.MethodParameters> </ObjectDataProvider> </Window.Resources> <Grid> <ListBox ItemsSource="{Binding Source={StaticResource CulturesProvider}}"/> </Grid> </Window>
Displaying all CultureInfos in a ListBox

In the code above, note the use of the System.Globalization namespace through the addition of the xmlns:global prefix. Also, note the use of ObjectDataProvider.MethodParameters to specify which overload of the static method GetCultures must be called, and to pass it the value AllCultures of the enumeration System.Globalization.CultureTypes.

Sorting and grouping

Sorting and grouping is also possible in pure XAML. To sort and group a collection (in our case, an array), you use a CollectionViewSource object. This object has two properties CollectionViewSource.SortDescriptions and CollectionViewSource.GroupDescriptions. For example, the following code displays all the Cultures, grouped according to their parent (for example, "en-UK" and "en-US" both have the parent "en".

<Window x:Class="WindowsApplication1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="WindowsApplication1" Height="300" Width="300" xmlns:global="clr-namespace:System.Globalization;assembly=mscorlib" xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase" xmlns:dat="clr-namespace:System.Windows.Data;assembly=PresentationFramework" > <Window.Resources> <ObjectDataProvider x:Key="CulturesProvider" ObjectType="{x:Type global:CultureInfo}" MethodName="GetCultures"> <ObjectDataProvider.MethodParameters> <global:CultureTypes>AllCultures</global:CultureTypes> </ObjectDataProvider.MethodParameters> </ObjectDataProvider> <CollectionViewSource x:Key="MyCVS" Source="{StaticResource CulturesProvider}"> <CollectionViewSource.SortDescriptions> <scm:SortDescription PropertyName="IetfLanguageTag" /> </CollectionViewSource.SortDescriptions> <CollectionViewSource.GroupDescriptions> <dat:PropertyGroupDescription PropertyName="Parent" /> </CollectionViewSource.GroupDescriptions> </CollectionViewSource> </Window.Resources> <Grid> <ListBox ItemsSource="{Binding Source={StaticResource MyCVS}}"> <ListBox.GroupStyle> <x:Static Member="GroupStyle.Default"/> </ListBox.GroupStyle> </ListBox> </Grid> </Window>
Sorting and grouping in XAML

Note the use of the structure System.ComponentModel.SortDescription and the class System.Windows.Data.PropertyGroupDescription. Because these objects are defined in other namespaces and assemblies, they must be mapped again using the "scm" and "dat" prefix (the names of the prefixes is free, it can be anything). Also, note the use of the GroupStyle property on the ListBox to specify how the items must be grouped.

Filtering

What we want to do now is filtering according to the CultureInfo.IetfLanguageTag and display only items of which that tag starts with "en-" (another way would be to check the CultureInfo.Parent property). Unfortunately, there is no way to filter a CollectionViewSource in pure XAML. So we'll need a little snippet of code-behind. Filtering is done by specifying an event handler for the Filter event. This event handler then uses the parameter "e" (of type FilterEventArgs) to accept of reject items.

<Window x:Class="WindowsApplication1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="WindowsApplication1" Height="300" Width="300" xmlns:global="clr-namespace:System.Globalization;assembly=mscorlib" > <Window.Resources> <ObjectDataProvider x:Key="CulturesProvider" ObjectType="{x:Type global:CultureInfo}" MethodName="GetCultures"> <ObjectDataProvider.MethodParameters> <global:CultureTypes>AllCultures</global:CultureTypes> </ObjectDataProvider.MethodParameters> </ObjectDataProvider> <CollectionViewSource x:Key="MyCVS" Source="{StaticResource CulturesProvider}" Filter="MyCVS_Filter" /> </Window.Resources> <Grid> <ListBox ItemsSource="{Binding Source={StaticResource MyCVS}}"/> </Grid> </Window>

with (code behind)

void MyCVS_Filter(object sender, FilterEventArgs e) { CultureInfo item = e.Item as CultureInfo; if (item.IetfLanguageTag.StartsWith("en-")) { e.Accepted = true; } else { e.Accepted = false; } }

I hope that this helps people understand using ObjectDataProviders in XAML and also CollectionViewSources. For further examples, I encourage you to refer to Beatriz Costa excellent (but unfortunately too rare) postings in her own blog.