views:

243

answers:

1

Hi,

I was looking at Prism EventAggregator and its' great. I part i was most concerned was its capability to marshal thread correctly to UI thread.

I was wondering if i can use this capability to provide module developers a class which could be used to create threads in a similar way as BackgroundWorker. Interface of class can be somewhat similar to

public interface IMyTask
{
    event DoWorkEventHandler DoWork;
    event RunWorkerCompletedEventHandler RunWorkerCompleted;
    void RunTaskAsync(object obj);
}

I have kept types similar to backgroundworker for better understanding. In implementation i am registering taskstart and taskcomplete events

public class TaskStartEventPayload
{
    public SubscriptionToken token { get; set; }
    public object Argument { get; set; }
}

public class TaskStartEvent : CompositePresentationEvent<TaskStartEventPayload>
{
}

public class TaskCompleteEventPayload
{
    public SubscriptionToken token { get; set; }
    public object Argument { get; set; }
    public object Result { get; set; }
}
public class TaskCompleteEvent : CompositePresentationEvent<TaskCompleteEventPayload>
{
}

In the constructor for the MyTask class i take which thread the completion is required on as

 public MyTask(IEventAggregator eventAggregator, bool isUICompletion)
 {
       if (eventAggregator == null)
       {
                throw new ArgumentNullException("eventAggregator");
            }
            _eventAggregator = eventAggregator;
            _eventAggregator.GetEvent<TaskStartEvent>().Subscribe(TaskStartHandler, ThreadOption.BackgroundThread, false, new Predicate<TaskStartEventPayload>(StartTokenFilter));
            if(isUICompletion)
                _token = _eventAggregator.GetEvent<TaskCompleteEvent>().Subscribe(TaskCompleteHandler, ThreadOption.UIThread,true,new Predicate<TaskCompleteEventPayload>(CompleteTokenFilter));
            else
                _token = _eventAggregator.GetEvent<TaskCompleteEvent>().Subscribe(TaskCompleteHandler, ThreadOption.BackgroundThread, true, new Predicate<TaskCompleteEventPayload>(CompleteTokenFilter));
        }

here i am registering with filters where filter function returns the event only if it has Payload has same token as while got while subscribing.

further I use

 public void RunTaskAsync(object obj)
{
    //create payload
    _eventAggregator.GetEvent<TaskStartEvent>().Publish(payload);
}
public void TaskStartHandler(TaskStartEventPayload t)
{
     //fire dowork and create payload
     DoWork(this, args);
     _eventAggregator.GetEvent<TaskCompleteEvent>().Publish(tc);
}
public void TaskCompleteHandler(TaskCompleteEventPayload t)
{
    RunWorkerCompleted(this, args);
}

This class can be used as

        MyTask et = new MyTaskagg, true);
        et.DoWork += new System.ComponentModel.DoWorkEventHandler(et_DoWork);
        et.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(et_RunWorkerCompleted);            
        et.RunTaskAsync("Test");

Benefit I see in this approach is 1. It uses threadpool so no overhead of creating threads as in backgroundWorker. 2. Proper thread marshalling in case RunWorkerCompleted to be executed on UI thread.

Please advice if this would be correct to use eventaggregator as Threader.

A: 

This will work, although it's code you have to debug for very little performance gain. Micro-optimizing is rarely worth the effort and support costs in my opinion.

EventAggregator is meant to be a message bus for your application and I typically prefer to use things for their original intention, lest I have to debug a lot of code, but that's my personal preference.

Event Aggregator is going to have to work a little harder than it is meant to cleaning up all of those subscriptions, which will likely exceed any performance gain you get from the thread pooling, but that is just a guess.

Anderson Imes