Composite WPF, Aggressive GC and dead events

by Christoph Menge in Software

Well, this is the first post after a very long pause, I am sorry but I had very little time…

Anyway, I stumbled over some strange bug this morning that turned out to be related to the GC. But let’s just step back a minute:

The application I currently work on is based on CompositeWPF . I added a very simple module to the application, a simple passive debugging module. I called it “InspectorModule”. The InspectorPresenter now listens for global modifications to the business object which is kept by the BusinessEntityManager:

public InspectorPresenter(IInspectorView _view,
            IEventAggregator _eventAggregator,
            IBusinessEntityManager _businessEntityManager)
{
    mView = _view;
    mEventAggregator = _eventAggregator;
    mBusinessEntityManager = _businessEntityManager;

    mEventAggregator.GetEvent<BusinessInstanceInvalidatedEvent>().Subscribe(ReloadInspector);
}

Now, upon each modification of the business object, ReloadInspector shall be called. So, starting the application and triggering the event — nothing happened. The ReloadInspector method is not being called. Why?

After some debugging, it suddenly worked – the only problem being: I didn’t actually change anything!

To make a long story, I realized the CompositeWPF DelegateReferenceclass keeps a WeakReference to the object (the InspectorPresenter, in this case) when registering it via the EventAggregator as above.

Unfortunately, due to the simplicity of the InspectorPresenter, no instantiated object actually keeps a reference to the Presenter (apart from the WeakReference of the event which, by definition, does not prevent it from being finalized).

That’s why the object is being finalized and the event never fires. Actually, on the first call of the associated Publish() method, the Composite WPF-Internal EventBase.PruneAndReturnStrategies() will remove it from the list after it’s associated Action is supposedly null.

Debugging this was quite cumbersome, and the solution of striking simplicity: I simply continued to develop the “Inspector”, a little more than I originally planned, so the user can now select an object in the inspector. Now, I have a simple event like this:

public InspectorPresenter(IInspectorView _view,
            IEventAggregator _eventAggregator,
            IBusinessEntityManager _businessEntityManager)
{
    // ...
    mView.SelectedNodeChanged += new OnSelectedNodeChanged(mView_SelectedNodeChanged);
    // ...
}

This keeps a (strong) reference to the Presenter, and the GC does not kill my presenter anymore! The reason it worked when debugging, I guess, is that the debugger will keep the GC from finalizing objects under certain circumstances.

Post to Twitter Post to Delicious Post to Digg Post to Facebook

No related posts.

Tags: , , ,

← Previous

Next →

1 Comment

  1. Steve says:

    A bit late but it still might come in handy:

    Make it a singleton, as in public static InspectorPresenter Instance = new InspectorPresenter() so that it will never be garbage collected.

Leave a Comment