Filter WPF TreeView using ICollectionView in MVVM Pattern

Background:

A customer achieved a WPF TreeView with HierarchicalDataTemplate, there have a group of CheckBoxs (Green, Yellow & Red) and being checked:
treeview1

We can see that each item has a Circle with different color(Green, Yellow & Red). Now, he needs to accomplish filtering the TreeViewItem by color when check/uncheck CheckBox controls.

Reference:

In the above article, author used the ICollectionView interface to filter multiple level. This interface gives us the flexibility to Filter a collection even without touching the contents of the data source.

Implementation:

This project has two Models->

Class Model:

public class Class
{
         private string name;

        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        private string imagePath;

        public string ImagePath
        {
            get { return imagePath; }
            set { imagePath = value; }
        }

        private ObservableCollection<Student> students;

        public ObservableCollection<Student> Students
        {
            get
            {
                if (students == null)
                {
                    students = new ObservableCollection<Student>();
                }

                return students;
            }
            set { students = value; }
        }

        public Class()
        { 

        }

        public Class(string name)
        {
            this.name = name;
        }

        public Class(string name, string imagePath)
        {
            this.name = name;
            this.imagePath = imagePath;
        }
}

Student Model:

public class Student
{
         private string name;

        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        private string imagePath;

        public string ImagePath
        {
            get { return imagePath; }
            set { imagePath = value; }
        }

        private string toolTip;

        public string ToolTip
        {
            get { return toolTip; }
            set { toolTip = value; }
        }

        public Student()
        {

        }

        public Student(string name, string imagePath)
        {
            this.name = name;
            this.toolTip = name;
            this.imagePath = imagePath;
        }
}

To trigger the filtering function, we need to have three properties in ViewModel: IsDisplayGreen, IsDisplayRed and IsDisplayYellow. These three Properties are bound to the IsChecked property of the CheckBox.

<CheckBox Content="Green" Margin="2" IsChecked="{Binding Path=IsDisplayGreen, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
            <CheckBox Content="Yellow" Margin="2" IsChecked="{Binding Path=IsDisplayYellow, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
            <CheckBox Content="Red" Margin="2" IsChecked="{Binding Path=IsDisplayRed, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

The filtering implementation:

private void FilterFunction()
{
            ICollectionView classesDataSourceView =
                    CollectionViewSource.GetDefaultView(ClassList);
                classesDataSourceView.Filter = (classModel =>
                {
                    ICollectionView studentsDataSourceView =
                        CollectionViewSource.GetDefaultView(
                            ((Class)classModel).Students);

                    if (_isDisplayGreen == false && _isDisplayYellow == false && _isDisplayRed==false)
                        studentsDataSourceView.Filter =
                        (studentModel =>false);
                    if (_isDisplayGreen == true && _isDisplayYellow == true && _isDisplayRed == true)
                        studentsDataSourceView.Filter =
                        (studentModel => true);

                    if (_isDisplayGreen == false && _isDisplayYellow == true && _isDisplayRed == false)
                        studentsDataSourceView.Filter =
                        (studentModel =>
                            ((Student)studentModel).ImagePath.
                                               Equals("../Images/Yellow-icon.png"));
                    if (_isDisplayGreen == true && _isDisplayYellow == false && _isDisplayRed == false)
                        studentsDataSourceView.Filter =
                        (studentModel =>
                            ((Student)studentModel).ImagePath.
                                               Equals("../Images/Green-icon.png"));
                    if (_isDisplayGreen == false && _isDisplayYellow == false && _isDisplayRed == true)
                        studentsDataSourceView.Filter =
                        (studentModel =>
                            ((Student)studentModel).ImagePath.
                                               Equals("../Images/Red-icon.png"));
                    if (_isDisplayGreen == true && _isDisplayYellow == false && _isDisplayRed == true)
                        studentsDataSourceView.Filter =
                        (studentModel =>
                            ((Student)studentModel).ImagePath.
                                               Equals("../Images/Red-icon.png") 
                                               || ((Student)studentModel).ImagePath.
                                               Equals("../Images/Green-icon.png"));
                    if (_isDisplayGreen == false && _isDisplayYellow == true && _isDisplayRed == true)
                        studentsDataSourceView.Filter =
                        (studentModel =>
                            ((Student)studentModel).ImagePath.
                                               Equals("../Images/Red-icon.png")
                                               || ((Student)studentModel).ImagePath.
                                               Equals("../Images/Yellow-icon.png"));
                    if (_isDisplayGreen == true && _isDisplayYellow == true && _isDisplayRed == false)
                        studentsDataSourceView.Filter =
                        (studentModel =>
                            ((Student)studentModel).ImagePath.
                                               Equals("../Images/Yellow-icon.png")
                                               || ((Student)studentModel).ImagePath.
                                               Equals("../Images/Green-icon.png"));

                    return !studentsDataSourceView.IsEmpty;
                });
}

Properties:

private bool _isDisplayGreen = true;
private bool _isDisplayRed = true;
private bool _isDisplayYellow = true;

public bool IsDisplayGreen
{
            get { return _isDisplayGreen; }
            set
            {
                _isDisplayGreen = value;
                FilterFunction();
                OnPropertyChanged("IsDisplayRed");
                OnPropertyChanged("IsDisplayGreen");
                OnPropertyChanged("IsDisplayYellow");
            }
}

public bool IsDisplayRed
{
            get { return _isDisplayRed; }
            set
            {
                _isDisplayRed = value;
                FilterFunction();
                OnPropertyChanged("IsDisplayRed");
                OnPropertyChanged("IsDisplayGreen");
                OnPropertyChanged("IsDisplayYellow");
            }
}

public bool IsDisplayYellow
{
            get { return _isDisplayYellow; }
            set
            {
                _isDisplayYellow = value;
                FilterFunction();
                OnPropertyChanged("IsDisplayRed");
                OnPropertyChanged("IsDisplayGreen");
                OnPropertyChanged("IsDisplayYellow");
            }
}

Of course, the ViewModel need to be inherited from PropertyChangedBase class:

public class PropertyChangedBase : INotifyPropertyChanged
{
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                var e = new PropertyChangedEventArgs(propertyName);
                handler(this, e);
            }
        }
}

Screenshot:
WpfTVHierarchicalDataTemplateFilter

Download Sample: WpfTVHierarchicalDataTemplateFilter

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>