matthew_b matthew_b - 1 month ago 12
C# Question

ICollectionView Sort doesn't work after changing source

I have a method that queries a database using entity framework and places the results in an

ICollectionView
. The
ICollectionView
acts as the
ItemsSource
for a
DataGrid
. Everything works fine on the first query, but upon querying a second time, the data is not properly sorted, despite the application of the correct
SortDescriptions
.

Here is my code for trying querying and grouping/sorting the data:

CollectionViewSource cvsRS;

private ObservableCollection<productorder> rs;
public ObservableCollection<productorder> RS
{
get { return rs; }
set
{
if (rs != value)
{
rs = value;
OnPropertyChanged("RS");
}
}
}

private ICollectionView rsView;
public ICollectionView RSView
{
get { return rsView; }
set
{
if (rsView != value)
{
rsView = value;
OnPropertyChanged("RSView");
}
}
}

public void QueryDatabase()
{

RS = new ObservableCollection<productorder>(DatabaseEntities.productorders.Where(o => o.month.id == CurrentMonth.id));
if (RS != null)
{
cvsRS.Source = RS;
RSView = cvsRS.View;

RSView.GroupDescriptions.Clear();
RSView.GroupDescriptions.Add(new PropertyGroupDescription("producttype.productcategory.name"));
RSView.GroupDescriptions.Add(new PropertyGroupDescription("producttype.name"));

RSView.SortDescriptions.Clear();
RSView.SortDescriptions.Add(new SortDescription("producttype.productcategory.sortorder", ListSortDirection.Ascending));
RSView.SortDescriptions.Add(new SortDescription("client.name", ListSortDirection.Ascending));
RSView.Refresh();
CurrentRecord = null;
SelectedRecords = null;
}
}


The grouping works fine, but the groups aren't in the correct order based on the sorting. I've tried a number of possible "fixes" with no success (e.g. adding sort/group descriptions directly to the
CollectionViewSource
, sorting before grouping, removing some of the sorting/grouping, removing the
SortDescriptions
per CollectionViewSource does not re-sort on property change).

Does anyone know how to maintain the sort order regardless of how many queries are performed? I'm open to alternative methods of querying displaying the data in the
DataGrid
if that may work.

Answer

Try binding your CollectionViewSource.Source property to your ObservableCollection<T> property. Set up the binding in the viewmodel constructor. Then, just leave it alone. Update the ObservableCollection<T>, replace it, etc. As long as it's an ObservableCollection<T> and its public property raises PropertyChanged whenever you replace it, the whole thing will work.

public MyViewModel()
{
    BindCollectionViewSource();
}

protected void BindCollectionViewSource()
{
    cvsRS = new CollectionViewSource();

    var binding = new Binding
    {
        Source = this,
        Path = new PropertyPath("RS")
    };
    BindingOperations.SetBinding(cvsRS, CollectionViewSource.SourceProperty, binding);
}

//  Since we're not going to be messing with cvsRS or cvsRS.View after the 
//  constructor finishes, RSView can just be a plain getter. The value it returns 
//  will never change. 
public ICollectionView RSView
{
    get { return cvsRS.View; }
}

You can't just assign a binding to Source; there's more to it than that. The Source="{Binding RSView}" stuff you see in XAML may look like an assignment, but some details are being hidden for convenience. The Binding actively does stuff. It needs to know who the target object is.

I did see one funny thing: I gave my test code one PropertyGroupDescription and one SortDescription. When I added items to the collection, it sorted them within the groups. Then when I called RSView.Refresh(), it resorted them without reference to the groups. Not sure I understood what it was doing there.

Comments