I'm working on an application that has a main form with a status bar at the bottom. The status bar contains a ProgressBar, and a Label that I want to use to show the user the current progress of some work that is being done. The status bar also contains a label which I want to use like a click-able Cancel button.
I've create asynchronous interfaces before like this, but they have always been based around a single action, and by using a background worker. But in this new program there are a number of different actions the user may envoke all of which I want to use this same status bar to show the progress of. So I'm trying to figure out a way to generalize and standardize the interface to these progress reporting controls in the status bar.
In some cases the asynchronous processes are created using a BackGroundWorker, yet in other cases I need to create an manage the secondary threads directly.
Here's some half finished skeleton code of what I've been thinking:
public partial class MyForm: System.Windows.Forms.Form
{
...SNIP...
private void WorkProgressChanged(Object sender, EventArgs args)
{
ProgressChangedEventArgs backgroundWorkerArgs = args as ProgressChangedEventArgs;
ProgressReport formReport = args as ProgressReport; //my own custom progress report class
//tries to cast args to a Background worker args
if (backgroundWorkerArgs != null)
{
// update UI based on backgroundWorkerArgs
}
else if (formReport != null)
{
// update UI basd on formReport
}
else
{
//couldn't figure out what kind of progress report was sent
//update UI based on args.ToString();
}
}
private void cancelButtonToolStripLabel_Click(object sender, EventArgs e)
{
//calls cancel method of current processing
if (this._currentWorkCancelAction != null)
{
_currentWorkCancelAction(); //envoke cancel requet
cancelButtonToolStripLabel.Text = "Canceling"; //shows user that cancel request was made
_currentWorkCancelAction = null; //disaccociates cancel button to prevent user from canceling twice
}
}
private void WorkProcessCompleted(Object sender, EventArgs args)
{
//Reset cancel button
cancelButtonToolStripLabel.Text = "Cancel";
cancelButtonToolStripLabel.Visible = false;
//resets the status label and progress bar
statusToolStripLabel.Text = "";
toolStripProgressBar.Value = 0;
}
....SNIP
}
So the status bar is updated by subscribing `WorkProgressChanged(Object sender, EventArgs args) to some event ', and ultimately reset when 'WorkProcessCompleted(Object sender, EventArgs args)' is envoked by a completion even. My cancel label (button) also needs to be associated and later dissociated with a delegate method that will request that whatever work is currently being done is canceled.
So each time work is done a bunch of stuff needs to happen. Event subscriptions are added/remove, delegate references are changed etc.. etc.. So I started wondering if there was some way I could encapsulate all these actions in to one or two reusable methods rather then writing duplicate code for each action that may take place.
The InitWorkProcess()
method below shows how I am thinking this may work . Although I'm pretty sure this is not the right way to use the EventDescriptor class. I couldn't figure out any other way to reference an event as a method parameter. Maybe this isn't possible?
public void InitWorkProcess(EventDescriptor workProgressChangedEvent, EventDescriptor workCompletedEvent, System.Action requestCancel)
{
//subscribe to progress changed
workProgressChangedEvent.AddEventHandler(this, this.WorkProgressChanged);
this._workProgressChangedEvent = workProgressChangedEvent;
//subscribe to process completed
workCompletedEvent.AddEventHandler(this, this.WorkProcessCompleted);
this._workCompletedEvent = workCompletedEvent;
//enable cancel button
if (requestCancel != null)
{
cancelButtonToolStripLabel.Visible = true;
this._currentWorkCancelAction = requestCancel;
}
}
... and I'd change the WorkProgressComplete event handling method to unsubscribe the event relationships when the work is completed.
private void WorkProcessCompleted(Object sender, EventArgs args)
{
//Reset cancel button
cancelButtonToolStripLabel.Text = "Cancel";
cancelButtonToolStripLabel.Visible = false;
//resets the status label and progress bar
statusToolStripLabel.Text = "";
toolStripProgressBar.Value = 0;
//unsubscribes WorkProcessCompleted() and WorkProgressChanged() methods
this._workCompletedEvent.RemoveEventHandler(this, this._workCompletedEvent);
this._workCompletedEvent = null;
this._workProgressChangedEvent.RemoveEventHandler(this, this._workProgressChangedEvent);
this._workProgressChangedEvent = null;
}
Does anyone have any suggestions on how I should set this up? Should I just forget about the InitWorkProcess()
method and instead add/remove all the event/delegate relationships separately for each action? Or is there a better way entirely?