Search code examples
c#wpfdatagrid

How can add filter function to a DataTamplateGridColumn in WPF C#?


I created an EmployeeDataGrid like in this Code Below. Employee is the parent table and has 3 child tables, Contacts, Languages and Duties. I created a custom Data-grid like below and what wanted is to display all child tables inside the parent table as in the picture below. Everything worked as Expected but when it came to filtering it didn't work for Template Columns like Contacts, How can i archive that?

XAML:

    <Window.Resources>
        <CollectionViewSource x:Key="CvsKey">
            <CollectionViewSource.GroupDescriptions>
                <PropertyGroupDescription PropertyName="Employee"/>
            </CollectionViewSource.GroupDescriptions>
        </CollectionViewSource>
        
    </Window.Resources>

    <Grid>
        <DataGrid AutoGenerateColumns="False" x:Name="dataGrid1" ItemsSource="{Binding Employees}" IsReadOnly="True" RowDetailsVisibilityMode="Collapsed"
                          
                  CanUserAddRows="True">

            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding EmployeeID}" Header="EmployeeID"/>
                <DataGridTextColumn Binding="{Binding FirstName}" Header="FirstName"/>
                <DataGridTextColumn Binding="{Binding LastName}" Header="LastName"/>
                <DataGridTextColumn Binding="{Binding Age}" Header="Age"/>
                <DataGridTextColumn Binding="{Binding Gender}" Header="Gender"/>
                <DataGridTextColumn Binding="{Binding Email}" Header="Email"/>
                <DataGridTemplateColumn Header="Contects"  Width="75">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <DataGrid ItemsSource="{Binding Contacts}" IsReadOnly="True" AutoGenerateColumns="False" HeadersVisibility="None">
                                <DataGrid.Columns>
                                    <DataGridTemplateColumn Width="*">
                                        <DataGridTemplateColumn.CellTemplate>
                                            <DataTemplate>
                                                <TextBlock Text="{Binding Telephone}"/>
                                            </DataTemplate>
                                        </DataGridTemplateColumn.CellTemplate>
                                    </DataGridTemplateColumn>
                                </DataGrid.Columns>
                            </DataGrid>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
                <DataGridTemplateColumn Header="Duties"  Width="75">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <DataGrid ItemsSource="{Binding Duties}" IsReadOnly="True" AutoGenerateColumns="False" HeadersVisibility="None">
                                <DataGrid.Columns>
                                    <DataGridTemplateColumn Width="*">
                                        <DataGridTemplateColumn.CellTemplate>
                                            <DataTemplate>
                                                <TextBlock Text="{Binding Duty}"/>
                                            </DataTemplate>
                                        </DataGridTemplateColumn.CellTemplate>
                                    </DataGridTemplateColumn>
                                </DataGrid.Columns>
                            </DataGrid>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
                <DataGridTemplateColumn Header="Languages"  Width="75">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <DataGrid ItemsSource="{Binding Languages}" IsReadOnly="True" AutoGenerateColumns="False" HeadersVisibility="None">
                                <DataGrid.Columns>
                                    <DataGridTemplateColumn Width="*">
                                        <DataGridTemplateColumn.CellTemplate>
                                            <DataTemplate>
                                                <TextBlock Text="{Binding LanguageName}"/>
                                                
                                            </DataTemplate>
                                        </DataGridTemplateColumn.CellTemplate>
                                    </DataGridTemplateColumn>
                                </DataGrid.Columns>
                            </DataGrid>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>

        </DataGrid>
    </Grid>

CODE BEHIND:

using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Windows;
using System.Windows.Input;

namespace WpfApp1
{
    public partial class MainWindow : Window
    {
        private EmployeeViewModel _viewModel;

        public MainWindow()
        {
            InitializeComponent();
            _viewModel = new EmployeeViewModel();
            DataContext = _viewModel;
        }
    }

    public class EmployeeViewModel
    {
        private readonly EmployeeDbContext _context;

        public EmployeeViewModel()
        {


            using (var context = new EmployeeDbContext())
            {
                Employees = context.Employees
                       .Include(e => e.Duties)
                    .Include(e => e.Contacts)

                    .Include(e => e.Languages)
                    .ToList();


            }

        }


        public List<Employee> Employees { get; set; } = new List<Employee>();

        public void SaveChanges()
        {
            _context.SaveChanges();
        }

        // Add methods for CRUD operations as needed
    }
  
    public class EmployeeDbContext : DbContext
    {
        public DbSet<Employee> Employees { get; set; }
        public DbSet<EmployeesContact> EmployeesContacts { get; set; }
        public DbSet<EmployeesDuty> EmployeesDuties { get; set; }
        public DbSet<EmployeesLanguage> EmployeesLanguages { get; set; }




        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            // Configure your database connection here
            optionsBuilder.UseSqlServer("Data Source=(localdb)\\ProjectModels;Initial Catalog=EmployeesDB;Integrated Security=True;Connect Timeout=30;Encrypt=False;Trust Server Certificate=False;Application Intent=ReadWrite;Multi Subnet Failover=False");

        }
    }
    public class Employee
    {
        public int EmployeeID { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public int Age { get; set; }
        public string Gender { get; set; }
        public string Email { get; set; }

        public ObservableCollection<EmployeesContact> Contacts { get; set; }
        public ObservableCollection<EmployeesDuty> Duties { get; set; }
        public ObservableCollection<EmployeesLanguage> Languages { get; set; }
    }

    public class EmployeesContact
    {
        [Key] // Define TelephoneID as the primary key
        public int TelephoneID { get; set; }

        public int EmployeeID { get; set; }
        public string Telephone { get; set; }

        // Other properties and relationships
    }

    public class EmployeesDuty
    {
        public int EmployeeID { get; set; }
        [Key]
        public int EmployeeDutyID { get; set; }
        public string Duty { get; set; }
    }

    public class EmployeesLanguage
    {
        public int EmployeeID { get; set; }
        [Key]
        public int EmployeeLanguageID { get; set; }
        public string LanguageName { get; set; }
        public string TalkingAbility { get; set; }
        public string ReadingAbility { get; set; }
        public string WritingAbility { get; set; }
    }
}

LOOKS LIKE THIS


Solution

  • To filter employees by duty, you could use a CollectionViewSource along with a filter predicate. Here's how you can achieve this:

    Modify your EmployeeViewModel as follows:

    public class EmployeeViewModel : INotifyPropertyChanged
    {
        private string _dutyFilter;
    
        public string DutyFilter
        {
            get { return _dutyFilter; }
            set
            {
                if (_dutyFilter != value)
                {
                    _dutyFilter = value;
                    OnPropertyChanged(nameof(DutyFilter));
                    ApplyFilter();
                }
            }
        }
    public EmployeeViewModel()
    {
        using (var context = new EmployeeDbContext())
        {
            Employees = context.Employees
                .Include(e => e.Duties)
                .Include(e => e.Contacts)
                .Include(e => e.Languages)
                .ToList();
        }
    
    
        DutyFilter = "";
    } 
    
    private ListCollectionView _filteredEmployees;
    
    public ListCollectionView FilteredEmployees
    {
        get { return _filteredEmployees; }
        set
        {
            _filteredEmployees = value;
            OnPropertyChanged(nameof(FilteredEmployees));
        }
    }
    
    private void ApplyFilter()
    {
        FilteredEmployees = new ListCollectionView(Employees);
        FilteredEmployees.Filter = employee =>
        {
            var emp = (Employee)employee;
            return emp.Duties.Any(d => d.Duty.Contains(DutyFilter, StringComparison.OrdinalIgnoreCase));
        };
    }
        ...
    }
    

    THE RESULT