Skip to content
This repository was archived by the owner on Sep 25, 2024. It is now read-only.

Commit 4a2adca

Browse files
author
Eric Maupin
committed
[core] Fix empty parents on filter changes
Fixes #522
1 parent 20394cf commit 4a2adca

File tree

2 files changed

+75
-10
lines changed

2 files changed

+75
-10
lines changed

Xamarin.PropertyEditing.Tests/SimpleCollectionViewTests.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,6 +756,50 @@ public void Indexer ()
756756
Assert.Throws<ArgumentOutOfRangeException> (() => view[2].ToString(), "this[] didn't throw out of range on filtered out item");
757757
}
758758

759+
[Test]
760+
[Description ("Covers #522, empty parents now unfiltered by their own filter shouldn't be added")]
761+
public void ParentFilterChangesOnEmpty ()
762+
{
763+
var parents = new ObservableCollection<TestNode> {
764+
new TestNode ("A") {
765+
Children = new List<TestNode> {
766+
new TestNode ("A child")
767+
}
768+
},
769+
new TestNode ("Baz") {
770+
Children = new List<TestNode> {
771+
new TestNode ("Baz child")
772+
}
773+
},
774+
new TestNode ("Bar") {
775+
Children = new List<TestNode> {
776+
new TestNode ("Bar child")
777+
}
778+
},
779+
};
780+
781+
var view = new SimpleCollectionView (parents, new SimpleCollectionViewOptions {
782+
DisplaySelector = TestNodeDisplaySelector,
783+
ChildrenSelector = TestNodeChildrenSelector,
784+
ChildOptions = new SimpleCollectionViewOptions {
785+
DisplaySelector = TestNodeDisplaySelector
786+
}
787+
});
788+
789+
Assume.That (view.Count, Is.EqualTo (3));
790+
791+
view.Options.Filter = o => ((TestNode) o).Key != "Bar";
792+
Assume.That (view.Count, Is.EqualTo (2));
793+
794+
view.Options.ChildOptions.Filter = o => ((TestNode) o).Key.StartsWith ("A");
795+
Assume.That (view.Count, Is.EqualTo (1));
796+
797+
view.Options.Filter = null;
798+
799+
Assert.That (((KeyValuePair<string, SimpleCollectionView>) view[0]).Key, Is.EqualTo (parents[0].Key));
800+
Assert.That (view.Count, Is.EqualTo (1));
801+
}
802+
759803
private IEnumerable TestNodeChildrenSelector (object o)
760804
{
761805
return ((TestNode)o).Children;

Xamarin.PropertyEditing/ViewModels/SimpleCollectionView.cs

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,6 @@ public object this[int index]
127127

128128
public bool HasChildElements => (this.filtered.Count > 0);
129129

130-
public bool IsFiltering => Options?.Filter != null;
131-
132130
public bool Contains (object value)
133131
{
134132
return IndexOf (value) != -1;
@@ -289,15 +287,19 @@ private string GetKey (object element)
289287

290288
private bool MatchesFilter (Element element)
291289
{
292-
if (!IsFiltering)
290+
if (!GetIsFiltering())
291+
return true;
292+
if (element.ChildrenView != null && !element.ChildrenView.HasChildElements)
293+
return false;
294+
if (Options.Filter == null)
293295
return true;
294296

295297
return Options.Filter (element.Item);
296298
}
297299

298300
private void FilterCore (bool notify = true, bool isPureSubset = false)
299301
{
300-
if (!IsFiltering) {
302+
if (!GetIsFiltering()) {
301303
if (this.arranged.Count == this.filtered.Count)
302304
return;
303305
}
@@ -312,8 +314,7 @@ private void FilterCore (bool notify = true, bool isPureSubset = false)
312314

313315
var toRemove = new List<string>();
314316
foreach (var kvp in this.filtered) {
315-
var childView = kvp.Value.ChildrenView;
316-
if ((childView != null && !childView.HasChildElements) || !MatchesFilter (kvp.Value)) {
317+
if (!MatchesFilter (kvp.Value)) {
317318
toRemove.Add (kvp.Key);
318319
}
319320
}
@@ -324,7 +325,7 @@ private void FilterCore (bool notify = true, bool isPureSubset = false)
324325
var toAdd = new List<string> (filteredOut.Count);
325326
foreach (string key in filteredOut) {
326327
Element e = this.arranged[key];
327-
if (!IsFiltering || Options.Filter (e.Item))
328+
if (MatchesFilter (e))
328329
toAdd.Add (key);
329330
}
330331
toAdd.Sort (Comparer);
@@ -435,8 +436,6 @@ private void Reset (bool notify = true)
435436
this.arranged.Clear();
436437
this.filtered.Clear();
437438

438-
bool filtering = IsFiltering;
439-
440439
foreach (var sourceItem in this.source.Cast<object>().Select (o => new { Item = o, Key = GetKey (o) }).OrderBy (e => e.Key, Comparer)) {
441440
Element e = new Element {
442441
Item = sourceItem.Item
@@ -453,7 +452,7 @@ private void Reset (bool notify = true)
453452
e.ChildrenView = new SimpleCollectionView (children, Options.ChildOptions, this, sourceItem.Key, sourceItem.Item);
454453
}
455454

456-
if (!filtering || this.options.Filter (e.Item))
455+
if (MatchesFilter (e))
457456
this.filtered.Add (sourceItem.Key, e);
458457
}
459458

@@ -499,5 +498,27 @@ private void OnCollectionChanged (NotifyCollectionChangedEventArgs e)
499498
}
500499
}
501500
}
501+
502+
private bool GetIsFiltering ()
503+
{
504+
// Generally our hierarchy is at max 3 levels deep, this can be cached if we find it problematic
505+
SimpleCollectionView parent = this;
506+
while (parent != null) {
507+
if (parent.Options?.Filter != null)
508+
return true;
509+
510+
parent = parent.parent;
511+
}
512+
513+
SimpleCollectionViewOptions childOptions = Options.ChildOptions;
514+
while (childOptions != null) {
515+
if (childOptions.Filter != null)
516+
return true;
517+
518+
childOptions = childOptions.ChildOptions;
519+
}
520+
521+
return false;
522+
}
502523
}
503524
}

0 commit comments

Comments
 (0)