Search code examples
c#parametersinvoke

passing parameters to delegate


I want to change the text in a textbox of a Windows Form with different error messages. These error messages are set to an output string using the same method, but i can't pass the string as a parameter.

Here's how i call a new backgroundworker to safely change the text in the textbox:

worker.DoWork += worker_DoWork;
worker.RunWorkerAsync(argument: error));

Then i try to invoke the call:

private void worker_DoWork(object sender, DoWorkEventArgs e)
    {

        string output = e.Argument.ToString();
        object[] par = new object[] { output };


        Delegate del = new DELEGATE(changeErrortext);

        this.Invoke(del,par);

    }

    private void changeErrorText()
    {

        textBoxError.Text = output.ToString();
    }

I think i've got to assign the output in the object to the one in the changeErrorText, but i don't really know how to do it.

I've tried different methods, but none have worked. I'm new to C#, so tell me if and where i've messed up.


Solution

  • Instantiate the necessary event handlers

    Place eventhandlers in the constructor of the form. For example:

    public Form1()
    {
        InitializeComponent(); // Standard initialization component method...
    
        backgroundWorker1.DoWork += backgroundWorker1_DoWork;
        backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
    }
    

    Using the DoWork AND the RunWorkerCompleted events

    The way you used 'worker.DoWork += worker_DoWork;' should be expanded with the "RunWorkerCompleted" event. The DoWork event for the operation and the RunWorkerCompleted to handle the completed operation. This event is also usefull when you want to use cancellation or exception handling. This also gets called automatically, so there is no need for a dedicated "changeErrorText"-method. Example code:

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
       label1.Text = e.Result.ToString();
    }
    

    You don't have to use a Delegate to pass parameters

    The parameters can be passed the way you wrote the RunWorkAsync. The only thing you might want to do is placing that method in a (click) event. For example:

    private void button1_Click(object sender, EventArgs e)
    {
       int value = 123; // example input
       backgroundWorker1.RunWorkerAsync(argument: value);
    }
    

    The full code doc:

    public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
    
                backgroundWorker1.DoWork += backgroundWorker1_DoWork;
                backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                int value = 123;
                backgroundWorker1.RunWorkerAsync(argument: value);
            }
    
            private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
            {
                string output = e.Argument.ToString();
    
                e.Result = output;
            }
    
            private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
            {
                label1.Text = e.Result.ToString();
            }
        }
    

    I hope i've helped you with the above explanations.

    Sources

    1. Sending Arguments To Background Worker?;
    2. https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.backgroundworker?view=netcore-3.1