Cascading filter using different control and validation MVVM WPF.

don bradman 626 Reputation points
2022-06-26T13:56:32.823+00:00

I'm trying to do a cascading type filter using combo box, text box and radio buttons maintaining MVVM pattern.

What I mean by that is initially when the app loads the radio buttons, text box and button is going to be inactive, then when I type/choose a item from the combo box the data is going to be filtered based on the combo box selected item (matching with the Party column).
When a valid item is selected from the combo box then the radio buttons, text box and button is going to become active and then the datagrid will further be filtered using both the text box text and the combo box selected item on the button click.

Now, the text box text will be matched against the BillNo column when the 1st radiobutton is selected, will be matched against the BillDt column when the 2nd radiobutton is selected and will be matched against the Amt column when the 3rd radiobutton is selected. I'm struggling to implement that as well.

Here is some of my code :

XAML

<Grid>  
    <Grid.RowDefinitions>  
        <RowDefinition  
            Height="60" />  
        <RowDefinition  
            Height="Auto" />  
        <RowDefinition  
            Height="Auto" />  
        <RowDefinition  
            Height="*" />  
    </Grid.RowDefinitions>  
    <StackPanel  
        Orientation="Horizontal"  
        HorizontalAlignment="Left"  
        Grid.Row="0"  
        Grid.RowSpan="2">  
        <Label  
            Grid.Row="0"  
            Content="Party :" />  
        <ComboBox ItemsSource="{Binding ComboItems}" SelectedItem="{Binding SelectedCBItem}"  
                  Text="{Binding SelectedCBItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"  
                  IsTextSearchEnabled="False"  
                  IsEditable="True"  
                  x:Name="cmb"/>  
    </StackPanel>  
    <StackPanel  
        Orientation="Horizontal"  
        HorizontalAlignment="Right">  
        <RadioButton IsEnabled="{Binding ElementName=cmb, Path=SelectedIndex, Converter={StaticResource IndexToBoolConverter}}" IsChecked="True"  
                     Content="Invoice No."  
                     x:Name="rb1"/>  
        <RadioButton IsEnabled="{Binding ElementName=cmb, Path=SelectedIndex, Converter={StaticResource IndexToBoolConverter}}"  
                     Content="Invoice Date"  
                     x:Name="rb2" />  
        <RadioButton IsEnabled="{Binding ElementName=cmb, Path=SelectedIndex, Converter={StaticResource IndexToBoolConverter}}"  
                     Content="Amount"  
                     x:Name="rb3" />  
    </StackPanel>  
    <TextBlock  
        Grid.Row="2"  
        x:Name="tblock">  
    </TextBlock>  
    <StackPanel  
        Grid.Row="1"  
        Orientation="Horizontal"  
        HorizontalAlignment="Right">  
        <Grid>  
            <TextBox IsEnabled="{Binding ElementName=cmb, Path=SelectedIndex, Converter={StaticResource IndexToBoolConverter}}"  
                     Text="{Binding FilterString, UpdateSourceTrigger=PropertyChanged}"  
                     x:Name="txt"/>  
            <TextBlock  
                IsHitTestVisible="False"  
                Text="Enter text here..."  
                VerticalAlignment="Center"  
                HorizontalAlignment="Left"  
                Margin="20,3,0,0"  
                Foreground="Gray">  
            </TextBlock>  
        </Grid>  
        <Button Command="{Binding GoButtonClicked}"  
                Content="Go" />  
    </StackPanel>  
    <Grid  
        Grid.Row="2">  
        <Grid.ColumnDefinitions>  
            <ColumnDefinition  
                Width="Auto" />  
            <ColumnDefinition  
                Width="*" />  
            <ColumnDefinition  
                Width="*" />  
        </Grid.ColumnDefinitions>  
    </Grid>  
    <DockPanel  
        Grid.Row="3">  
        <DataGrid ItemsSource="{Binding AllBills}"  
                  AutoGenerateColumns="False"  
                  HeadersVisibility="Column"  
                  GridLinesVisibility="None"  
                  IsReadOnly="True"  
                  HorizontalScrollBarVisibility="Auto"  
                  CanUserAddRows="False"  
                  SelectionUnit="FullRow"  
                  x:Name="dg">  
            <DataGrid.Columns>  
                <DataGridTextColumn  
                    Header="Vendor"  
                    Binding="{Binding Path=Party, Mode=OneWay}"  
                    IsReadOnly="True" />  
                <DataGridTextColumn  
                    Header="Bill No."  
                    Binding="{Binding Path=BillNo, Mode=OneWay}"  
                    IsReadOnly="True" />  
                <DataGridTextColumn  
                    Header="Bill Date"  
                    Binding="{Binding Path=BillDt, Mode=OneWay}"  
                    IsReadOnly="True" />  
                <DataGridTextColumn  
                    Header="Amount"  
                    Binding="{Binding Path=Amt, StringFormat=N2, Mode=OneWay}"  
                    IsReadOnly="True" />  
                <DataGridTextColumn  
                    Header="Due Date"  
                    Binding="{Binding Path=DueDt, Mode=OneWay}"  
                    IsReadOnly="True" />  
                <DataGridTextColumn  
                    Header="Paid On"  
                    Binding="{Binding Path=PaidOn, Mode=OneWay}"  
                    IsReadOnly="True" />  
            </DataGrid.Columns>  
        </DataGrid>  
    </DockPanel>  
</Grid>  

CS file

public class Bills : ViewModelBase  
    {  
        private string _party;  
        public string Party  
        {  
            get  
            {  
                return _party;  
            }  
            set  
            {  
                SetValue(ref _party, value);  
            }  
        }  
  
        private string _billNo;  
        public string BillNo  
        {  
            get  
            {  
                return _billNo;  
            }  
            set  
            {  
                SetValue(ref _billNo, value);  
            }  
        }  
  
  
        private string _billDt;  
        public string BillDt  
        {  
            get  
            {  
                return _billDt;  
            }  
            set  
            {  
                SetValue(ref _billDt, value);  
            }  
        }  
  
        private string _amt;  
        public string Amt  
        {  
            get  
            {  
                return _amt;  
            }  
            set  
            {  
                SetValue(ref _amt, value);  
            }  
        }  
  
    }  
  
    public class Model  
        {  
            private List<Bills> _sBills;  
      
            public List<Bills> SBills  
            {  
                get  
                {  
                    if (_sBills == null) LoadAllBillsFromDatabase();  
                      
                    return _sBills;  
                }  
            }  
  
          
        public void LoadAllBillsFromDatabase()  
        {  
            SQLiteConnection m_dbConnection = new SQLiteConnection(@"Data Source=Bills.db;");  
            SQLiteCommand sqlCom = new SQLiteCommand(@"Select * From billdata", m_dbConnection);  
            SQLiteDataAdapter sda = new SQLiteDataAdapter(sqlCom);  
            DataTable dt = new DataTable();  
            sda.Fill(dt);  
            _sBills = new List<Bills>();  
              
            foreach (DataRow row in dt.Rows)  
            {  
                _sBills.Add(new Bills()  
                            {  
                                Party = (string)row["Party"],  
                                BillNo = (string)row["BillNo"],  
                                BillDt = (string)(row["BillDt"]),  
                                Amt = (string)row["Amt"],  
                            });  
                  
            }  
            m_dbConnection.Close();  
        }  
    }  
  
public class BillsViewModel : ViewModelBase  
    {  
        private List<Bills> _allBills;  
        public RelayCommand GoButtonClicked { get; set; }  
  
        public BillsViewModel()  
        {  
            _allBills = m.SBills;  
  
            AllBills = new ListCollectionView(_allBills)  
            {  
                Filter = o => ((Bills)o).Party == SelectedCBItem2  
            };  
              
            ComboItems = _allBills.Select(b => b.Party).Distinct().OrderBy(b => b).ToList();  
              
            GoButtonClicked = new RelayCommand(GoFilterData);  
        }  
          
        public void GoFilterData(object param)  
        {  
            AllBills = new ListCollectionView(_allBills)  
            {  
                Filter = o => ((Bills)o).Party == SelectedCBItem && ((Bills)o).BillNo == FilterString  
            };  
            AllBills.Refresh();  
        }  
  
        Model m = new Model();  
  
        public ICollectionView AllBills { get; private set; }  
  
        public List<string> ComboItems { get; private set; }  
  
        private string _selectedCBItem;  
        public string SelectedCBItem  
        {  
            get { return _selectedCBItem; }  
            set  
            {  
                SetValue(ref _selectedCBItem, value);  
            }  
        }  
          
        private string _filterString;  
        public string FilterString  
        {  
            get { return _filterString; }  
            set  
            {  
                _filterString = value;  
                SetValue(ref _filterString, value);  
            }  
        }  
    }  

and also the converter class:

public class IndexToBoolConverter : IValueConverter  
{  
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)  
    {  
        if ((int)value >= 0)  
        {  
            return true;  
        }  
        else  
        {  
            return false;  
        }  
    }  
      
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)  
        {  
            throw new NotImplementedException();  
        }  
    }  

The initial filtering when I select/type a valid combo box item is working but the button click filtering is what also not working.

Also, the radiobutton checked validation with the filtering using the text box is quite challenging for me.

Help!

My project onedrive link

Developer technologies | Windows Presentation Foundation
Developer technologies | C#
Developer technologies | 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.
0 comments No comments
{count} votes

Answer accepted by question author
  1. Hui Liu-MSFT 48,711 Reputation points Microsoft External Staff
    2022-06-27T09:36:44.127+00:00

    I set up update notifications for AllBills and it filters successfully.

        private ICollectionView _allBillsCollection;  
         public ICollectionView AllBills  
         {  
           get { return _allBillsCollection; }  
           set { _allBillsCollection = value; SetValue(ref _allBillsCollection, value); }  
          }  
    

    Update

    Xaml:

    <Window.Resources>  
            <local:IndexToBoolConverter x:Key="IndexToBoolConverter"/>  
            <ObjectDataProvider x:Key="selectColumn" ObjectType="{x:Type local:SelectOptions}" />  
            <local:RadioButtonCheckedConverter x:Key="RadioButtonCheckedConverter" />  
        </Window.Resources>  
      
    <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">  
                                <RadioButton IsEnabled="{Binding ElementName=cmb2, Path=SelectedIndex, Converter={StaticResource IndexToBoolConverter}}"  
                                             IsChecked="{Binding SOptions.EnumProperty,Converter= {StaticResource RadioButtonCheckedConverter}, ConverterParameter={x:Static local:Options.BillNo}}"  
                  VerticalAlignment="Bottom"  
                  Margin="10,5,0,2"  
                  Content="Invoice No."  
                  Width="90"  
                  Padding="5"  
                  FontFamily="Candara"  
                  FontSize="15"  
                  Style="{StaticResource LeftRoundedRadioButtonStyle}"  
                  x:Name="rb1"  
                                                GroupName="group1"  
                                             />  
                                <RadioButton IsEnabled="{Binding ElementName=cmb2, Path=SelectedIndex, Converter={StaticResource IndexToBoolConverter}}"  
                                              IsChecked="{Binding SOptions.EnumProperty,Converter= {StaticResource RadioButtonCheckedConverter}, ConverterParameter={x:Static local:Options.BillDt}}"  
                  VerticalAlignment="Bottom"  
                  Margin="0,5,0,2"  
                  Content="Invoice Date"  
                  Width="100"  
                  Padding="5"  
                  FontFamily="Candara"  
                  FontSize="15"  
                  Style="{StaticResource MyRadioButtonStyle}"  
                  x:Name="rb2"   
                                             GroupName="group1"  
     />  
                                <RadioButton IsEnabled="{Binding ElementName=cmb2, Path=SelectedIndex, Converter={StaticResource IndexToBoolConverter}}"  
                                              IsChecked="{Binding SOptions.EnumProperty,Converter={StaticResource RadioButtonCheckedConverter}, ConverterParameter={x:Static local:Options.Amt}}"  
                  VerticalAlignment="Bottom"  
                  Margin="-5,5,10,2"  
                  Content="Amount"  
                  Width="120"  
                  Padding="5"  
                  FontFamily="Candara"  
                  FontSize="15"  
                  Style="{StaticResource RightRoundedRadioButtonStyle}"  
                  x:Name="rb3"   
     GroupName="group1"  
                                             />  
                            </StackPanel>  
      
    <TextBox IsEnabled="{Binding ElementName=cmb2, Path=SelectedIndex, Converter={StaticResource IndexToBoolConverter}}"  
      Text="{Binding FilterString,Mode=TwoWay,UpdateSourceTrigger=LostFocus }"  x:Name="txt"     />  
    

    Codebehind:

     public class SelectOptions  
      {  
     public Options EnumProperty { get; set; }  
     public bool BooleanProperty { get; set; }  
      }  
      public enum Options  
      {  
     BillNo ,  
     BillDt,  
     Amt  
      }  
      public class RadioButtonCheckedConverter : IValueConverter  
      {  
     public object Convert(object value, Type targetType, object parameter,  
     System.Globalization.CultureInfo culture)  
     {  
       return value.Equals(parameter);  
     }  
     public object ConvertBack(object value, Type targetType, object parameter,  
     System.Globalization.CultureInfo culture)  
     {  
       return value.Equals(true) ? parameter : Binding.DoNothing;  
     }  
      }  
    

    ViewModel:
    215998-7.txt
    215999-image.png


    If the response is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


0 additional answers

Sort by: Most helpful

Your answer

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