0

Summary:

I'm creating a simple application for practice, where the user can maintain and query a collection of Things. On the UI are several TextBoxes and ComboBoxes with which they can filter the collection.

The three buttons I'm concerned with are [Filter], [Random], and [All]. [Filter] applies the current filter options. [Random] applies the current filter options (if any), and then only shows one random entry from the filtered results. [All], as expected, shows the unfiltered collection.

To fully understand the background for the question, I'll provide the relevant code.


Here is where anything having to do with the CollectionViewSource (or any relevant code I'm posting) gets declared:

//Members
private ObservableCollection<Thing> _myDataCollection;
private CollectionViewSource _CVS;
private Thing _randomThing;

//Properties
public ObservableCollection<Thing> MyDataCollection
{
    get { return _myDataCollection; }
    set
    {
        if (_myDataCollection!= value)
        {
            _myDataCollection= value;
            RaisePropertyChanged(() => MyDataCollection);
        }
    }
}
public CollectionViewSource CVS
{
    get { return _CVS; }
    set
    {
        if (_CVS != value)
        {
            _CVS = value;
            RaisePropertyChanged(() => CVS);
        }
    }
}
public ICollectionView CVSView
{
    get { return CVS.View; }
}

Here is where the CVS is initialized (in the window view-model's constructor). For now, the data collection is populated with a ton of random things (that's all that RandomizeData() does).

MyDataCollection = new ObservableCollection<Thing>();
RandomizeData();

CVS = new CollectionViewSource();
CVS.Source = MyDataCollection;

Here is the code for the [Filter] button's command:

//Clear any stale filter options and rebuild with the most current ones.
CVSView.Filter = null;
//IF THE FOLLOWING LINE IS UNCOMMENTED, THE ISSUE OCCURS.
//CVS.Filter -= new FilterEventHandler(SingleRandomFromCollectionFilter);
BuildCVSFilter();

The code for the [All] button literally just clears the filter:

CVSView.Filter = null;

The code for the [Random] button. I suspect the issue is coming from the handler added here.

//Clear any stale filter options and rebuild with the most current ones.
CVSView.Filter = null;
//IF THE FOLLOWING LINE IS UNCOMMENTED, THE ISSUE OCCURS.
//CVS.Filter -= new FilterEventHandler(SingleRandomFromCollectionFilter);
BuildCVSFilter();

//Only proceed if there are actually results in the filtered collection.
int resultsCount = CVSView.Cast<Thing>().Count();
if (resultsCount > 0)
{
    //Point to a random thing in the filtered collection.
    CVSView.MoveCurrentToPosition(random.Next(0, resultsCount));
    _randomThing = CVSView.CurrentItem as Thing;

    //Add another filter event that further constrains the collection to only contain the random thing.
    CVS.Filter += new FilterEventHandler(SingleRandomFromCollectionFilter);
}

And here is the code for that BuildCVSFilter() I've been calling. I use this so that I can use multiple filters concurrently. The "FilterOption" strings are properties that are bound to the values of the UI controls.

if (!string.IsNullOrEmpty(FilterOption1))
{
    CVS.Filter += new FilterEventHandler(Fitler1);
}
if (!string.IsNullOrEmpty(FilterOption2) && FilterOption2 != "ignore")
{
    CVS.Filter += new FilterEventHandler(Fitler2);
}
if (!string.IsNullOrEmpty(FilterOption3))
{
    CVS.Filter += new FilterEventHandler(Filter3);
}

Each filter that gets added this way only sets e.Accepted to false, if applicable, and leaves it alone if it's true.


Issue:

If I click on [Random] at all, it seems like the FilterEventHandler that gets added there does not go away. This makes it so that selecting [Filter] after [Random] won't work as expected, because it's only going to filter from the current collection of one thing. Additionally, selecting [Random] a second time seems to reuse the same random thing (instead of finding a new one). Interestingly enough, clicking [All] still works just fine. It shows everything.

When I go into those [Filter] and [Random] OnCommand methods and explicitly add a line to remove that SingleRandomFromCollectionFilter handler, everything works as expected.

Why would NameEntriesView.Filter = null; work to clear the filter on [All], but not on [Filter] or [Random]? Is there something about the CollectionViewSource and its implementation that I'm not fully understanding?

Torr
  • 81
  • 1
  • 3
  • 10
  • There is a similar issue reported at [link](http://stackoverflow.com/questions/12961268/how-do-you-apply-multiple-filter-functions-on-one-collection-view-source-one-af). jnosek provides a class with multi-filters, give it a try. In his words "The problem apply multiple filter event handlers, is that all the handlers are called and the CollectionViewSource does not take the individual results of e.Accepted into account. The result will always be the value of e.Accepted in the last event handler." – berXpert Jun 03 '14 at 20:15
  • This does provide me with an alternate way to set up my filtering (which I appreciate and will probably use - thank you), and it solves the issue more cleanly than the explicit removals I was using above. But out of curiosity (since I don't _think_ the link explained it), I'm still wondering _why_ that [Random] event handler manages to persist after the entire filter gets null-ified? – Torr Jun 03 '14 at 20:28

0 Answers0