0

New to WPF and MVVM. I'm trying to use a filter with FilterEventHandler to a CollectionViewSource. I'm trying to add the filter in a property change(p_sSelectedCreatedDate). The problem is that FilterEventHandler delegate function(FilterByCreatedDate) is not firing when I add the filter to the CollectionViewSource object. When I debug, I can see in the code that the filter is being added as in the below line.

CVS.Filter += new FilterEventHandler(FilterByCreatedDate);

However, the code returns without executing FilterByCreatedDate. Note that I am only publishing the code parts which are necessary to this problem and a BaseViewModel which inherit from INotifyPropertyChanged.

Following is the necessary code.

ScanBatchWindow.xaml

<Window x:Class="BatchManPOC.ScanBatchWindow"
    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:BatchManPOC"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:cmdBehavior="clr-namespace:BatchManPOC.CmdBehavior"
    xmlns:video="clr-namespace:BatchManPOC.Video"
    xmlns:Custom="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    mc:Ignorable="d"
    Title="ScanBatchWindow" 
    Height="800"
    Width="800">
<Window.Resources>
    <CollectionViewSource Source="{Binding p_ListBatches}" x:Key="CVS"/>
</Window.Resources>
     <Grid>
         <Grid.RowDefinitions>
               <RowDefinition/>
         </Grid.RowDefinitions>
              <Custom:DataGrid ItemsSource="{Binding Source={StaticResource CVS}}" Margin="8" Grid.Row="0" AutoGenerateColumns="True"  IsReadOnly="True">
</Custom:DataGrid>
        </Grid>
</Window>

ScanBatchViewModel.cs

public class ScanBatchViewModel : BaseViewModel
{
    public ObservableCollection<Batch> p_ListBatches { get; set; }
    public CollectionViewSource CVS { get; set; }

    private string _p_sSelectedCreatedDate;
    public string p_sSelectedCreatedDate {
        get
        {
            return _p_sSelectedCreatedDate;
        }
        set
        {
            _p_sSelectedCreatedDate = value;
            ApplyFilter(!string.IsNullOrEmpty(_p_sSelectedCreatedDate) ? FilterField.CREATED_DATE : FilterField.NONE);
        }
    }

    public ScanBatchViewModel()
    {
        p_ListBatches = new ObservableCollection<Batch>();

        LoadBatches();
        CVS = new CollectionViewSource();
    }

    private void ApplyFilter(FilterField field)
    {
        switch (field)
        {
            case FilterField.CREATED_DATE:
                AddCreatedDateFilter();
                break;
            default:
                break;
        }
    }

    public void AddCreatedDateFilter()
    {
        // see Notes on Adding Filters:
        if (p_bCanRemoveCreatedDateFilter)
        {
            CVS.Filter -= new FilterEventHandler(FilterByCreatedDate);
            CVS.Filter += new FilterEventHandler(FilterByCreatedDate);
        }
        else
        {
            CVS.Filter += new FilterEventHandler(FilterByCreatedDate);
            p_bCanRemoveCreatedDateFilter = true;
        }
    }

    private void FilterByCreatedDate(object sender, FilterEventArgs e)
    {
        // see Notes on Filter Methods:
        var src = e.Item as Batch;
        if (src == null)
            e.Accepted = false;
        else if (string.Compare(p_sSelectedCreatedDate, src.Date) != 0)
            e.Accepted = false;   
    }
}
KeepCalmAndCode
  • 207
  • 2
  • 12

1 Answers1

0

CollectionViewSource.Filter is an event. It will be fired when the CollectionViewSource needs to filter the content. This occurs when the CollectionViewSource updates the view.

In order to update the view, call the corresponding method:

CVS.View.Refresh();

Keep in mind that your method AddCreatedDateFilter() could add multiple event handlers for the Filter event. Each event handler will be called for each item in the collection. This might cause a performance problem. And all the event handlers are the same, so this is useless too.

So ensure that you only add one event handler for this event.

dymanoid
  • 14,771
  • 4
  • 36
  • 64
  • Called CVS.View.Refresh();. CVS.View seems to be null and throwing an exception . But I am able to see the populated list in my front-end. – KeepCalmAndCode Jun 18 '18 at 09:36
  • I was able trigger the filter event FilterByCreatedDate(...) when I set the CVS.Source = p_ListBatches;. Now my problem is, in code where do I have to call the CVS.View.Refresh();. Since I am adding a filter on the property change of 'p_sSelectedCreatedDate', in the code sequence where can I call CVS.View.Refresh();? – KeepCalmAndCode Jun 20 '18 at 06:15
  • You have two instances of `CollectionViewSource` - the one is in the view created by XAML, the other is in the view-model. That is wrong. You only need one instance of that. Delete the one either in the view-model or in XAML. The `CVS.View.Refresh()` call depends on where `CVS` is stored. See [this question](https://stackoverflow.com/questions/20888619/proper-way-to-use-collectionviewsource-in-viewmodel/20899469) for more details. There you can also find an answer showing how to apply a custom filter. – dymanoid Jun 20 '18 at 08:07