Datagrid bind filter view for multiple textboxes

Kran2022 406 Reputation points
2022-12-13T13:06:37.577+00:00

Hi All:

I'm tried to duplicate the View Filter but it looks like i'm making a mistake. I have 4 datagrid columns & i need to make an individual search for two columsn, so i added two textboxes; one textbox is working, another textbox is not working:

  • Filter Working: TextBox x:Name="tname" Text="{Binding SizeSearch, UpdateSourceTrigger=PropertyChanged}"
  • Filter Not working: TextBox Name="tmainproduct" Text="{Binding MainProductSearch,UpdateSourceTrigger=PropertyChanged}"

How can i have multiple filters or dedicated filter for each textbox?

Also using Xdocument.Save() method, how can i save back the file after editing from the datagrid?

270055-dta.txt Find attached the file to read in the datagrid

XAML Code:

 <Grid>  
        <Grid.ColumnDefinitions>  
            <ColumnDefinition Width="*" />  
            <ColumnDefinition Width="*" />  
        </Grid.ColumnDefinitions>  
       
        <Grid Grid.Column="0" >  
            <Grid.RowDefinitions >  
                <RowDefinition Height="200"/>  
                <RowDefinition Height="*"/>  
  
            </Grid.RowDefinitions>  
            <StackPanel VerticalAlignment="Top" Margin="10,0,-10,0" Grid.Row="0">  
            <Label Name="lcategory" Content="Product Category Search" HorizontalAlignment="Left" Margin="0,0,0,0" />  
            <TextBox Name="tmainproduct" Text="{Binding MainProductSearch,UpdateSourceTrigger=PropertyChanged}"   
                     HorizontalAlignment="Left"  Width="150" Margin="5,5" />  
            <ComboBox x:Name="ccategory" Width="150" Text="{Binding MainProductSearch,UpdateSourceTrigger=PropertyChanged}"  Margin="5,5" HorizontalAlignment="Left" />  
            <Label Name="lproduct" Content="Product Name Search" Margin="5,5" HorizontalAlignment="Left" />  
            <TextBox x:Name="tname" Text="{Binding SizeSearch, UpdateSourceTrigger=PropertyChanged}" Margin="5,5" HorizontalAlignment="Left" Width="150"  />  
            <ComboBox x:Name="cpdtname" Width="150" Margin="5,5" HorizontalAlignment="Left" Text="{Binding SizeSearch, UpdateSourceTrigger=PropertyChanged}"/>  
            </StackPanel>  
            <DockPanel Grid.Row="1" >  
                    
            <DataGrid  x:Name="datagrid" VerticalAlignment="Top" HorizontalAlignment="Left" SelectedItem="{Binding SelectedProduct}" Width="400"   
               ItemsSource="{Binding View}" AutoGenerateColumns="False" CanUserAddRows="False" ScrollViewer.VerticalScrollBarVisibility="Visible" Margin="0,2,0,0"     
                       Height="{Binding RelativeSource={RelativeSource AncestorType={x:Type DockPanel}}, Path=ActualHeight}"  >  
                <DataGrid.Columns>  
  
                    <DataGridTextColumn Header="MianProduct"   Binding="{Binding Mainproduct}" Width="*" IsReadOnly="True"/>  
                    <DataGridTextColumn Header="Name"   Binding="{Binding Name}" Width="*" IsReadOnly="True"/>  
                    <DataGridTextColumn Header="Price"  Binding="{Binding Price}" Width="*" />  
                      
                    <DataGridTextColumn Header="Visible"  Binding="{Binding Visible}" Width="*" />  
                </DataGrid.Columns>  
  
            </DataGrid>  
            </DockPanel>  
          
        </Grid>  
  
        <Grid Grid.Row="0" Grid.Column="1" >  
            <StackPanel HorizontalAlignment="Stretch">  
            <Button Name="bsavepricefile" Content="Save File" HorizontalAlignment="Left" Margin="147,303,0,0" VerticalAlignment="Top" Width="75" Click="bsavepricefile_Click"/>  
                </StackPanel>  
        </Grid>  
    </Grid>  

Code incl class:

/// </summary>  
public partial class PricingEdit : Window  
{  
    public PricingEdit()  
    {  
        InitializeComponent();  
        DataContext = new ProductPriceViewModel();  
        tmainproduct.Background = (SolidColorBrush)new BrushConverter().ConvertFromString("#ff66ccff");  
        tmainproduct.Foreground = Brushes.Black;  
  
        addpretexts(); // to add some pre-texts to the comboboxes   
    }  
  
    void addpretexts()  
    {  
        List<string> MainProductCategory = new List<string>();  
  
        MainProductCategory.Add("PrintProduct");  
        MainProductCategory.Add("RetroPrint");  
        MainProductCategory.Add("PrintWithFrame");  
        MainProductCategory.Add("Calendar");  
        MainProductCategory.Add("Collage");  
        MainProductCategory.Add("CollagePoster");  
        MainProductCategory.Add("SingleSidePhoto");  
        MainProductCategory.Add("PassportPhoto");  
        MainProductCategory.Add("IDPhotoCard");  
        MainProductCategory.Add("GadgetProduct");  
        MainProductCategory.Add("GreetingCard");  
  
  
        foreach (var mpdtcategory in MainProductCategory)  
        {  
            ccategory.Items.Add(mpdtcategory);  
        }  
  
  
        List<string> ProductName = new List<string>();  
  
        ProductName.Add("10x10");  
        ProductName.Add("10x15");  
        ProductName.Add("10x8");  
        ProductName.Add("10x20");  
        ProductName.Add("13x18");  
        ProductName.Add("13x13");  
        ProductName.Add("15x20");  
        ProductName.Add("15x23");  
        ProductName.Add("20x25");  
        ProductName.Add("20x30");  
        ProductName.Add("Sticker");  
        ProductName.Add("Metallic");  
        ProductName.Add("Perfo");  
  
        foreach (var pdtnames in ProductName)  
        {  
            cpdtname.Items.Add(pdtnames);  
        }  
    }  
  
    private void bsavepricefile_Click(object sender, RoutedEventArgs e)  
    {  
  
    }  
  
     
}  
  
  
//https://learn.microsoft.com/en-us/answers/questions/675416/wpf-filtering-datagrid.html  
//https://stackoverflow.com/questions/1934935/wpf-using-multiple-filters-on-the-same-listcollectionview  
//https://www.c-sharpcorner.com/UploadFile/20c06b/filtering-elements-in-a-collection-in-wpf/  
class ProductPriceViewModel : INotifyPropertyChanged  
{  
    public event PropertyChangedEventHandler PropertyChanged;  
  
  
    public void OnPropertyChanged(String info)  
    {  
        if (PropertyChanged != null)  
        {  
            PropertyChanged(this, new PropertyChangedEventArgs(info));  
        }  
    }  
  
  
    public ProductPriceViewModel()  
    {  
        ProductPriceList = new ObservableCollection<Products>(GetProductsPriceList());  
  
        this._view = new ListCollectionView(this.productpricelist);  
        this._view.Filter = Filter;//MainProduct  
       this._view.Filter = SizeFilter; //Name (size seacrch) but not working  
  
  
    }  
  
    private bool Filter(object item)  
    {  
        if (String.IsNullOrEmpty(MainProductSearch))  
            return true;  
        else  
            return ((item as Products).Mainproduct.IndexOf(MainProductSearch, StringComparison.OrdinalIgnoreCase) >= 0) ||  
                ((item as Products).Name.IndexOf(MainProductSearch, StringComparison.OrdinalIgnoreCase) >= 0);  
                 
    }  
  
    private bool SizeFilter(object item)  
    {  
        if (String.IsNullOrEmpty(SizeSearch))  
            return true;  
        else  
            return ((item as Products).Name.IndexOf(SizeSearch, StringComparison.OrdinalIgnoreCase) >= 0);  
    }  
  
    private ObservableCollection<Products> productpricelist;  
  
    public ObservableCollection<Products> ProductPriceList  
    {  
        get { return productpricelist; }  
        set  
        {  
            productpricelist = value;  
            OnPropertyChanged("ProductPriceList");  
        }  
    }  
    private ListCollectionView _view;  
    public ICollectionView View  
    {  
        get { return this._view; }  
    }  
  
    private string _MainProductSearch;  
    public string MainProductSearch  
    {  
        get { return _MainProductSearch; }  
        set  
        {  
            _MainProductSearch = value;  
            OnPropertyChanged("MainProductSearch");  
            View.Refresh();  
        }  
    }  
  
    private string _SizeSearch;  
    public string SizeSearch  
    {  
        get { return _SizeSearch; }  
        set  
        {  
            _SizeSearch = value;  
            OnPropertyChanged("SizeSearch");  
            View.Refresh();  
        }  
    }  
  
    private List<Products> GetProductsPriceList()  
    {  
  
        var mylist = new List<Products>();  
        XmlDocument doc = new XmlDocument();  
        doc.Load(@"C:\xmltest\Dta.txt");  
        foreach (XmlElement pn in doc.SelectNodes("/Data/Products/*"))  
        {  
            var productlist = new Products  
            {  
                Mainproduct = pn.LocalName.ToString(),  
                Name = pn.GetAttribute("Name"),  
                Price = pn.SelectSingleNode(".//ProductPrice/@Price")?.Value,  
                Visible = pn.SelectSingleNode(".//ProductVisibility/@Visible")?.Value,  
            };  
            mylist.Add(productlist);  
        }  
  
        return mylist;  
    }  
  
    
}  
  
  
  
  
public class Products  
{  
  
    string mainproduct;  
    string name;  
    string price;  
    string visible;  
  
    public string Mainproduct  
    {  
        get { return mainproduct; }  
        set { mainproduct = value; }  
    }  
    public string Name  
    {  
        get { return name; }  
        set { name = value; }  
    }  
    public string Price  
    {  
        get { return price; }  
        set { price = value; }  
    }  
    public string Visible  
    {  
        get { return visible; }  
        set { visible = value; }  
    }  
}  
Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,853 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
11,399 questions
XAML
XAML
A language based on Extensible Markup Language (XML) that enables developers to specify a hierarchy of objects with a set of properties and logic.
837 questions
0 comments No comments
{count} votes

Accepted answer
  1. Peter Fleischer (former MVP) 19,336 Reputation points
    2022-12-14T13:20:39.333+00:00

    Hi,
    to change and save xml you can use XElement:

    ViewModel to previous XAML:

    namespace WpfApp033  
    {  
    #pragma warning disable CS8601, CS8602, CS8612  
    	class ProductPriceViewModel : INotifyPropertyChanged, ICommand  
    	{  
    		public List<string> MainProductCategory  
    		{  
    			get => new List<string>() {"PrintProduct","RetroPrint","PrintWithFrame","Calendar","Collage",  
    				"CollagePoster","SingleSidePhoto","PassportPhoto","IDPhotoCard","GadgetProduct","GreetingCard"};  
    		}  
      
    		public List<string> ProductName  
    		{  
    			get => new List<string>() {  
    				"10x10","10x15","10x8","10x20","13x18","13x13","15x20","15x23","20x25","20x30","Sticker","Metallic","Perfo" };  
    		}  
      
    		public event PropertyChangedEventHandler PropertyChanged;  
    		public event EventHandler? CanExecuteChanged;  
      
    		public void OnPropertyChanged(String info) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(info));  
      
    		private bool Filter(object item)  
    		{  
    			var ret = true;  
    			if (!String.IsNullOrEmpty(MainProductSearch))  
    				ret = ret && ((item as Product).Mainproduct.IndexOf(MainProductSearch, StringComparison.OrdinalIgnoreCase) >= 0) ||  
    						((item as Product).Name.IndexOf(MainProductSearch, StringComparison.OrdinalIgnoreCase) >= 0);  
    			if (!String.IsNullOrEmpty(SizeSearch))  
    				ret = ret && ((item as Product).Name.IndexOf(SizeSearch, StringComparison.OrdinalIgnoreCase) >= 0);  
    			return ret;  
    		}  
      
    		private ObservableCollection<Product> productpricelist;  
    		public ObservableCollection<Product> ProductPriceList  
    		{  
    			get { return productpricelist; }  
    			set  
    			{  
    				productpricelist = value;  
    				OnPropertyChanged("ProductPriceList");  
    			}  
    		}  
    		private CollectionViewSource cvs = new CollectionViewSource();  
    		public ICollectionView View  
    		{  
    			get  
    			{  
    				if (cvs.Source == null)  
    				{  
    					cvs.Source = GetProductsPriceList();  
    					cvs.View.Filter = Filter;  
    				}  
    				return this.cvs.View;  
    			}  
    		}  
      
    		public Product SelectedProduct { get; set; }  
      
    		private string _MainProductSearch;  
    		public string MainProductSearch  
    		{  
    			get { return _MainProductSearch; }  
    			set  
    			{  
    				_MainProductSearch = value;  
    				OnPropertyChanged("MainProductSearch");  
    				View.Refresh();  
    			}  
    		}  
      
    		private string _SizeSearch;  
    		public string SizeSearch  
    		{  
    			get { return _SizeSearch; }  
    			set  
    			{  
    				_SizeSearch = value;  
    				OnPropertyChanged("SizeSearch");  
    				View.Refresh();  
    			}  
    		}  
      
    		XElement data;  
      
    		private List<Product> GetProductsPriceList()  
    		{  
    			var mylist = new List<Product>();  
      
    			data = XElement.Load("Window033Dta.txt");  
    			foreach (XElement xe1 in data.Elements())  
    				if (xe1.Name == "Products")  
    					foreach (var xe2 in xe1.Elements()) mylist.Add(new Product(xe2));  
    			return mylist;  
    		}  
      
    		public bool CanExecute(object? parameter) => true;  
    		public void Execute(object? parameter) => data.Save("xxx.txt");  
    		}  
    	}  
      
      
    	public class Product  
    	{  
    		public Product(XElement xe3) => this.xe4 = xe3;  
    		private XElement xe4;  
    		public string Mainproduct { get => xe4.Name.LocalName; }  
    		public string Name { get => xe4.Attribute("Name").Value; }  
    		public string Price  
    		{  
    			get  
    			{  
    				XElement xe5 = xe4.Descendants("ProductPrice").FirstOrDefault();  
    				if (xe5 == null) return string.Empty;  
    				return xe5.Attribute("Price").Value;  
    			}  
    			set  
    			{  
    				XElement xe5 = xe4.Descendants("ProductPrice").FirstOrDefault();  
    				if (xe5 != null) xe5.Attribute("Price").Value = value;  
    			}  
    		}  
    		public string Visible  
    		{  
    			get  
    			{  
    				XElement xe5 = xe4.Descendants("ProductVisibility").FirstOrDefault();  
    				if (xe5 == null) return string.Empty;  
    				return xe5.Attribute("Visible").Value;  
    			}  
    			set  
    			{  
    				XElement xe5 = xe4.Descendants("ProductVisibility").FirstOrDefault();  
    				if (xe5 != null) xe5.Attribute("Visible").Value = value;  
    			}  
    		}  
    	}  
    }  
    
    1 person found this answer helpful.

1 additional answer

Sort by: Most helpful
  1. Peter Fleischer (former MVP) 19,336 Reputation points
    2022-12-13T17:47:58.703+00:00

    Hi,
    I simplified your project and ist works fine:

    XAML:

    <Window x:Class="WpfApp1.Window033"  
            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:WpfApp033"  
            mc:Ignorable="d"  
            Title="Window033" Height="450" Width="800">  
      <Window.DataContext>  
        <local:ProductPriceViewModel/>  
      </Window.DataContext>  
      <Grid>  
        <Grid.ColumnDefinitions>  
          <ColumnDefinition Width="*" />  
          <ColumnDefinition Width="*" />  
        </Grid.ColumnDefinitions>  
      
        <Grid Grid.Column="0" >  
          <Grid.RowDefinitions >  
            <RowDefinition Height="200"/>  
            <RowDefinition Height="*"/>  
      
          </Grid.RowDefinitions>  
          <StackPanel VerticalAlignment="Top" Margin="10,0,-10,0" Grid.Row="0">  
            <Label Content="Product Category Search" HorizontalAlignment="Left" Margin="0,0,0,0" />  
            <TextBox Text="{Binding MainProductSearch,UpdateSourceTrigger=PropertyChanged}"   
                     HorizontalAlignment="Left"  Width="150" Margin="5,5" />  
            <ComboBox Width="150" ItemsSource="{Binding MainProductCategory}"  
                      Text="{Binding MainProductSearch,UpdateSourceTrigger=PropertyChanged}"    
                      Margin="5,5" HorizontalAlignment="Left" />  
            <Label Content="Product Name Search" Margin="5,5" HorizontalAlignment="Left" />  
            <TextBox Text="{Binding SizeSearch, UpdateSourceTrigger=PropertyChanged}"   
                     Margin="5,5" HorizontalAlignment="Left" Width="150"  />  
            <ComboBox Width="150" ItemsSource="{Binding ProductName}"  
                      Text="{Binding SizeSearch, UpdateSourceTrigger=PropertyChanged}"  
                      Margin="5,5" HorizontalAlignment="Left"/>  
          </StackPanel>  
          <DockPanel Grid.Row="1" >  
      
            <DataGrid VerticalAlignment="Top" HorizontalAlignment="Left"   
                      SelectedItem="{Binding SelectedProduct}" Width="400"   
                      ItemsSource="{Binding View}" AutoGenerateColumns="False"   
                      CanUserAddRows="False" ScrollViewer.VerticalScrollBarVisibility="Visible"   
                      Margin="0,2,0,0"     
                      Height="{Binding RelativeSource={RelativeSource AncestorType={x:Type DockPanel}}, Path=ActualHeight}"  >  
              <DataGrid.Columns>  
                <DataGridTextColumn Header="MianProduct" Binding="{Binding Mainproduct}" Width="*" IsReadOnly="True"/>  
                <DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="*" IsReadOnly="True"/>  
                <DataGridTextColumn Header="Price" Binding="{Binding Price}" Width="*" />  
                <DataGridTextColumn Header="Visible" Binding="{Binding Visible}" Width="*" />  
              </DataGrid.Columns>  
            </DataGrid>  
          </DockPanel>  
      
        </Grid>  
      
        <Grid Grid.Row="0" Grid.Column="1" >  
          <StackPanel HorizontalAlignment="Stretch">  
            <Button Content="Save File" HorizontalAlignment="Left" Margin="147,303,0,0"   
                    VerticalAlignment="Top" Width="75"   
                    Command="{Binding}" CommandParameter="bsavepricefile_Click"/>  
          </StackPanel>  
        </Grid>  
      </Grid>  
    </Window>  
    

    and ViewModel:

    Result:

    270195-x.gif

    1 person found this answer helpful.

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.