Setup a ConditionalWeakTable in ListProxy to hold weak references so that a ListView will work when connected to a Weak Source (#802)
This commit is contained in:
Родитель
63af840804
Коммит
377d24fd05
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче