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.
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.