Tango
Tango

Reputation: 396

C# - Delegates and BackgroundWorkers

I'm new to C# and object-oriented programming in general. I have an application which parses the text files.

By default, the program executes on the main thread and thus the application freezes until execution.

I have 5 void methods which take in a list of string as parameter.

Based on the various CheckBox options, these 5 void methods get executed in combinations.

The BackgroundWorker performs the operation on a different thread. Thus, the application does not freeze.

However, I would require 15+ BackgroundWorkers for every combination.

The following is my code:

public partial class Form1 : Form
{
    List<string> textFiles = new List<string>();

    public Form1()
    {
        InitializeComponent();
    }

    public void mParsing(List<string> textFiles) { /* parsing logic */ }
    public void iParsing(List<string> textFiles) { /* parsing logic */ }
    public void aParsing(List<string> textFiles) { /* parsing logic */ }
    public void qParsing(List<string> textFiles) { /* parsing logic */ }

    public void Summary()
    {
        // Logic to generate summary   
    }

    private void btnGo_Click(object sender, EventArgs e)
    {
        if (checkM.Checked == true && checkI.Checked == false && checkA.Checked == false && checkQ.Checked == false)
        {
            backgroundWorker1.RunWorkerAsync();
        }
        else if (checkM.Checked == true && checkI.Checked == true && checkA.Checked == false && checkQ.Checked == false)
        {
            backgroundWorker2.RunWorkerAsync();
        }            

        //So On....
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        mParsing(textFiles);
        Summary();
    }
    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        DialogResult dialogResult = MessageBox.Show("View Summary?", MessageBoxButtons.YesNo);
        if (dialogResult == DialogResult.Yes)
        {
            string summary = filepath;
            Process.Start("notepad.exe", summary);
        } 
    }
    private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
    {
        mParsing(textFiles);
        iParsing(textFiles);
        Summary();
    }
    private void backgroundWorker2_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        DialogResult dialogResult = MessageBox.Show("View Summary?", MessageBoxButtons.YesNo);
        if (dialogResult == DialogResult.Yes)
        {
            string summary = filepath;
            Process.Start("notepad.exe", summary);
        }
    }
}

The Func<> does not accept void datatype and I am having a bad time understanding the delegates and multi threading.

My problem is, I don't know how to avoid multiple background workers. Can this be implemented with help of delegates?

Update: .NET Framework Version: 4.0

Upvotes: 1

Views: 2000

Answers (2)

Tango
Tango

Reputation: 396

Coolerfarmer's answer works well with .NET 4.5.

However, Due to .NET 4.0 limitations, Managed to achieve asynchronous executions with help of threads & delegates

It may not be an efficient way of performing the combination execution of methods.

What I did was, created an individual method with execution order and used the following code:

 public partial class Form1 : Form
{
    List<string> textFiles = new List<string>();

    public Form1()
    {
        InitializeComponent();
    }

    public void mParsing(List<string> textFiles) { /* parsing logic */ }
    public void iParsing(List<string> textFiles) { /* parsing logic */ }
    public void aParsing(List<string> textFiles) { /* parsing logic */ }
    public void qParsing(List<string> textFiles) { /* parsing logic */ }

    public void Summary()
    {
        // Logic to generate summary   
    }

    private void btnGo_Click(object sender, EventArgs e)
    {
        if (checkM.Checked == true && checkI.Checked == false && checkA.Checked == false && checkQ.Checked == false)
        {
            Thread worker = new Thread(mOption);
                if (!worker.IsAlive)
                {

                    worker.Start();
                    frm.Show(); // Displaying Form - Performing Operation.. Please Wait... 
                    btn1.Enabled = false;
                }
        }
        else if (checkM.Checked == true && checkI.Checked == true && checkA.Checked == false && checkQ.Checked == false)
        {
            Thread worker = new Thread(miOption);
                if (!worker.IsAlive)
                {

                    worker.Start();
                    frm.Show(); // Displaying Form - Performing Operation.. Please Wait... 
                    btn1.Enabled = false;
                }
        }            

        //So On....
    }


        private void mOption()
        {
            mParsing(textFiles);
            Summary();

            MethodInvoker inv = delegate
            {
                frm.Hide();

        DialogResult dialogResult = MessageBox.Show("View Summary?", MessageBoxButtons.YesNo);
        if (dialogResult == DialogResult.Yes)
        {
            string summary = filepath;
            Process.Start("notepad.exe", summary);
        } 
                this.btn1.Enabled = true;

            };
            this.Invoke(inv);
        }

        private void miOption()
        {
            mParsing(textFiles);
            iParsing(textFiles);
            Summary();

            MethodInvoker inv = delegate
            {
                frm.Hide();

        DialogResult dialogResult = MessageBox.Show("View Summary?", MessageBoxButtons.YesNo);
        if (dialogResult == DialogResult.Yes)
        {
            string summary = filepath;
            Process.Start("notepad.exe", summary);
        } 
                this.btn1.Enabled = true;

            };
            this.Invoke(inv);
        }

}

Any inputs with explanation are most welcome and Thank you all for the inputs and suggestions.

Upvotes: 1

coolerfarmer
coolerfarmer

Reputation: 385

In C# there is async/await which is exactly what you need. Take this example:

private async void btnGo_Click(object sender, EventArgs e)
{
    if (checkM.Checked == true && checkI.Checked == false && checkA.Checked == false && checkQ.Checked == false)
    {
        await mParsing(textFiles);
        DialogResult dialogResult = MessageBox.Show("View Summary?", MessageBoxButtons.YesNo);
        if (dialogResult == DialogResult.Yes)
        {
            string summary = filepath;
            Process.Start("notepad.exe", summary);
        } 
    }
}

For this to work both functions, btnGo_Click and mParsing must have the keyword async in it's definition. In addition the return type of the parsing function must be changed to Task.

public async Task mParsing(List<string> textFiles)
{
    //Method containing parsing logic
}

Moreover you need some changes to your (now async) mParsing function. E.g. blocking calls like new WebClient().DownloadString(url) must be replaced with non blocking calls new WebClient().DownloadStringTaskAsync(url)

As there's not always a non blocking call available you can also use Task.Run():

public async Task mParsing(List<string> textFiles)
{
    await Task.Run(() => {
        //Do blocking calls
    });
}

Upvotes: 1

Related Questions