Search code examples
c#wpfforeachfilteringcollectionviewsource

Filtering under multiple conditions is not working


I am writing a WPF application that loads dummy data to a datagrid. The data grid contains the following data model:

public class CharacterCollection
  {
    public string Name { get; set; }
    public int Level { get; set; }
    public string Race { get; set; }
    public string Class { get; set; }

    public List<CharacterCollection> GetCharacters()
    {
      List<CharacterCollection> characters = new List<CharacterCollection>();
      characters.Add(new CharacterCollection { Name = "Lothar", Class = "Fighter", Race = "Human", Level = 5 });
      characters.Add(new CharacterCollection { Name = "Turk", Class = "Barbarian", Race = "Half-Orc", Level = 3 });
      characters.Add(new CharacterCollection { Name = "Melian", Class = "Cleric", Race = "Elf", Level = 10 });
      //... there's about 16 more entries, but you get the idea ;)
      return characters;
    }

Next, I added 4 combo boxes; each filled with one of the properties in CharacterCollection

public partial class MainWindow : Window
{
    private CharacterCollection _characters = new CharacterCollection();
    List<CharacterCollection> collection = new List<CharacterCollection>();

    public MainWindow()
    {
      InitializeComponent();

      collection = _characters.GetCharacters();
      dgCharacterChart.ItemsSource = collection;

      var characterNames = collection.Select(c =>c.Name).Distinct().ToList();
      foreach(var item in characterNames)
      {
        CheckBox cb = new CheckBox();
        cb.Content = item.ToString();

        cbName.Items.Add(cb);
      }
      //...the other 3 combo boxes are filled the same way. I know its ugly and I will work on abstracting this a little better :)
   }
}

So far what I got are 4 combo boxes populated with checkboxes which the user can check however many they want. These are going to be used for filtering.

Lastly, I have a filter button...

private void btnFilter_Click(object sender, RoutedEventArgs e)
{
      ICollectionView _characterCollection = CollectionViewSource.GetDefaultView(collection);
      var predicates = new List<Predicate<CharacterCollection>>();

      foreach (CheckBox checkbox in cbName.Items)
      {
        if (checkbox.IsChecked == true)
        {
          predicates.Add(new Predicate<CharacterCollection>(x => x.Name == checkbox.Content.ToString()));
        }
      }

      foreach (CheckBox checkbox in cbClass.Items)
      {
        if (checkbox.IsChecked == true)
        {
          predicates.Add(new Predicate<CharacterCollection>(x => x.Class == checkbox.Content.ToString()));
        }
      }

      foreach (CheckBox checkbox in cbLevel.Items)
      {
        if (checkbox.IsChecked == true)
        {
          predicates.Add(new Predicate<CharacterCollection>(x => x.Level == Convert.ToInt32(checkbox.Content)));
        }
      }

      foreach (CheckBox checkbox in cbRace.Items)
      {
        if (checkbox.IsChecked == true)
        {
          predicates.Add(new Predicate<CharacterCollection>(x => x.Race == checkbox.Content.ToString()));
        }
      }
      _characterCollection.Filter = o =>
      predicates.All(predicate => predicate(o as CharacterCollection));
      dgCharacterChart.ItemsSource = _characterCollection;
 }

When I click the button with just one field chosen, say from the Name combo box, it filters just fine. However, if I choose more than one from Name or if I start checking multiple entries from the other combo boxes then my data grid shows blank. When I debug my code I can see that my predicate list contains all of my entries marked as checked but my collection count is 0. Can someone help me figure out why I am getting these results?

Many thanks in advance.


Solution

  • I did something similar but I did filtering via textbox. May be it will help you.

    .Xaml as follows

     <TextBox FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}"
                                         Background="{x:Null}"
                                         Text="{Binding Item , UpdateSourceTrigger=LostFocus}" Margin="6,0,0,0" BorderThickness="0" PreviewKeyDown="ItemField_PreviewKeyDown" TextChanged="ItemField_TextChanged" IsReadOnly="{Binding IsReadonly}" />
    

    .Xaml.cs as follows

    private ObservableCollection<ItemGrid> _itemGrid = new ObservableCollection<ItemGrid>();
        public ObservableCollection<ItemGrid> ItemGrid
        {
            get
            {
                return _itemGrid;
            }
            set
            {
                _itemGrid = value;
    
    
            }
        }
    
        private void ItemField_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (isBeginingEdit) return;
            //here we show the item selector and take care of autocomplete
            var textBox = sender as TextBox;
            if (textBox.Text != "")
            {
                var _itemSourceList = new CollectionViewSource() { Source = ItemGrid };
                ICollectionView Itemlist = _itemSourceList.View;
                ItemSearchText = textBox.Text;
                Itemlist.Filter = ItemFilter;
                var count = _itemSourceList.View.Cast<ItemGrid>().Count();
                if (count > 0)
                {
                    ItemsGrid.ItemsSource = Itemlist;
                } 
            } 
       }