0

I have an ObservableCollection called States

in the States Model I have id, name, code, country

I would like to keep this collection with all of them but I would like to make a new collection to filter only the country. Currently I have this working by using this:

ViewModel.cs

StateCollectionView = CollectionViewSource.GetDefaultView(States);
StateCollectionView.Filter += StatesFilter;

public static void GetStates()
{


    States.Clear();
    using var conn = new SqlConnection(Settings.Default.ConnectionString);

    conn.Open();
    string qry = "SELECT * FROM dbo.State";
    var cmd = new SqlCommand(qry, conn);

    var reader = cmd.ExecuteReader();
    while (reader.Read())
    {
        States.Add(new States(reader));

    }
            
        conn.Close();
    }

    public static bool StatesFilter(object state)
    {
        bool result = true;
        if (state is States states)
        {
            if (states.Country)
            {
                Debug.Print(states.Name);
                return true;
            }
            else
            {
                return false;
            }
        }


        return result;
}
    

This is working by filtering the ObservableCollection of States but I would not like to filter that collection but rather create a ICollectionViewSource and use that in the binding in the view. As I need the States ObservableCollection to not be filtered to display correct data in other views.

I am trying to bind it to a ComboBox on the country drop down I want it to only show counties and the states dropdown to only show states. They are set apart by a bool value in the database.

EDIT: Sample

StateCollectionView = CollectionViewSource.GetDefaultView(States);
            CountryCollectionView = CollectionViewSource.GetDefaultView(States);
            StateCollectionView.Filter += StatesFilter;
            CountryCollectionView.Filter += CountryFilter;

public static void GetStates()
        {


            States.Clear();
            using var conn = new SqlConnection(Settings.Default.ConnectionString);

            conn.Open();
            string qry = "SELECT * FROM dbo.State";
            var cmd = new SqlCommand(qry, conn);

            var reader = cmd.ExecuteReader();
            while (reader.Read())
            {
                States.Add(new States(reader));

            }
            
            conn.Close();
        }

        private static bool StatesFilter(object state) => state is States states && !states.Country;
        private static bool CountryFilter(object state) => state is States states && states.Country;

public static ObservableCollection<States> States { get; set; } = new ObservableCollection<States>();

        public static ICollectionView StateCollectionView { get; set; }
        public static ICollectionView CountryCollectionView { get; set; }
Knowledge
  • 134
  • 9

1 Answers1

1

You are not actually filtering the ObservableCollection<T> source collection but a view of it. But the thing is that WPF are always binding to this view instead of the actual source collection.

So instead of binding one control directly to the ObservableCollection<T> and another one to the filtered ICollectionView, you should create another (unfiltered) ICollectionView and bind to this one instead of the source collection. The other option would be to create two separate source collections and filter only one of them.

If you go with two ICollectionViews, you need to filter them separately using two different methods:

private static bool StatesFilter(object state) => state is States states && !states.Country;
private static bool CountryFilter(object state) => state is States states && states.Country;

Note that you need to create the views using the constructor instead of calling CollectionViewSource.GetDefaultView:

StateCollectionView = new ListCollectionView(States);
CountryCollectionView = new ListCollectionView(States);
mm8
  • 163,881
  • 10
  • 57
  • 88
  • Could you please help me understand this a bit more? I have an `ObservableCollection` as well as a `ICollectionView` already. I am missing what you are saying? Create 3 different collections? 2 filtered and 1 not filtered? – Knowledge Oct 19 '20 at 17:58
  • Two `ICollectionViews` - one filtered and one unfiltered - and an `ObservableCollection` or just two `ObservableCollections` - one filtered and one unfiltered. – mm8 Oct 20 '20 at 12:37
  • yes that is what I am trying to do. 2 `ICollectionViews` with one `ObservableCollection` I am just having trouble creating the `ICollectionView` to filter by `Country` or `State` – Knowledge Oct 20 '20 at 13:41
  • You realize that you need two separate filter methods? – mm8 Oct 20 '20 at 13:46
  • yes, if you can help me with one I would be able to grasp how it's done and create the other. Plus I need it for another collection as well. Just trying to learn how I would do it. – Knowledge Oct 20 '20 at 14:13
  • So how is a `States` defined? – mm8 Oct 20 '20 at 14:14
  • I provided an example in my answer. Does it help? – mm8 Oct 20 '20 at 14:18
  • yes that is perfect, so then to add into xaml it would be using like I did in the code I provided? – Knowledge Oct 20 '20 at 14:26
  • Add what into XAML? You should bind to the filtered collection view in XAML. – mm8 Oct 20 '20 at 14:27
  • yes when I do that it it still only has countries filtered and shows only countries regardless if I use statescollectionview or countrycollectionview – Knowledge Oct 20 '20 at 14:32
  • Then you have done something wrong. Please provide a minimal reproducible sample of your issue. – mm8 Oct 20 '20 at 14:33
  • yes i've provided all the code relating to the filtering. – Knowledge Oct 20 '20 at 14:42
  • @Knowledge: `CollectionViewSource.GetDefaultView` does not return a new view. You need to create a view using `new ListCollectionView(States)` for both the states and the countries. – mm8 Oct 20 '20 at 14:45