Home > Mobile >  How can I make a column name filtering in data table? using C#, WPF
How can I make a column name filtering in data table? using C#, WPF

Time:09-09

I am very first to this work. I want to make a data table which is filtered on its column name. Here is what I want: enter image description here

I want to click TYPE and there are only "A", "B", "C". So I can see only selected type contents.

umm like this one. enter image description here but only in the column name. the highest column.

I am using C#, .NET 6.0, WPF.

Can you show me some simple or complex codes by C# and WPF? I dont know much about it but keep studying.

THANKS

CodePudding user response:

You always filter a ItemsControl like DataGrid by assigning a filter expression to its associated ICollectionView.Filter property.
For this purpose, you can retrieve the ICollectionView of an ItemsControl by accessing the ItemsControl.Items property (in case you have direct access to the ItemsControl instance.
Otherwise, you can always use the static helper method CollectionViewSource.GetDefaultView(mySourceCollection), which of course requires a direct reference to the source collection (for example in a data binding scenario).

Assuming you have a ComboBox to select the filter predicate e.g. a string value or enum value (whatever the data type of the Type property/column is) for the corresponding column and a DataGrid that shows data by binding to a collection of data models of type MyRowItem which has the properties Name, Content, Type and Exceptions, a very simple solution could be as follows:

Handle the ComboBox.SelectedItemChanged event in your code-behind

private void OnComboBoxSelectedItemChanged(object sender, EventArgs e)
{
  var comboBox = sender as ComboBox;
  var selectedColumnValue = comboBox.SelectedItem as string;

  // ICollectionView.Filter is of type 'Predicate<object>',
  // so we can assign a simple lambda expression as filter predicate.
  // The predicate must return 'true' if the tested item must be displayed.
  this.DataGridView.Items.Filter = item => (item as MyRowItem).Type == selectedColumnValue;
}
<Window>
  <StackPanel>
    <DataGrid x:Name="DataGridView" />
    <ComboBox SelectedItemChanged="OnComboBoxSelectedItemChanged" />
  </StackPanel>
</Window>

It's important to understand the concept of collection views. The WPF binding engine will reference the collection view of a collection instead the collection itself: Collection views.
Even if you are assigning the source collection locally without any data binding to the ItemsControl.ItemsSource, the ItemsControl will internally register the collection with the binding engine in order to track changes.
For this reason, to improve performance you should always assign a collection that implements INotifyCollectionChanged (like the ObservableCollection for example) to the ItemsControl.ItemsSource property.

CodePudding user response:

Example:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace Core2022.SO.nojob
{
    public enum TypeEnum
    { A, B, C }

    public class RowEntity
    {
        public string Name { get; set; } = string.Empty;

        public TypeEnum Type { get; set; }
    }

    public class TableVM
    {
        public ObservableCollection<RowEntity> Rows { get; } = new();

        public TypeEnum? SelectedType { get; set; }

        public static IReadOnlyList<TypeEnum> Types { get; } = Array.AsReadOnly((TypeEnum[])Enum.GetValues(typeof(TypeEnum)));
    }
}
<Window x:Class="Core2022.SO.nojob.ColumnFilterWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Core2022.SO.nojob"
        mc:Ignorable="d"
        Title="ColumnFilterWindow" Height="450" Width="800"
        DataContext="{DynamicResource vm}">
    <Window.Resources>
        <local:TableVM x:Key="vm">
            <local:TableVM.Rows>
                <local:RowEntity Name="first" Type="B"/>
                <local:RowEntity Name="second" Type="A"/>
                <local:RowEntity Name="third" Type="C"/>
                <local:RowEntity Name="fourth" Type="B"/>
                <local:RowEntity Name="fifth" Type="A"/>
                <local:RowEntity Name="sixth" Type="C"/>
                <local:RowEntity Name="seventh" Type="B"/>
                <local:RowEntity Name="eighth" Type="A"/>
                <local:RowEntity Name="ninth" Type="C"/>
                <local:RowEntity Name="tenth" Type="B"/>
                <local:RowEntity Name="eleventh" Type="A"/>
                <local:RowEntity Name="twelfth" Type="C"/>
            </local:TableVM.Rows>
        </local:TableVM>
    </Window.Resources>
    <Grid>
        <DataGrid x:Name="dGrid"
                  ItemsSource="{Binding Rows}"
                  AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Name}" Header="Name"/>
                <DataGridComboBoxColumn SelectedItemBinding="{Binding Type}"
                                        ItemsSource="{x:Static local:TableVM.Types}">
                    <DataGridComboBoxColumn.Header>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Text="TYPE"/>
                            <ComboBox x:Name="cBox" ItemsSource="{x:Static local:TableVM.Types}"
                                      SelectionChanged="OnTypeSelectionChanged"
                                      SelectedItem="{Binding SelectedType, Source={StaticResource vm}}"/>
                            <Button Content="❌" Foreground="Red" FontWeight="ExtraBold"
                                    Click="OnClearClick"/>
                        </StackPanel>
                    </DataGridComboBoxColumn.Header> 
                </DataGridComboBoxColumn>
            </DataGrid.Columns>

        </DataGrid>
    </Grid>
</Window>
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;

namespace Core2022.SO.nojob
{
    public partial class ColumnFilterWindow : Window
    {
        public ColumnFilterWindow()
        {
            InitializeComponent();
        }

        private void OnTypeSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            Selector selector = (Selector)sender;
            if (selector.SelectedItem is TypeEnum type)
            {
                dGrid.Items.Filter = item =>
                {
                    return item is RowEntity rowEntity &&
                           rowEntity.Type == type;
                };
            }
            else
            {
                dGrid.Items.Filter = null;
            }
        }

        private void OnClearClick(object sender, RoutedEventArgs e)
        {
            cBox.SelectedIndex = -1;
        }
    }
}
  • Related