views:

2071

answers:

5

The BackgroundWorker object allows us to pass a single argument into the DoWorkEventHandler.

// setup/init:
BackgroundWorker endCallWorker = new BackgroundWorker();
endCallWorker.DoWork += new DoWorkEventHandler(EndCallWorker_DoWork);
...
endCallWorker.RunWorkerAsync(userName);

// the handler:
private void EndCallWorker_DoWork(object sender, DoWorkEventArgs e)
{
    string userName = e.Argument as string;
    ...
}

To pass multiple arguments, I must wrap them in an object, like this poor string array:

// setup/init:

BackgroundWorker startCallWorker = new BackgroundWorker();
startCallWorker.DoWork += new DoWorkEventHandler(StartCallWorker_DoWork);
...
startCallWorker.RunWorkerAsync(new string[]{userName, targetNumber});


// the handler:
private void StartCallWorker_DoWork(object sender, DoWorkEventArgs e)
{
    string[] args = e.Argument as string[];
    string userName = args[0];
    string targetNumber = args[1];
}

Is there another object or pattern that allows us pass multiple arguments nicely, or ideally, write our own signature?

A: 

Why not have the "one" object passed be an array of parameters? You only need to cast it back to array inside the method from the object parameter.

kek444
+12  A: 

You could use a closure (Lambda):

backgroundWorker.DoWork += (s, e) => MyWorkMethod(userName, targetNumber);

Or with delegate (anonymous method) syntax:

backgroundWorker.DoWork += 
    delegate(object sender, DoWorkEventArgs e)
    {
        MyWorkMethod(userName, targetNumber);
    };
Ben M
could you elaborate on how this works? (especially the "(s, e)"... why are they declared?)
Jeff Meatball Yang
I like this a lot - For my use case, it works great, but more complex apps might have issues, i.e. I need access to the parameter values (username and targetNumber) at setup/init.
Jeff Meatball Yang
Glad to help (and some more text).
Ben M
+2  A: 

Maybe pass a lambda function as your object? Then you'd call it in the DoWork handler.

endCallWorker.RunWorkerAsync(new Action( () => DelegatedCallTarget(userName, targetNumber) ));
280Z28
could you show me how I unwrap them in the handler?
Jeff Meatball Yang
+3  A: 

Object can be a list or array or some such. Just make your object a container of some sort, then cast within the BackgroundWorker. You need to make sure you're always passing in the same type though.

McAden
+McAden If the library designers handled two arguments, why not three, four, etc? The solution was to handle one, and that one can be an object of arbitrary complexity.
DougN
+3  A: 

What's wrong with using a typed object?

internal class UserArgs
{
    internal string UserName { get; set; }
    internal string TargetNumber { get; set; }
}

var args = new UserArgs() {UserName="Me", TargetNumber="123" };
startCallWorker.RunWorkerAsync(args);
Vijay Patel
This is nicer than my string[] array, but still - I don't want to declare another class just to pass arguments into my own function. This happens in a lot of other built-in handlers in .NET - I guess I am looking for a consistent pattern that doesn't pollute my code with useless wrapper classes.
Jeff Meatball Yang