简体   繁体   中英

How to Create a Filter in WPF using Datagrid and ComboBox

So here I have a MVVM form. the Form contains a Datagrid which is connected to the Databank. I also have a ComboBox which I want to use as a filter option. The Filter option shoud filter by the "AnlV nr" so when the user selects "01" from the ComboBox the datagrid should refresh and show only that "AnlV nr" that have "01" Below I will share you the code and you can see that i've gotten as far as showing the "AnlV" values in the ComboBox but I now do not know how to do the rest and make the filter work. Below is my Viewmodel and the Xaml code.

If anyone can help me with this I would really apreciate it.

Xaml Code:

<Window x:Class="QBondsFrontend.Views.Input.AnlVTexteView"
        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:QBondsFrontend.Views.Input" xmlns:input="clr-namespace:QBondsFrontend.ViewModels.Input" d:DataContext="{d:DesignInstance Type=input:AnlVTexteViewModel}"
        mc:Ignorable="d"
        Title="AnlVTexteView" 
        Width="800"
        MinHeight="400"
        Height="490"
        MinWidth="1010"
        MaxWidth="1010"
        UseLayoutRounding="True">
    <Grid Background="#A8A8A8" >
        

        <StackPanel VerticalAlignment="Top" Background="#A8A8A8" Orientation="Horizontal" Height="57">
            <Label  
                   Content="AnlV Nr.:" Height="35" FontSize="12"/>

            <ComboBox  Background="LightGray" Height="20" Width="70" ItemsSource="{Binding lstAnlVTexte}" SelectedItem="{Binding Search}">
                <ComboBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding AnlVPara}"/>
                    </DataTemplate>
                </ComboBox.ItemTemplate>

            </ComboBox>


                <Button  Height="18" Width="68" Margin="5, 0"
                    Content="Filter löschen" FontSize="11" Style="{StaticResource STL_ButtonStandard}"
                    x:Name="filterlöschen"  
                     Command="{Binding icdFilterDelete}"/>

            
                    
            
            
        </StackPanel>

        
        

       
        <StackPanel Background="LightGray" VerticalAlignment="Top" Height="177"  Margin="0,57,0,0">


            <DataGrid x:Name="datagridXAML" 
                      Height="177" 
                      ItemsSource="{Binding lstAnlVTexte, Mode=TwoWay}" 
                      Style="{StaticResource STL_DataGridReporting}"
                      CellStyle="{StaticResource STL_DataGridCellReporting}"
                      ColumnHeaderStyle="{StaticResource STL_DataGridColumnHeaderReporting}"
                      AlternatingRowBackground="#A8A8A8"
                      CanUserResizeColumns="False"
                      >
                      

                <DataGrid.Columns>
                   
                    <DataGridTextColumn Header="AnlV-Nr" 
                                        Binding="{Binding AnlVPara}" 
                                        Width="60"/>
                    
                    
                    <DataGridTextColumn Header="gültig ab" 
                                        Binding="{Binding TextGueltigAb}"
                                        Width="68"/>
                    
                    <DataGridTextColumn Header="Text" 
                                        Binding="{Binding ParaText}" 
                                        Width="750"/>
                    
                    <DataGridTextColumn Header="Info" 
                                        Binding="{Binding Info}" 
                                        Width="*"/>

                </DataGrid.Columns>

            </DataGrid>

        </StackPanel>

        
        
        
        <StackPanel Background="#A8A8A8" HorizontalAlignment="Center" Margin="10,268,0,141" Width="1010" >
            
            <Label Content="Bearbeitungsbereich" FontWeight="Bold" FontSize="12" Height="33" />
        
        </StackPanel>




        <StackPanel>
           
            
            <StackPanel Orientation="Horizontal" Background="#A8A8A8" HorizontalAlignment="Center" 
                        Width="1010" Margin="0,294,0,0" Height="31">
                
                <Label Height="25" Width="60" Margin="20, 0, 0, 0" Content="AnlV-Nr.:"  />

                <ComboBox IsEditable="True" Background="gray" Height="22" Width="69" ItemsSource="{Binding AnlVPara}">
                    <ComboBox.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding lstAnlVTexte}"/>
                        </DataTemplate>
                    </ComboBox.ItemTemplate>
                </ComboBox>



                    <CheckBox Height="15" Margin="10, 0, 0, 0"  />
                
                <Label  Height="26" Width="122" Content="Editierwarnungen"  />
                                
                <StackPanel Height="48" Width="100"/>
                        
            </StackPanel>
            
            
            
            
            <StackPanel Height="22" Orientation="Horizontal">
                
                <Label Margin="20, 0, 0, 0" Content="gültig ab:" Height="27"  />
                
                <TextBox Background="LightGray" Height="20" Width="100" />
            
            </StackPanel>

            
            
            
            <StackPanel Height="50" Orientation="Horizontal">
                
                <Label  Content="Text:" Height="27" Width="38" Margin="42,0,0,10"  />
                
                <TextBox Background="LightGray" Width="500" Height="43" />
            
            </StackPanel>
            
            
            
            
            <StackPanel Orientation="Horizontal" >
                
                <Label Content="Info:" Height="27" Width="38" Margin="42,0,0,0" />
                
                <TextBox Background="LightGray" Width="500" Height="20" />
                
                <Button x:Name="BTN_speichern" Width="80" Height="18" Margin="20,0,0,0" Content="Speichern" 
                        Style="{StaticResource STL_ButtonStandard}" Command="{Binding icdSpeichern}"/>
            
            </StackPanel>
            
        
            
            
        </StackPanel>
    </Grid>
</Window>

ViewModel:

using Newtonsoft.Json;
using QBondsData.DBModels;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Linq;

namespace QBondsFrontend.ViewModels.Input
{
    public class AnlVTexteViewModel : BaseViewModel
    {

        #region data

        private string _AnlVPara;
        private DateTime _TextGueltigAb;
        private string _ParaText;
        private string _Info;      
        private List<AnlVhistText> _lstAnlVTexte;
        private string _search;
        
        #endregion
        #region constructor
        public AnlVTexteViewModel()
        {
            icdFilterDelete = new RelayCommand<object>(parameter => filterdelete(), parameter => true);


            icdSpeichern = new RelayCommand<object>(parameter => speichern(), parameter => true);

        
           GetData();
        }




        #endregion
        #region members

        

        public ICommand icdFilterDelete { get; set; }
                     

        public ICommand icdSpeichern { get; set; }




        private string Search
        {
            get { return _search; }
            set
            {
                _search = value;
                OnPropertyChanged("Search");
            }
        }

        




        public string AnlVPara
        {
            get
            {
                return _AnlVPara;
            }
            set
            {
                _AnlVPara = value;
                OnPropertyChanged("AnlVPara");
            } 
        }

        public DateTime TextGueltigAb
        {
            get
            {
                return _TextGueltigAb;
            }
            set
            {
                _TextGueltigAb = value;
                OnPropertyChanged("TextGueltigAb");
            }
        }

        public string ParaText
        {
            get
            {
                return _ParaText;
            }
            set
            {
                _ParaText = value;
                OnPropertyChanged("ParaText");

                
            }
        }

        public string Info
        {
            get
            {
                return _Info;
            }
            set
            {
                _Info = value;
                OnPropertyChanged("Info");
            }
        }

        public List<AnlVhistText> lstAnlVTexte
        {
            get { return _lstAnlVTexte; }
            set
            {
                
                _lstAnlVTexte = value;
                OnPropertyChanged("lstAnlVTexte");
            }
        }



        #endregion
        #region methods

        private void filterdelete()
        {
            
        }

          
        private void speichern()
        {
             
        }
        private async Task GetData()
        {
            HttpResponseMessage Response = await Globals.SendRequest("AnlVTexte/GetAnlVTexte"
                                                                 , "GET");
            if (Response.IsSuccessStatusCode)
            {
                lstAnlVTexte = JsonConvert.DeserializeObject<List<AnlVhistText>>
                        (await Response.Content.ReadAsStringAsync());
                    
            }
            else
            {
                lstAnlVTexte = new List<AnlVhistText>();

                Application.Current.Dispatcher.Invoke((Action)delegate
                {
                    Globals.CloseReportByHash(this.GetHashCode()
                                            , "Fehler! (HTTP Status " + Response.StatusCode + ")." +
                                              "Kontaktieren Sie den Support.");
                    
                
                });
            }
        
        }
        #endregion




    }


}

When you change the type of lstAnlVTexte to ICollectionView you get two events CurrentChanged and CurrentChanging which you can handle in your viewmodel. From the ICollectionView you can get the CurrentItem .

Like this:

private List<AnlVhistText> _anlVTexte = new List<AnlVhistText>();


public AnlVTexteViewModel()
{
    [...]
    lstAnlVTexte = new CollectionView(_anlVTexte);
    lstAnlVTexte.CurrentChanged += SelectionChanged;  // raised after the current item has been changed.
    lstAnlVTexte.CurrentChanging += SelectionChanging;  // raise before changing the current item. Event handler can cancel this event.
}

private void SelectionChanged(object sender, EventArgs e)
{
var selectedItem = lstAnlVTexte.CurrentItem;
}

private void SelectionChanging(object sender, CurrentChangingEventArgs e)
{

}


private ICollectionView _lstAnlVTexte;

public ICollectionView lstAnlVTexte
{
    get { return _lstAnlVTexte; }
    set
    {
        
        _lstAnlVTexte = value;
        OnPropertyChanged("lstAnlVTexte");
    }
}

Here's a sample using the community toolkit mvvm and linq.

If you're not familiar, the toolkit does code generation.

This is a simple scenario to illustrate the approach.

Mainwindowviewmodel.

public partial class MainWindowViewModel : ObservableObject
{
    [ObservableProperty]
    private int selectedFilterInt = -1;

    partial void OnSelectedFilterIntChanged(int newValue)
    {
        FilteredList = new ObservableCollection<MyItem>(FullList.Where(x=>x.Category == selectedFilterInt).ToList());
    }

    public List<int> FilterOptions { get; set; } = new List<int> {1,2,3};

    private List<MyItem> FullList= new List<MyItem>           
        {    
             new MyItem{ Category = 1},
             new MyItem{ Category = 1},
             new MyItem { Category = 1 },
             new MyItem { Category = 2 },
             new MyItem { Category = 2 },
             new MyItem { Category = 3 }
        };


    [ObservableProperty]
    private ObservableCollection<MyItem> filteredList = new ObservableCollection<MyItem>();

    public MainWindowViewModel()
    {
        FilteredList = new ObservableCollection<MyItem>(FullList);
    }
}

There's a full list of all the items.

But a filtered list is going to be bound to the itemssource of my listbox ( equivalent to your datagrid ).

Due to the code generated, when selectedFilterInt changes, OnSelectedFilterIntChanged will be called. It's got a handler listening for property changed of SelectedFilterInt if you dug into the generated code.

That method uses a linq where to filter the full list into filtered list.

Setting that filtered list property raises property changed and the view re reads the new collection.

MainWindow. ( I did mention this is simplified )

<Window.DataContext>
    <local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
    <StackPanel>
        <ComboBox SelectedItem="{Binding SelectedFilterInt}"
                  ItemsSource="{Binding FilterOptions}"/>
        <ListBox ItemsSource="{Binding FilteredList}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel>
                        <TextBlock Text="{Binding Category}"/>
                        <TextBlock Text="{Binding Comment}"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </StackPanel>
</Grid>
</Window>

and MyItem

public partial class MyItem : ObservableObject
{
    [ObservableProperty]
    private int category = 0;

    [ObservableProperty]
    private string comment = "Some test string";
}

Which is a bit underwhelming visually but works:

在此处输入图像描述

In your code you need to get all the data into a collection.

Call that FulList.

You then need another collection which will be the filtered data.

Call this FilteredList.

Bind itemssource to FilteredList

Initially, you presumably want FilteredList to be = FullList

Then when the user selects something in the combobox you need to react to that.

You could bind selecteditem to a property and act in the setter or handle propertychanged like my code does.

However you do it, you get a new integer.

You then use that to filter FullList into a new collection which will replace the bound FilteredList.

You also need to somehow have one entry per AnlV nr whatever that is in your combobox.

AnlV nr isn't going to work as a property name since it's got a space but it is the equivalent to Category in my sample.

You will use that selected value in the linq.

Substitute the name of that property for Category. Substitute the type of whatever your collection is. Maybe that's AnlVhistText. I'm not sure.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM