Reputation: 396
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
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
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