How to use Background worker with windows forms c# app?

A

Anjan Bhowmik

Hi,
I need to develop a c# forms application. My application will do these
steps ---

1) It will read a list of user entries from SQL server 2005 Database.

2) For each user it will generate some content & send it to him/her via
email

3) For each operation it will generate lines of information to be
displayed in a textbox & then be saved to a log file. It will also
show a progress bar manipulated by entries processed/Total entries.

Now i want to use the background worker class to use Threading so that my
form remains responsive while doing this heavy work .

Now my problem is, I can not show lines of texts as each entry gets
processed. At some point it just stops. The work finishes but i dont see any
text entry in the text box as i expected.

How can i configure it so that i can view lines of informtion while every
entry is processing, so that the operator monitoring can take immediate
action based on that? Plz help! My mind is completely blank!!!

Thnx in advance.
 
P

Peter Duniho

[...]
Now i want to use the background worker class to use Threading so that
my form remains responsive while doing this heavy work .

A good idea.
Now my problem is, I can not show lines of texts as each entry gets
processed. At some point it just stops. The work finishes but i dont see
any text entry in the text box as i expected.

What have you tried? What made you believe it would work?

Without knowing what code you've written so far, it's really not possible
to advise you regarding how to fix it.

Pete
 
A

Anjan Bhowmik

Sorry for the delay, below is the complete code for the form containing
background worker. It stops right after printing 12 lines :( plz help.

------------------------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
using Premium_service_manager.TenderDigestTableAdapters;
using System.Threading;
using System.IO;
using System.Xml;
using System.Data.SqlClient;

namespace Premium_service_manager
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();


}

delegate void SetTextCallBack(String text);

private void SetText(String text)
{
if (this.richTextBox1.InvokeRequired)
{
SetTextCallBack d = new SetTextCallBack(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.richTextBox1.AppendText(text);
}
}

public String ConStr()
{
SqlConnectionStringBuilder scsb = new SqlConnectionStringBuilder();

scsb.DataSource = Properties.Settings.Default.SqlServerName;
scsb.UserID = Properties.Settings.Default.SqlServerUserName;
scsb.Password = Properties.Settings.Default.SqlServerPassword;
scsb.InitialCatalog =
Properties.Settings.Default.SqlServerDefaultDatabase;

return scsb.ConnectionString;
}


private void cancelSendingToolStripMenuItem_Click(object sender,
EventArgs e)
{

}

private void tendersPagesFolderToolStripMenuItem_Click(object sender,
EventArgs e)
{
FolderSettings fs = new FolderSettings();
fs.ShowDialog(this);
}


private void sendEmailsToolStripMenuItem_Click(object sender, EventArgs
e)
{
PremiumServices ps = new PremiumServices();

TenderDigest.PremiumServicesDataTable psTable = ps.GetAll();

this.backgroundWorker1.RunWorkerAsync(psTable);

this.cancelSendingToolStripMenuItem.Enabled = true;

this.sendEmailsToolStripMenuItem.Enabled = false;

this.richTextBox1.Text = "";
}

public static String res;

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
TenderDigest.PremiumServicesDataTable psTable = e.Argument as
TenderDigest.PremiumServicesDataTable;

BackgroundWorker bw = sender as BackgroundWorker;

if (psTable.Count <= 0)
{
this.AppendText("No premium subscriber entry found.");
this.AppendText("So, aborting ...");
this.AppendText("----------------------------------------------------------------------------------------------------------------------------------");
//bw.ReportProgress(1);
return;
}
else
{
this.AppendText("Premium subscribers found : " +
psTable.Count.ToString());
this.AppendText("Starting process . . .");
this.AppendText("----------------------------------------------------------------------------------------------------------------------------------");
//bw.ReportProgress(1);
}

for (int i = 0; i < psTable.Count; i++)
{

TenderDigest.PremiumServicesRow psRow = psTable;

this.AppendText("Premium subscriber ID: " +
psRow.PremiumServiceID.ToString());

this.AppendText("User ID: " + psRow.UserID.ToString());

this.AppendText("User Name: \"" + psRow.UserName + "\"");

if (psRow.ServiceType.Equals("Newsletter"))
{
this.ProcessPremiumSeviceEntry(psRow);
}
else
{
this.AppendText("This user has a subscription of type: " +
psRow.ServiceType);
this.AppendText("So, skipping ...");

}

this.AppendText("----------------------------------------------------------------------------------------------------------------------------------");

//bw.ReportProgress(1);

}

this.AppendText("Ending process . . .");
}

private void ProcessPremiumSeviceEntry(TenderDigest.PremiumServicesRow
psRow)
{
PremiumServiceCriterias psc = new PremiumServiceCriterias();
TenderDigest.PremiumServiceCriteriasDataTable pscTable =
psc.GetCriteriasByPremiumServiceID(psRow.PremiumServiceID);

if (pscTable.Count <= 0)
{
this.AppendText("This entry has no criteria defined !!!");
this.AppendText("Please check it out.");
return;
}
else
{
this.AppendText("This entry has criterias: " +
pscTable.Count.ToString());

TenderFormats tf = new TenderFormats();

TenderDigest.FormatsDataTable fdTable = tf.GetByID(psRow.FormatID);

#region Check for the format file

this.AppendText("Tender formats for this entry: " + fdTable[0].Name);

String format_file_path = fdTable[0].FilePath.Replace("~",
Properties.Settings.Default.TemplatesFolder).Replace("/", "\\");

this.AppendText("Format file: " + format_file_path);

this.AppendText("Looking for the format file ...");


if (File.Exists(format_file_path))
{
FileInfo fi = new FileInfo(format_file_path);

this.AppendText("Found format file. File size: " + fi.Length + "
bytes");


}
else
{
this.AppendText("Format file not found !!!");
return;
}
#endregion



#region Check for Tenders pages Dir

String tendersPagesFolder =
Properties.Settings.Default.TendersPagesFolder;
DirectoryInfo pagesDir = new DirectoryInfo(tendersPagesFolder);

if (!pagesDir.Exists)
{
pagesDir.Create();
}
#endregion

#region Create date directory with "selected date" inside pages dir
DirectoryInfo dateDir = new DirectoryInfo(pagesDir.FullName +
this.dateTimePicker1.Value.ToString("dd-MMM-yyyy"));

if (!dateDir.Exists)
{
dateDir.Create();
}
#endregion

#region Create user name dir
DirectoryInfo userNameDir = new DirectoryInfo(dateDir.FullName + "\\"
+ psRow.UserName);

if (!userNameDir.Exists)
userNameDir.Create();
#endregion

String tenderFilePath = userNameDir + "\\" + "tenders" +
psRow.PremiumServiceID.ToString() + ".htm";

if(!File.Exists(tenderFilePath))
{
File.CreateText(tenderFilePath);
}


for (int i = 0; i < pscTable.Count; i++)
{
TenderDigest.PremiumServiceCriteriasRow pscRow = pscTable;

if (pscRow.type == 1)
{
KeywordsList kl = new KeywordsList();

int keyID = -1;

if (Int32.TryParse(pscRow.value, out keyID) && (keyID > 0))
{
this.AppendText("Criteria type: \"Keyword\" with value = \"" +
kl.GetNameByID(Convert.ToInt32(pscRow.value)) + "\"");

this.ProcessKeyWord(keyID, this.dateTimePicker1.Value,
psRow.PremiumServiceID);

}


}
}
}
}

private String ProcessKeyWord(int keyID,DateTime date,int
PremiumServiceID)
{


String conStr =
System.Configuration.ConfigurationManager.ConnectionStrings["tenderdigestConnectionString"].ConnectionString;

if (!String.IsNullOrEmpty(conStr))
{
DataSet ds = new DataSet();
SqlConnection con = new SqlConnection(conStr);

con.Open();

SqlCommand cmd = new
SqlCommand("CompleteTendersForPremiumService_ByKeyword", con);
cmd.CommandTimeout = 60;
cmd.CommandType = CommandType.StoredProcedure;



SqlDataAdapter adp = new SqlDataAdapter();

adp.Fill(ds);

if (ds.Tables.Count <= 0)
{
this.AppendText("Dataset returned no tables !!!");
this.AppendText("Aborting . . .");
}
else if (ds.Tables.Count >= 3)
{
#region NO tender found, so get back
if (ds.Tables[0].Rows.Count <= 0)
{
this.AppendText("No tender entry found for this keyword for date: "
+ date.ToString("dd-MMM-yyyy"));
this.AppendText("Aborting . . .");
return "";
}
#endregion


}
}
else
{
this.AppendText("Connection string not found!!!");
this.AppendText("Aborting . . .");
return "";
}

this.AppendText("----------------------------------------------------------------------------------------------------------------------------------");

return "";
}

private void AppendText(String text)
{
this.richTextBox1.AppendText(DateTime.Now.ToString("[dd-MMM-yyyy
hh:mm:ss tt]") + " " + text + "\r\n");
}

private void backgroundWorker1_ProgressChanged(object sender,
ProgressChangedEventArgs e)
{
this.richTextBox1.AppendText(res);
}

private void backgroundWorker1_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
this.cancelSendingToolStripMenuItem.Enabled = false;

this.sendEmailsToolStripMenuItem.Enabled = true;
}

private void settingsToolStripMenuItem_Click(object sender, EventArgs e)
{

String exePath = Application.ExecutablePath;

String exeName = exePath.Substring(exePath.LastIndexOf('\\') +
1,exePath.Length - exePath.LastIndexOf('\\') -1);

String configName = exeName + ".config";

if (File.Exists(configName))
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(configName);

XmlNodeList nodes = xmlDoc.GetElementsByTagName("connectionStrings");
}

SqlServerSettings sss = new SqlServerSettings();

sss.ShowDialog(this);
}
}
}

Peter Duniho said:
[...]
Now i want to use the background worker class to use Threading so that
my form remains responsive while doing this heavy work .

A good idea.
Now my problem is, I can not show lines of texts as each entry gets
processed. At some point it just stops. The work finishes but i dont see
any text entry in the text box as i expected.

What have you tried? What made you believe it would work?

Without knowing what code you've written so far, it's really not possible
to advise you regarding how to fix it.

Pete
 
P

Peter Duniho

Sorry for the delay, below is the complete code for the form containing
background worker. It stops right after printing 12 lines :( plz help.

Sorry, I should have been more specific. If you are going to post code,
the code should be _concise_ as well as complete. It appears that the
code you posted is complete, but it contains far too much "other stuff".
You need to pare the code example down to the bare minimum required in
order to reproduce the issue you're seeing.

Pete
 
A

Anjan Bhowmik

As I am using BackgroundWorker, I am doing such tasks in the DoWork method -

I found the problem! The process halts when a Exception occurs in the
background worker thread and not handled.

My question is why should i not access UI items in DoWork method?
 
P

Peter Duniho

As I am using BackgroundWorker, I am doing such tasks in the DoWork
method -

I found the problem! The process halts when a Exception occurs in the
background worker thread and not handled.

That makes sense. Exceptions that occur in a thread pool thread simply
cause that thread's task to be stopped and the thread returned to the pool.
My question is why should i not access UI items in DoWork method?

Because the .NET Forms controls don't support it. I can't answer the
exact "why", since .NET _could_ have been designed without this
limitation. But it does relate to thread safety and presumably was a
design decision on the part of the .NET implementors intended to trade off
simplicity in one area for simplicity in another. It's fairly common for
a GUI API to require all GUI interaction to occur on a specific thread.

In code in your DoWork event handler, or any code that is executed in the
same thread, you need to use Control.Invoke() or Control.BeginInvoke() to
execute code that will access any UI object.

This is, in fact, documented in the BackgroundWorker class.

Pete
 
G

Gopal

That makes sense.  Exceptions that occur in a thread pool thread simply  
cause that thread's task to be stopped and the thread returned to the pool..


Because the .NET Forms controls don't support it.  I can't answer the  
exact "why", since .NET _could_ have been designed without this  
limitation.  But it does relate to thread safety and presumably was a  
design decision on the part of the .NET implementors intended to trade off 
simplicity in one area for simplicity in another.  It's fairly common for  
a GUI API to require all GUI interaction to occur on a specific thread.

In code in your DoWork event handler, or any code that is executed in the  
same thread, you need to use Control.Invoke() or Control.BeginInvoke() to  
execute code that will access any UI object.

This is, in fact, documented in the BackgroundWorker class.

Pete


Anjan,

try to update your form properties in backgroundWorker_ProgressChanged
event rather than in backgroundWorker_DoWork event. In my case, it
really worked well.

Please let me know incase of any question.

Thanks,
Gopal
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top