Friday, November 27, 2009

Silverlight 3, the CollectionViewSource and sorting

In my previous post we were introduced to the CollectionViewSource. We have multiple ItemSources binding to the same collection using a CollectionViewSource – very powerful.  Now what if we want to sort the items displayed in one of our grid cells?  We will focus on row one and column one for the rest of this post.

I’ve added some more default data to the Control’s constructor to make things a little more interesting and also notice I have added a few buttons to the bottom of our control:

image

The Sort by Name button adds a sort description to the CollectionViewSource

theDataContext[0].Column1.View.SortDescriptions.Add(new SortDescription("SomeName",ListSortDirection.Ascending));

This code tells the CollectionViewSource to sort the items in it’s view by the SomeName property in ascending order.  Click the button and we see the following:

image

Click the Clear Sort Descriptions button.

The Sort By Value button tells the CollectionViewSource to sort the items in the view by the SomeValue Property in ascending order.

theDataContext[0].Column1.View.SortDescriptions.Add(new SortDescription("SomeValue", ListSortDirection.Ascending));

Click the button to see the following:

image

This time our list is sorted by the SomeValue property.

Where things get interesting is that you can add multiple sort descriptions.  Try clearing the filter, then adding the name and value filter (in that order) and we see the following:

image

The collection is first sorted by name, then by value.

Clear the filter and click the Value, then name button and we see this:

image

The collection is first sorted by SomeValue, then by SomeName.

The order is important!  If you want to add a sort description to the top of the sort order, simply use the Insert method as follows:

theDataContext[0].Column1.View.SortDescriptions.Insert(0,new SortDescription("SomeValue", ListSortDirection.Ascending));

Here is the modified XAML:



Code Snippet



  1. <UserControl xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data" x:Class="SilverlightApplication1.MainPage"
  2.    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  5.    mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
  6.     <UserControl.Resources>
  7.         <Style TargetType="Button">
  8.             <Setter Property="FontSize" Value="9"/>
  9.         </Style>
  10.     </UserControl.Resources>
  11.   <Grid x:Name="LayoutRoot">
  12.         <ScrollViewer VerticalScrollBarVisibility="Auto">
  13.             <StackPanel Orientation="Vertical">
  14.             <data:DataGrid x:Name="TheMainDataGrid"  AutoGenerateColumns="False" ItemsSource="{Binding}" HeadersVisibility="Column">
  15.                 <data:DataGrid.Columns>
  16.                     <data:DataGridTemplateColumn Header="Column 1">
  17.                         <data:DataGridTemplateColumn.CellTemplate>
  18.                             <DataTemplate>
  19.                                 <ListBox MinHeight="15" ItemsSource="{Binding Path=Column1.View}" >
  20.                                     <ListBox.ItemTemplate>
  21.                                         <DataTemplate>
  22.                                             <StackPanel Orientation="Horizontal">
  23.                                                 <TextBlock Margin="10" Text="{Binding Path=SomeName}" />
  24.                                                 <TextBlock Margin="10" Text="{Binding SomeValue}" />
  25.                                             </StackPanel>
  26.                                         </DataTemplate>
  27.                                     </ListBox.ItemTemplate>
  28.                                 </ListBox>
  29.                             </DataTemplate>
  30.                         </data:DataGridTemplateColumn.CellTemplate>
  31.                     </data:DataGridTemplateColumn>
  32.                     <data:DataGridTemplateColumn Header="Column 2">
  33.                         <data:DataGridTemplateColumn.CellTemplate>
  34.                             <DataTemplate>
  35.                                 <ListBox MinHeight="15" ItemsSource="{Binding Path=Column2.View}" >
  36.                                     <ListBox.ItemTemplate>
  37.                                         <DataTemplate>
  38.                                             <StackPanel Orientation="Horizontal">
  39.                                                 <TextBlock Margin="10" Text="{Binding SomeName}" />
  40.                                                 <TextBlock Margin="10" Text="{Binding SomeValue}" />
  41.                                             </StackPanel>
  42.                                         </DataTemplate>
  43.                                     </ListBox.ItemTemplate>
  44.                                 </ListBox>
  45.                             </DataTemplate>
  46.                         </data:DataGridTemplateColumn.CellTemplate>
  47.                     </data:DataGridTemplateColumn>
  48.                 </data:DataGrid.Columns>
  49.             </data:DataGrid>
  50.             <StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
  51.                 <TextBlock Margin="5" Text="Name:"/>
  52.                 <TextBox x:Name="tbNAme" Margin="5" Width="100"></TextBox>
  53.                 <TextBlock Margin="5" Width="100" Text="Value:"/>
  54.                 <TextBox x:Name="tbValue" Margin="5" Width="100"></TextBox>
  55.                 <Button x:Name="AddButton" Margin="5" Content="Add" Click="AddButton_Click"/>
  56.             </StackPanel>
  57.             <StackPanel HorizontalAlignment="Left">
  58.                 <Button x:Name="ChangeNameButton" Width="150" Content="Change Name" Click="ChangeNameButton_Click"/>
  59.                 <Button x:Name="ChangeValueButton" Width="150" Content="Change Value" Click="ChangeValueButton_Click"/>
  60.                 <Button x:Name="refresh" Width="150" Content="Refresh CVS" Click="refresh_Click" />
  61.                 <Button x:Name="AddNameSort" Width="150" Content="Sort by Name" Click="AddNameSort_Click"/>
  62.                 <Button x:Name="AddValueSort" Width="150" Content="Sort by Value" Click="AddValueSort_Click"/>
  63.                 <Button x:Name="ClearSort" Width="150" Content="Clear Sort Descriptions" Click="ClearSort_Click"/>
  64.             </StackPanel>
  65.         </StackPanel>
  66.             </ScrollViewer>
  67.   </Grid>
  68. </
  69. UserControl>




Here is the modified code behind:



Code Snippet



  1. using System.Collections.ObjectModel;
  2. using System.Windows.Controls;
  3. using System.Windows.Data;
  4. using System.ComponentModel;
  5. namespace SilverlightApplication1
  6. {
  7.     public partial class MainPage : UserControl
  8.     {
  9.         ObservableCollection<TestClass> theMainCollection ;
  10.         ObservableCollection<TheRowClass> theDataContext;
  11.         public MainPage()
  12.         {
  13.             InitializeComponent();
  14.             theMainCollection = new ObservableCollection<TestClass>()
  15.                 { new TestClass() {SomeName="A",SomeValue=11},
  16.                     new TestClass() {SomeName="A",SomeValue=12},
  17.                     new TestClass() {SomeName="A",SomeValue=10},
  18.                     new TestClass() {SomeName="AB",SomeValue=21},
  19.                     new TestClass() {SomeName="A",SomeValue=13},
  20.                     new TestClass() {SomeName="B",SomeValue=13},
  21.                     new TestClass() {SomeName="B",SomeValue=14},
  22.                     new TestClass() {SomeName="AB",SomeValue=11},
  23.                     new TestClass() {SomeName="BC",SomeValue=22},
  24.                     new TestClass() {SomeName="AB",SomeValue=23},
  25.                     new TestClass() {SomeName="BC",SomeValue=24}
  26.                 };
  27.           
  28.             theDataContext = new ObservableCollection<TheRowClass>();
  29.             theDataContext.Add(new TheRowClass(theMainCollection));
  30.             theDataContext.Add(new TheRowClass(theMainCollection));
  31.             TheMainDataGrid.DataContext = theDataContext;
  32.             AddFilter(theDataContext[0].Column1, 1, 1);
  33.             AddFilter(theDataContext[0].Column2, 1, 2);
  34.             AddFilter(theDataContext[1].Column1, 2, 1);
  35.             AddFilter(theDataContext[1].Column2, 2, 2);
  36.            
  37.         }
  38.         private void AddFilter(CollectionViewSource cvs, int row, int column)
  39.         {
  40.             cvs.Filter += delegate(object o, FilterEventArgs eArgs)
  41.             {
  42.                 //Simple filter saying if column = 1 look for an A in the SomeName property
  43.                 //Else look for a B.  If we are in Row 1 look for a 1 in the SomeValue property
  44.                 //Else look for a 2
  45.                 string columnFilter;
  46.                 if (row == 1)
  47.                     columnFilter = "A";
  48.                 else
  49.                     columnFilter = "B";
  50.                 if ((eArgs.Item as TestClass).SomeValue.ToString().Contains(column.ToString()) && (eArgs.Item as TestClass).SomeName.Contains(columnFilter))
  51.                     eArgs.Accepted = true;
  52.                 else
  53.                     eArgs.Accepted = false;
  54.             };
  55.         }
  56.         private void AddButton_Click(object sender, System.Windows.RoutedEventArgs e)
  57.         {
  58.             TestClass tc = new TestClass();
  59.             tc.SomeName = tbNAme.Text;
  60.             tc.SomeValue = int.Parse(tbValue.Text);
  61.             theMainCollection.Add(tc);
  62.         }
  63.         private void ChangeNameButton_Click(object sender, System.Windows.RoutedEventArgs e)
  64.         {
  65.             theMainCollection[theMainCollection.Count-1].SomeName = "B";
  66.         }
  67.         private void ChangeValueButton_Click(object sender, System.Windows.RoutedEventArgs e)
  68.         {
  69.             theMainCollection[theMainCollection.Count - 1].SomeValue = 25;
  70.         }
  71.         private void refresh_Click(object sender, System.Windows.RoutedEventArgs e)
  72.         {
  73.             theDataContext[0].Column1.View.Refresh();
  74.             theDataContext[1].Column1.View.Refresh();
  75.             theDataContext[0].Column2.View.Refresh();
  76.             theDataContext[1].Column2.View.Refresh();
  77.         }
  78.         private void AddNameSort_Click(object sender, System.Windows.RoutedEventArgs e)
  79.         {
  80.             theDataContext[0].Column1.View.SortDescriptions.Add(new SortDescription("SomeName",ListSortDirection.Ascending));
  81.         }
  82.         private void AddValueSort_Click(object sender, System.Windows.RoutedEventArgs e)
  83.         {
  84.             theDataContext[0].Column1.View.SortDescriptions.Add(new SortDescription("SomeValue", ListSortDirection.Ascending));
  85.         }
  86.         private void ClearSort_Click(object sender, System.Windows.RoutedEventArgs e)
  87.         {
  88.             theDataContext[0].Column1.View.SortDescriptions.Clear();
  89.         }
  90.     }
  91. }




See my previous post to get the supporting code.

No comments:

Post a Comment