I'm using the code from Weak Events in .Net, the easy way to handle monitoring changes to an observable collection. The code has worked without any problems for months. I recently updated to a new computer. After getting everything setup and pulling down the code from my repository I encountered a strange problem. The code no longer works!
Here's the relevant portion of my code, it all takes place in the constructor:
public class PurchaseOrderReceipt : BaseEntity
{
/// <summary>
/// Initializes a new instance of the <see cref="PurchaseOrderReceipt" /> class.
/// </summary>
public PurchaseOrderReceipt()
{
this.ReceiptItems = new ObservableCollection<PurchaseOrderItemReceipt>();
this.DateReceived = DateTime.Now;
this.ReceiptItems.ObserveCollectionChanged()
.SubscribeWeakly(this, (target, eventArgs) => target.ReceiptItemsChanged());
}
The exception is thrown on the SubscribeWeakly line with the following error message: ArgumentException: onNext must refer to a static method, or else the subscription will still hold a strong reference to target
I can recreate the problem in LinqPad just by creating an instance of the PurchaseOrderReceipt.
Odder still if I write a simple class in LinqPad that mirrors the setup in the PurchaseOrderReceipt class than it works.
LinqPad code:
void Main()
{
var x = new Test();
x.ReceiptItems.Add(new PurchaseOrderItemReceipt());
}
public class Test:BaseEntity
{
public ObservableCollection<PurchaseOrderItemReceipt> ReceiptItems {get; set;}
public Test()
{
this.ReceiptItems = new ObservableCollection<PurchaseOrderItemReceipt>();
this.ReceiptItems.ObserveCollectionChanged().SubscribeWeakly(this,(target, eventargs) => target.TestChanged());
}
private void TestChanged()
{
"Changed!".Dump();
}
}
Changed! is printed out in the results window.
Here's the CustomReactiveExtension class from the link at the top.
public static class CustomReactiveExtension
{
public static IObservable<EventPattern<NotifyCollectionChangedEventArgs>> ObserveCollectionChanged(this INotifyCollectionChanged collection)
{
return Observable.FromEventPattern<NotifyCollectionChangedEventHandler, NotifyCollectionChangedEventArgs>(
handler => (sender, e) => handler(sender, e),
handler => collection.CollectionChanged += handler,
handler => collection.CollectionChanged -= handler);
}
public static IDisposable SubscribeWeakly<T, TTarget>(this IObservable<T> observable, TTarget target, Action<TTarget, T> onNext) where TTarget : class
{
var reference = new WeakReference(target);
if (onNext.Target != null)
{
throw new ArgumentException("onNext must refer to a static method, or else the subscription will still hold a strong reference to target");
}
IDisposable subscription = null;
subscription = observable.Subscribe(item =>
{
var currentTarget = reference.Target as TTarget;
if (currentTarget != null)
{
onNext(currentTarget, item);
}
else
{
subscription.Dispose();
}
});
return subscription;
}
}
Any ideas?