Question

I have a Collection View Source (CVS) implemented much like you see in MSDN or many tutorials. In my case, a Car class, and a Cars Collection class which is shown in XAML via an Object Data Provider (ODP) The CVS is linked to this. It all works well.

I added a sort, then eventually got it to a stage where I could allow the user to select the property of the Car class to sort on.

Next I want to add a secondary sort. My problem is not adding the sort, but removing it. My problem is this. In my code, no secondary sort and happen (secondary control is disabled) unless a primary sort exists first. Lets say it does, now if I do a secondary sort, it works, but if I select another property to sort on, nothing happens. This is because a third sort is added, if I select another property, nothing happens (a fourth sort is added and so on).

I cant find the syntax anywhere that will let me remove the secondary sort applied last, before adding the next secondary sort.

Given there are only ever two items - Primary sort [0] and Secondary sort [1], I should be able to use code like:

lstCars.Items.SortDescriptions.RemoveAt(1);

but this doesnt work and even empties my combo boxes of selection items (not my actual question).

I am trying something like this:

lstCars.Items.SortDescriptions.Remove(new SortDescription(cbxSortSecondary.SelectedItem.ToString(), direction));

To remove an actual Item from the source that I know exists because it was put there when selected from the secondary combobox. But while this should be working, it for some reason is not.

Below is some of my code:

    private void cbxSortPrimary_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        //MessageBox.Show(((ComboBox)sender).Name);

        //Code to check if sorting is required or not, if so then do it.
        if(cbxSortPrimary.SelectedIndex == 0)//Sort Off
        {
            txtPrimary.Foreground = Brushes.Green;
            lstCars.Items.SortDescriptions.Clear();
            cbxSortSecondary.IsEnabled = false;
            chkSortSecAsc.IsEnabled = false;
        }
        else//Sort On
        {
            txtPrimary.Foreground = Brushes.Red;
            ApplyPrimarySort((bool)chkSortPriAsc.IsChecked);
            cbxSortSecondary.IsEnabled = true;
            chkSortSecAsc.IsEnabled = true;
        }
    }

    private void cbxSortSecondary_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        //If there is no primary sort just exit the method.
        if(cbxSortPrimary.SelectedIndex == 0) return;

        if(cbxSortSecondary.SelectedIndex == 0)//Sort Off
        {
            txtSecondary.Foreground = Brushes.Green;
            RemoveSecondarySort((bool)chkSortSecAsc.IsChecked);
        }
        else//Sort On
        {
            txtSecondary.Foreground = Brushes.Red;
            ApplySecondarySort((bool)chkSortSecAsc.IsChecked);
        }
    }

    private void chkSortPriAsc_Checked(object sender, RoutedEventArgs e)
    {
        //Check to see if list is null, if so then exit (nothing to sort).
        if(lstCars == null) return;

        if(cbxSortPrimary.SelectedIndex > 0)
        {
            if(chkSortPriAsc.IsChecked == true) //Sort Ascending
            {
                chkSortPriAsc.Foreground = Brushes.Green;
                chkSortPriAsc.Content = "Asc";
                ApplyPrimarySort((bool)chkSortPriAsc.IsChecked);
            }
            else //Sort Decending
            {
                chkSortPriAsc.Foreground = Brushes.Red;
                chkSortPriAsc.Content = "Dec";
                ApplyPrimarySort((bool)chkSortPriAsc.IsChecked);
            }
        }
    }


    private void chkSortSecAsc_Checked(object sender, RoutedEventArgs e)
    {
        //Check to see if list is null, if so then exit (nothing to sort).
        if(lstCars == null) return;

        //If there is no primary sort just quit.
        if(cbxSortPrimary.SelectedIndex == 0) return;

        if(cbxSortSecondary.SelectedIndex > 0)
        {
            if(chkSortSecAsc.IsChecked == true) //Sort Ascending
            {
                chkSortSecAsc.Foreground = Brushes.Green;
                chkSortSecAsc.Content = "Asc";
                ApplySecondarySort((bool)chkSortPriAsc.IsChecked);
            }
            else //Sort Decending
            {
                chkSortSecAsc.Foreground = Brushes.Red;
                chkSortSecAsc.Content = "Dec";
                ApplySecondarySort((bool)chkSortPriAsc.IsChecked);
            }
        }
    }

    private void ApplyPrimarySort(bool asc)
    {
        ListSortDirection direction = new ListSortDirection();
        //Next determine if the direction of the sort is Ascending or Decending.
        if(asc)
            direction = ListSortDirection.Ascending;
        else
            direction = ListSortDirection.Descending;

        //Finally get the property to be sorted on and apply the sort, else remove any existing sorts.
        lstCars.Items.SortDescriptions.Clear();
        lstCars.Items.SortDescriptions.Add(new SortDescription(cbxSortPrimary.SelectedItem.ToString(), direction));

        //Then refresh the view.
        CollectionViewSource.GetDefaultView(lstCars.ItemsSource).Refresh();
    }

    private void ApplySecondarySort(bool asc)
    {
        ListSortDirection direction = new ListSortDirection();
        //Next determine if the direction of the sort is Ascending or Decending.
        if(asc)
            direction = ListSortDirection.Ascending;
        else
            direction = ListSortDirection.Descending;

        lstCars.Items.SortDescriptions.Remove(new SortDescription(cbxSortSecondary.SelectedItem.ToString(), direction));
        lstCars.Items.SortDescriptions.Add(new SortDescription(cbxSortSecondary.SelectedItem.ToString(), direction));

        //Then refresh the view.
        CollectionViewSource.GetDefaultView(lstCars.ItemsSource).Refresh();
    }


    private void RemoveSecondarySort(bool asc)
    {
        ListSortDirection direction = new ListSortDirection();
        //Next determine if the direction of the sort is Ascending or Decending.
        if(asc)
            direction = ListSortDirection.Ascending;
        else
            direction = ListSortDirection.Descending;

        lstCars.Items.SortDescriptions.Remove(new SortDescription(cbxSortSecondary.SelectedItem.ToString(), direction));
    }

Esentially I am looking for the code I need to first remove the previous secondary sort, then add a new one so there is always only two sorts in the collection view source. If I were to then expand this to allow a third, fourth or whatever other level of sorting there would always only be that number of items in the list. However, because of the way I have it set up, a 3rd level cant exist unless a second level exists first. So there can be no mix up of sorts.

Any ideas on how to implement this would be appreicated.

Was it helpful?

Solution

The way you are removing the items is incorrect: the Remove method that you are using removes the specified object from the collection (specifically, the first instance of the specified object), but since you are passing a new object, it won't be in the collection and thus won't be removed.

Your best bet is to cycle through the collection and see which item meets your criteria for removal and remove that item.

For example:

        var sortDescriptions = lstCars.Items.SortDescriptions;

        for (int nI = sortDescriptions.Count; nI >= 0; nI--)
        {
            if (sortDescriptions[nI].PropertyName == cbxSortSecondary.SelectedItem.ToString())
            {
                sortDescriptions.RemoveAt(nI);
            }
        }

Update

The alternative to this line:

                sortDescriptions.RemoveAt(nI);

is to use this line, but they should be functionally equivalent:

                sortDescriptions.Remove(sortDescriptions[nI]);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top