ホーム > CodeMemo | MVVM | Silverlight | Windows Phone 7 | WPF > An implemention of WeakEvent pattern for WPF/Silverlight/Windows Phone

An implemention of WeakEvent pattern for WPF/Silverlight/Windows Phone

Using the Model-View-ViewModel pattern, you always need to keep your events clean when they are not used(Especially ViewModel to View Event).

In example, Suppose the object “Foo” handles an event, when you finished using the Foo and forgot to release the event handlers,
the event would keep grabbing references to the Foo. This means that a memory leak is occurred.

If you are not familar with Weak Event patterns, this page would be helpful:

 

Weak Event Patterns

http://msdn.microsoft.com/en-us/library/aa970850.aspx

 

The above standard implementation, however, is not available in Silverlight or Windows Phone.
In addition, this mechanism(WeakEventManager and IWeakEventListener) is too cumbersome.

In the rest of this post, I propose a new implemention of it. This can be used in WPF, Silverlight, and Windows Phone 7.
I think that this is simpler and more intuitive than traditional ones.

In fact, this code is used in the “Livet” MVVM Framework, powered by Japanese MVVMers.

Usage Example

WeakEventManager and IWeakEventListener are not used.

public class Program
{
    public static void Main(string[] args)
    {
        Program A = new Program();
 
        var oldR = new WeakReference(new ReceiverOld(A));
        var newR = new WeakReference(new ReceiverNew(A));
 
        A.RaiseTestEvent(); //First
 
        //Exec GC
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();
 
        A.RaiseTestEvent(); //Second
 
        //--Result --
        //
        // ReceiverOld Received !
        // ReceiverNew Received !
        // ReceiverOld Received !
        //
 
        Console.ReadLine();
    }
 
    private void RaiseTestEvent()
    {
        var handler = TestEvent;
        if (handler != null)
        {
            handler(this, new RoutedEventArgs());
        }
    }
 
    public event RoutedEventHandler TestEvent;
}
 
//Normal Event Receiver Class
public class ReceiverOld
{
    public ReceiverOld(Program b)
    {
        b.TestEvent += OnTestEvent;
    }
 
    void OnTestEvent(object sender, RoutedEventArgs e)
    {
        Console.WriteLine("ReceiverOld Received ! ");
    }
}
 
//Event Receiver Class With LivetWeakEventListener
public class ReceiverNew
{
    LivetWeakEventListener _listener;//strong reference of listener
 
    public ReceiverNew(Program b)
    {
        _listener = new LivetWeakEventListener(
            h = > new RoutedEventHandler(h),//h is EventHandler
            h = > b.TestEvent += h, //h is RoutedEventHandler
            h = > b.TestEvent -= h, //h is RoutedEventHandler
            OnTestEvent);
    }
 
    void OnTestEvent(object sender, System.Windows.RoutedEventArgs e)
    {
        Console.WriteLine("ReceiverNew Received ! ");
    }
}

Source

Inspired by Observable.FromEvent Method Signature in ReactiveExtensions(Rx).

public class LivetWeakEventListener : IDisposable where TEventArgs : EventArgs
{
    private bool _disposed = false;
 
    private EventHandler _handler;
    private THandler _resultHandler;
    private Action _remove;
 
    private static void ReceiveEvent(WeakReference listenerWeakReference, object sender, TEventArgs args)
    {
        var listener = listenerWeakReference.Target as LivetWeakEventListener;
 
        if (listener != null)
        {
            var handler = listener._handler;
 
            if (handler != null)
            {
                handler(sender, args);
            }
        }
    }
 
    private static THandler GetStaticHandler(WeakReference listenerWeakReference, Func, THandler> conversion)
    {
        return conversion((sender, e) = > ReceiveEvent(listenerWeakReference, sender, e));
    }
 
    public LivetWeakEventListener(Func, THandler> conversion, Action add, Action remove, EventHandler handler)
    {
        if (conversion == null) throw new ArgumentNullException("conversion");
        if (add == null) throw new ArgumentNullException("add");
        if (remove == null) throw new ArgumentNullException("remove");
        if (handler == null) throw new ArgumentNullException("handler");
 
        _handler = handler;
        _remove = remove;
 
        _resultHandler = GetStaticHandler(new WeakReference(this), conversion);
 
        add(_resultHandler);
    }
 
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
 
    protected virtual void Dispose(bool disposing)
    {
        if (_disposed) return;
 
        if (disposing)
        {
            _remove(_resultHandler);
        }
        _disposed = true;
    }
}

If you have any problems, suggestions, or improvements on this code, feel free to leave a comment here.

Full source in ideone.com

このエントリーをはてなブックマークに追加

コメント:0

コメントフォーム
入力した情報を記憶する

トラックバック:0

この記事のトラックバック URL
http://ugaya40.net/codememo/an-implemention-of-weakevent-pattern-for-wpfsilverlightwindows-phone.html/trackback
トラックバックの送信元リスト
An implemention of WeakEvent pattern for WPF/Silverlight/Windows Phone - the sea of fertility より

ホーム > CodeMemo | MVVM | Silverlight | Windows Phone 7 | WPF > An implemention of WeakEvent pattern for WPF/Silverlight/Windows Phone

検索
フィード
メタ情報

ページの上部に戻る