Search code examples
c#wpfsortingxmldataprovider

WPF: Sorting an XMLdataprovider at runtime


Good day!

I've working quite some time to create my own HTPC app that basicly allows me to simply browse and play my movie collection. I wrote another little app the indexes everything and prepares an XML file with the layout you see below.

It's all working fine but now I'd like to implement a few sorting options. By pressing the "S" key I'd like to iterate through some fixed sorting methods, like "By Title", "By Release Date", "By Genre", ...

My XAML is a mashup of things I found online, I'm not expert unfortunately and it shows in the messy code. It basically shows the fanart as the background and has a scrolling strip horizontally at the bottom of the screen where you can select your movie (it also keeps the selected movie in the middle of the screen).

How would I solve this issue?

<MOVIES>
  <MOVIE>
    <TITLE></TITLE>
    <PATH></PATH>
    <FANART></FANART>
    <COVER></COVER>
    <RELEASEDATE></RELEASEDATE>
    etc...
  </MOVIE>
</MOVIES>


<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" WindowStartupLocation="CenterScreen" ResizeMode="NoResize" WindowState="Maximized" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Height="350" Width="525" ShowInTaskbar="True" WindowStyle="None" Loaded="Window_Loaded">
<Window.Resources>
    <XmlDataProvider x:Key="MovieData"
               Source="movies.xml" />

    <DataTemplate x:Key="ItemTemplate">
        <Image Source="{Binding XPath=COVER}" Width="166" Height="250" Margin="0,0" MaxWidth="166" MaxHeight="250" MinWidth="166" MinHeight="250" Stretch="Fill" />
    </DataTemplate>

    <DataTemplate x:Key="SelectedItemTemplate">
        <Border BorderBrush="WhiteSmoke" BorderThickness="3">
            <Image Source="{Binding XPath=COVER}" Width="250" Height="375" Margin="0,0" MaxWidth="250" MaxHeight="375" MinWidth="250" MinHeight="375" Stretch="Fill" />
        </Border>
    </DataTemplate>

    <Style TargetType="{x:Type ListBoxItem}" x:Key="ContainerStyle">
        <Style.Resources>
            <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent" />
            <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent" />
        </Style.Resources>
        <Setter Property="FocusVisualStyle">
            <Setter.Value>
                <Style />
            </Setter.Value>
        </Setter>
        <Setter Property="ContentTemplate" Value="{StaticResource ItemTemplate}" />
        <Style.Triggers>
            <Trigger Property="IsSelected" Value="True">
                <Setter Property="ContentTemplate" Value="{StaticResource SelectedItemTemplate}" />
            </Trigger>
        </Style.Triggers>
    </Style>

</Window.Resources>
<Grid DataContext="{Binding Source={StaticResource MovieData}, XPath=/MOVIES/MOVIE}">
    <Grid.RowDefinitions>
        <RowDefinition Height="178*" />
        <RowDefinition Height="133*" />
    </Grid.RowDefinitions>
    <Grid.Background>
        <ImageBrush ImageSource="{Binding XPath=FANART}"/>
    </Grid.Background>
    <ListBox x:Name="Listbox1" 
             SelectionChanged="ScrollIntoView"
             ItemContainerStyle="{StaticResource ContainerStyle}"
             IsSynchronizedWithCurrentItem="True" 
             ItemsSource="{Binding}"
             HorizontalAlignment="Center" Grid.Row="1" VerticalAlignment="Bottom" KeyDown="Listbox1_KeyDown">
        <ListBox.Style>
            <Style TargetType="ListBox">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ListBox}">
                            <Border>
                                <ScrollViewer x:Name="ScrollView1" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" VerticalContentAlignment="Bottom" CanContentScroll="True">
                                    <VirtualizingStackPanel x:Name="SPanel1" IsItemsHost="True" Orientation="Horizontal" VerticalAlignment="Bottom"  HorizontalAlignment="Center"/>
                                </ScrollViewer>
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </ListBox.Style>
    </ListBox>
</Grid>


Solution

  • In the KeyDown event handler for listbox, you need a call like this:

    Listbox1.Items.SortDescriptions.Clear();
    Listbox1.Items.SortDescriptions.Add(new SortDescription("TITLE", ListSortDirection.Descending));
    

    This adds a sort description to the default collection view created when you bind to ItemsSource. You could filter this way too.

    The property text in the sort description can be an XPath selector.