Paul Knopf
Paul Knopf

Reputation: 9786

Creating a thread to handle events for a particular class

I have a WPF application and I need to listen to, and handle events for the lifetime of the application for a certain class.

Is it bad practice to create a wrapper class, create a static instance of it and call "StartListening()"? What if an unhanded exception happens on this static instance? Will it tear down the entire application as it would in an ASP.NET application?

Should I QueueUserWorkItem, create the class, attach events, and then put some kind of while(true){} statement to keep the thread alive?

What is the best practice?

Upvotes: 1

Views: 106

Answers (1)

h.alex
h.alex

Reputation: 902

To me this seems like a classic publisher/listener problem.

I would create an interface: IMyClassNameEventListener and make MyClass take an instance of it as a constructor parameter. Then in the constructor I would call the Attach(MyClass obj) method on the interface instance. Of course, the listener would have a singleton lifecycle, it doesn't need to be static.

A slightly better approach would be to use a factory to create instances of MyClass which would then do the attaching, so the Attach call and the dependency are out of the constructor.

Wether the app would fail would be dependent on how you start the listener. You can look into the TaskFactory class, it provides options to handle exception propagation. How would you want the app to behave if the listener fails?

Of course in the listener object itself, you only need to have code run when there is something to handle. So, when you receive an event, you startup a thread. You can use a queue of actions if you'd want to have only one thread running.

Inside the listener class, you might want to have something like the following:

private Queue<Action> ActionQueue = new Queue<Action>();
private object LockObj = new Object();
private volatile bool IsRunning;

public void Attach(Class1 obj)
{
   obj.SomeEvent += this.HandleEvent;
}

private void HandleEvent(object sender, EventArgs e)
{
    lock(this.LockObj)
    {
        this.ActionQueue.Enque(() => this.Handle(sender, e));

        if (!this.IsRunning)
        {
           Task.Factory.StartNew(() => this.Loop() );
        }
    }
}

private void Loop()
{
    this.IsRunning = true;

    while ((Action action = this.DequeueAction()) != null)
        action();

    this.IsRunning = false;
}

private Action DequeueAction()
{
    lock (this.LockObj)
    {
        return this.ActionQueue.Count > 0 ? this.ActionQueue.Dequeue() : null;
    }
}

private void Handle(object sender, EventArgs e)
{
//handling code
}

Upvotes: 1

Related Questions