Search code examples
.netwpfxamlsortingcollectionviewsource

Change list view sort Property / Direction within XAML only


I have a simple ListView and want to sort the contents numerically or alphabetically, ascending or descending. The choice comes from a drop down box. I understand I can use CollectionViewSource to achieve the sorting but how can I alter the SortDescription or direction on the fly?

Update:

Ok so I have setup my CVS like so, the viewModel is what the ListView is currently bound to. I require the PropertyName to be bound to the currently selected combo box item's property PropertyName. The combo box is bound to a custom list that expose the propertyname on which I want to sort.

It complains about the PropertyName that im attempting to use:

A 'Binding' cannot be set on the 'PropertyName' property of type 'SortDescription'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject.

    <CollectionViewSource Source="{StaticResource viewModel.ListValues}" x:Key="cvs">
        <CollectionViewSource.SortDescriptions>
            <scm:SortDescription PropertyName="{Binding Path=SortPropertyName, Source=comboSort}"/>
        </CollectionViewSource.SortDescriptions>
    </CollectionViewSource>

    <ListView ItemsSource="{Binding Source={StaticResource cvs}}"  />

Solution

  • you can this all at code behind in your viewmodel

    // in your view model
    private void ChangeSorting () {
      var collView = CollectionViewSource.GetDefaultView(ListValues);
      collView.SortDescriptions.Clear();
      // do this one
      collView.SortDescriptions.Add(new SortDescription("YourPropertyName", ListSortDirection.Ascending));
      // or this one
      collView.SortDescriptions.Add(new SortDescription("YourOtherPropertyName", ListSortDirection.Descending));
      collView.Refresh();
    }
    
    public ICollectionView ListValuesCollectionViewSource
    {
      get {
        return collView;
      }
    }
    
    <ListView ItemsSource="{Binding viewModel.ListValuesCollectionViewSource}"  />
    

    EDIT

    here is a little example for your view model

    <ComboBox ItemsSource="{Binding viewmodel.YourDataForComboboxCollection, Mode=OneWay}"
              SelectedItem="{Binding viewmodel.SelectedCombobox}" />
    

    a little viewmodel

    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Windows;
    using System.Windows.Data;
    
    namespace YourNameSpace
    {
      public class ViewModel : INotifyPropertyChanged
      {
        public static readonly DependencyProperty SelectedComboboxProperty =
          DependencyProperty.Register("SelectedCombobox", typeof(YourDataForCombobox), typeof(ViewModel), new PropertyMetadata(default(YourDataForCombobox), new PropertyChangedCallback(SelectedComboboxCallback)));
    
        private static void SelectedComboboxCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) {
          var vm = sender as ViewModel;
          if (vm != null && e.NewValue != null && e.NewValue != e.OldValue) {
            vm.ChangeSorting(e.NewValue);
          }
        }
    
        public ViewModel() {
          this.YourDataForComboboxCollection = new ObservableCollection<YourDataForCombobox>();
        }
    
        private void ChangeSorting(YourDataForCombobox newValue) {
          this.yourCollectionView.SortDescriptions.Clear();
          this.yourCollectionView.SortDescriptions.Add(new SortDescription(newValue.PropertyName, newValue.Sorting));
          this.yourCollectionView.Refresh();
        }
    
        private IObservableCollection yourDataForComboboxCollection;
    
        public IObservableCollection YourDataForComboboxCollection {
          get { return this.yourDataForComboboxCollection; }
          set {
            this.yourDataForComboboxCollection = value;
            this.RaisePropertyChanged("YourDataForComboboxCollection");
          }
        }
    
        public YourDataForCombobox SelectedCombobox {
          get { return (YourDataForCombobox)GetValue(SelectedComboboxProperty); }
          set { SetValue(SelectedComboboxProperty, value); }
        }
    
        private IObservableCollection yourCollection;
        private ICollectionView yourCollectionView;
    
        public ICollectionView YourCollectionView {
          get { return this.GetCollectionView(); }
        }
    
        private ICollectionView GetCollectionView() {
          if (this.yourCollection == null) {
            this.yourCollection = new ObservableCollection<YourDataForCollection>();
            this.yourCollectionView = CollectionViewSource.GetDefaultView(this.yourCollection);
            // initial sorting
            this.ChangeSorting(null);
          }
          return this.yourCollectionView;
        }
    
        private void RaisePropertyChanged(string property) {
          var eh = this.PropertyChanged;
          if (eh != null) {
            eh(this, new PropertyChangedEventArgs(property));
          }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
      }
    }
    

    hope this helps