lundi 30 mars 2009

Static event on ViewModel in MVVM : Helper that prevents Leak errors memory, and so more …

Abstract

Use static public event properties on ViewModel class for :

  • High level of API to mask the technical complexity of the problem
  • ensure communication between ViewModel and View part without leak memory AND with only one wired process on View part even if ViewModel contains lot of entities.
  • ensure communication between entities of ViewModel and ensure it in a graph of entities.
  • accept lot of quantity of ViewModel entities without overhead (memory or/and performance)
  • controls target’s type which is allowed to use on these events

Introduction

In MVVM architecture, I need create a graph of entities in ViewModel part with POCO objects. these entities must communicate with …

  • another instances of ViewModem
  • View part of the MVVM architecture

… without direct dependency between Sender to the targets : ViewModel has not dependency on "View Part" AND sometimes, entities of ViewModel  do not link directly all another entities of the model

A good technical approach to do this is used a static CLR Event on ViewModel class, static events are always accessibles even if ViewModel instance not yet exists

  • from another ViewModel class
  • from “View part“ of MVVM like a Window or UserControl.

BUT we need integrate these contraints :

  • a Simple static CLR Event keeps a reference on target’s instance : Garbage collector will never free target’s instance if this target will not remove its handler in the static CLR event.
  • If static CLR event is used by a lot of quantity of ViewModel instance. The performance must stay high.
  • If we create more than one instance of the ViewModel graph and use only static CLR Event : Each Invoke of static event must reach only the “good” instances of ViewModel (or View part) and not all referenced target.

“Good” instances seems only ViewModel entity that have relations with the invoker ViewModel OR View part that bind with ViewModel entity.

I proposed a main class : StaticEvent<> that can help us to do this !

How can I use it ?

Example of code to declare a new Event :

private static StaticEvent<MyEventArgs> _myEvent = 
  new  StaticEvent();
public static event EventHandler<MyEventArgs> MyEvent
{
  add
  {
    _myEvent.Add(value); 
  }
  remove
  {
    _myEvent.Remove(value);
  }
}

public static void OnMyEvent(MyEventArgs e)
{
  _myEvent.Invoke(e);
}

When developper uses the event : he works with it like a classic event with += / –= operator. The internal implementation is masked.

What can I wired on this type of Event ?

StaticEvent<> generic class is a base class to implement another type of it. In Diagram class below, and the prototype, I used a ModelViewEvent<>.

This event accepts 3 types of EventHandler :

  • EventHandler on a static method
  • EventHandler on an instance entity of ViewModel
  • EventHandler on an instance of FrameworkElement.

Entities of ViewModel must derivated from ViewModelBase<> class that implements required interface (IHandlersRepository)

The sequence of calls during “Invoke process”

The main concept is base on RoutedEvent of WPF framework. In the RoutedEvent design pattern : the “route” of calls is build BY the invoker !

I was reproduce the same approach in StaticEvent class !

If the invoker is a ViewModel Entity (supports IHandlersRepository), StaticEvent asks the invoker (by IHandlersRepository.GetHandlers) and invoker must give zero, one or more EventHandlers which will be called by StaticEvent.

So, ViewModelBase class visits each its owners and combines all handlers found during this visit.

 

 

For example, Demo application realize this sequence on an example graph

image

Using the approach of the RoutedEvent model of WPF FrameworkElement solves …

  • Communicate between ViewModel instances
  • have good performance event with a huge quantity of entities

I will use this approach in a MVVM Framework to send message between ViewModel instances : Example : When an ViewModel entity will be validated, and if this ViewModel is owned by another : It would be very useful that the owner ViewModel instance can stop or not the validation process of its own Son ViewModel instances !

I use it for Filter event of my own ICollectionView instance, very useful in this case !

With this approach, each instance of ViewModel (that supports IHandlerRepository) keeps references of its own EventHandler. So even if you have 1 000 000 instances of ViewModel object and just ONE static event that uses by this instances : Each instance keep one and only one EventHandler ! and moreover, StaticEvent is not a strong reference (by EventHandler) on these 1 000 000 ViewModel objects :  of course : it does not know these objects !!

Prevent against Leak memory issues : Using Life event cycle of FrameworkElement

Each FrameworkElement have Loaded, Unloaded and Initialize event. If you look inside the Demo, ViewEvent class creates an adapter on each FrameworkElement target. This adapter supports IHandlerRepository interface. This adapter is memorized by FrameworkElement instance (with an attached dependency property) and It uses these 3 events for accept or not a call process !

NB : WPF RoutedEvent mechanism used a roughly same approach to memorize EventHandlers (see System.Windows.UncommonField<T> internal class in WindowBase.dll and System.Windows.UIElement.AddHandler method :-)

TODO List …

  • Invoke’s strategy like Bubble, Direct, Tunnel strategy of RoutedEvent.

Class diagrams

  • StaticEvent class hierarchy : StaticEvent<> is the most important class : It have a dependancy on IHandlersRepository
      • by ProvideHandlersRepository method
      • if a handler’s target implements or not this interface (in Add(EventHandler) calls)
      • if a sender implements or not this interface (in Invoke calls)

Framework

  • ViewModel entity class hierarchy : Just a demo to use StaticEvent in ViewModel part of MVVM architecture : ViewModelEvent allows to wired a FrameworkElement instance without leak memory errors. It uses Loaded/UnLoaded event of FrameworkElement

Framework.Window

Download

Download v2.20 03/29/2009

References

previous article : http://thibaud60.blogspot.com/2009/03/helper-to-create-weak-event-with-strong.html