summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShane Neuville <shane94@hotmail.com>2017-03-24 12:58:28 -0600
committerJason Smith <jason.smith@xamarin.com>2017-03-24 11:58:28 -0700
commit377d24fd05e7fb597c4f9237c1596ed4fbf86f19 (patch)
tree9e7ddf6daf4a954d24d4087a0fde32baef30d776
parent63af84080454e7b108208b6e8e67bbf503e41209 (diff)
downloadxamarin-forms-377d24fd05e7fb597c4f9237c1596ed4fbf86f19.tar.gz
xamarin-forms-377d24fd05e7fb597c4f9237c1596ed4fbf86f19.tar.bz2
xamarin-forms-377d24fd05e7fb597c4f9237c1596ed4fbf86f19.zip
Setup a ConditionalWeakTable in ListProxy to hold weak references so that a ListView will work when connected to a Weak Source (#802)
-rw-r--r--Xamarin.Forms.Core.UnitTests/ListProxyTests.cs92
-rw-r--r--Xamarin.Forms.Core/ListProxy.cs12
2 files changed, 102 insertions, 2 deletions
diff --git a/Xamarin.Forms.Core.UnitTests/ListProxyTests.cs b/Xamarin.Forms.Core.UnitTests/ListProxyTests.cs
index 6fa85d2c..bf7f6eef 100644
--- a/Xamarin.Forms.Core.UnitTests/ListProxyTests.cs
+++ b/Xamarin.Forms.Core.UnitTests/ListProxyTests.cs
@@ -422,5 +422,97 @@ namespace Xamarin.Forms.Core.UnitTests
return Items.GetEnumerator ();
}
}
+
+ [Test]
+ public void WeakToWeak()
+ {
+ WeakCollectionChangedList list = new WeakCollectionChangedList();
+ var proxy = new ListProxy(list);
+
+ Assert.True(list.AddObject());
+
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ GC.Collect();
+
+ Assert.IsTrue(list.AddObject());
+
+ proxy = null;
+
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ GC.Collect();
+
+ Assert.IsFalse(list.AddObject());
+ }
+
+ public class WeakCollectionChangedList : List<object>, INotifyCollectionChanged
+ {
+ List<WeakHandler> handlers = new List<WeakHandler>();
+
+ public WeakCollectionChangedList()
+ {
+
+ }
+ public event NotifyCollectionChangedEventHandler CollectionChanged
+ {
+ add { handlers.Add(new WeakHandler(this, value)); }
+ remove { throw new NotImplementedException(); }
+ }
+
+
+ public bool AddObject()
+ {
+ bool invoked = false;
+ var me = new object();
+
+ foreach (var handler in handlers.ToList())
+ {
+ if (handler.IsActive)
+ {
+ invoked = true;
+ handler.Handler.DynamicInvoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, me));
+ }
+ else
+ {
+ handlers.Remove(handler);
+ }
+ }
+
+ return invoked;
+ }
+
+ class WeakHandler
+ {
+ WeakReference source;
+ WeakReference originalHandler;
+
+ public bool IsActive
+ {
+ get { return this.source != null && this.source.IsAlive && this.originalHandler != null && this.originalHandler.IsAlive; }
+ }
+
+ public NotifyCollectionChangedEventHandler Handler
+ {
+ get
+ {
+ if (this.originalHandler == null)
+ {
+ return default(NotifyCollectionChangedEventHandler);
+ }
+ else
+ {
+ return (NotifyCollectionChangedEventHandler)this.originalHandler.Target;
+ }
+ }
+ }
+
+ public WeakHandler(object source, NotifyCollectionChangedEventHandler originalHandler)
+ {
+ this.source = new WeakReference(source);
+ this.originalHandler = new WeakReference(originalHandler);
+ }
+ }
+ }
}
}
diff --git a/Xamarin.Forms.Core/ListProxy.cs b/Xamarin.Forms.Core/ListProxy.cs
index c2f5c9d8..b25da163 100644
--- a/Xamarin.Forms.Core/ListProxy.cs
+++ b/Xamarin.Forms.Core/ListProxy.cs
@@ -3,6 +3,7 @@ using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
+using System.Runtime.CompilerServices;
using Xamarin.Forms.Internals;
namespace Xamarin.Forms
@@ -12,6 +13,7 @@ namespace Xamarin.Forms
readonly ICollection _collection;
readonly IList _list;
readonly int _windowSize;
+ readonly ConditionalWeakTable<ListProxy, WeakNotifyProxy> _sourceToWeakHandlers;
IEnumerator _enumerator;
int _enumeratorIndex;
@@ -30,6 +32,7 @@ namespace Xamarin.Forms
ProxiedEnumerable = enumerable;
_collection = enumerable as ICollection;
+ _sourceToWeakHandlers = new ConditionalWeakTable<ListProxy, WeakNotifyProxy>();
if (_collection == null && enumerable is IReadOnlyCollection<object>)
_collection = new ReadOnlyListAdapter((IReadOnlyCollection<object>)enumerable);
@@ -40,7 +43,7 @@ namespace Xamarin.Forms
var changed = enumerable as INotifyCollectionChanged;
if (changed != null)
- new WeakNotifyProxy(this, changed);
+ _sourceToWeakHandlers.Add(this, new WeakNotifyProxy(this, changed));
}
public IEnumerable ProxiedEnumerable { get; }
@@ -362,10 +365,15 @@ namespace Xamarin.Forms
{
readonly WeakReference<INotifyCollectionChanged> _weakCollection;
readonly WeakReference<ListProxy> _weakProxy;
+ readonly ConditionalWeakTable<ListProxy, NotifyCollectionChangedEventHandler> _sourceToWeakHandlers;
public WeakNotifyProxy(ListProxy proxy, INotifyCollectionChanged incc)
{
- incc.CollectionChanged += OnCollectionChanged;
+ _sourceToWeakHandlers = new ConditionalWeakTable<ListProxy, NotifyCollectionChangedEventHandler>();
+ NotifyCollectionChangedEventHandler handler = new NotifyCollectionChangedEventHandler(OnCollectionChanged);
+
+ _sourceToWeakHandlers.Add(proxy, handler);
+ incc.CollectionChanged += handler;
_weakProxy = new WeakReference<ListProxy>(proxy);
_weakCollection = new WeakReference<INotifyCollectionChanged>(incc);