backgroundworker vs Event - c#

i am use my Winform application to send buffer of packet to my network card, my application show to progress via Progress Bar, if i choose to send all the buffer with out any delay between the packets my application stuck (become gray) and return to normal behaviour only after senging all the buffer (in case my buffer is very big, something like > 50,000 packets)
so how can i deal with such case ? maybee to change the backgroundworker who check all my class properties (number of packet send etc...) with event ?
listBoxFiles.SetSelected(0, true);
bgWoSingle = new BackgroundWorker();
bgWoSingle.WorkerReportsProgress = true;
bgWoSingle.ProgressChanged += new ProgressChangedEventHandler(bgW_ProgressChanged);
bgWoSingle.DoWork += new DoWorkEventHandler(
(s3, e3) =>
{
while (loopsCount < numberOfLoops && bContinuePlay && ifContinue)
{
for (int i = 0; (i < listBoxFiles.Items.Count) && bContinuePlay && ifContinue; i++)
{
this.Invoke((MethodInvoker)delegate
{
lbCurrentFileNum.Text = "(" + (i + 1) + "/" + listBoxFiles.Items.Count + "):";
});
string path = (string)listBoxFiles.Items[i];
pcap = new Pcap(path, playSpeed, isSync);
pcap._startTimer += new EventHandler(pcap_packetStartTimer);
pcap._stopTimer += new EventHandler(pcap__packetStopTimer);
pcap.evePacketProgress += new Pcap.dlgPacketProgress(
(progressCount) =>
{
pcap._fileSelectedIndex = i;
bgWoSingle.ReportProgress(progressCount, pcap);
});
if (selectedAdapter != null)
{
//play the file
bContinuePlay = pcap.playCapture(selectedAdapter._packetDevice); }
}
loopsCount++;
}
bgWoSingle.RunWorkerCompleted += new RunWorkerCompletedEventHandler(
(s3, e3) =>
{
}
);
bgWoSingle.RunWorkerAsync();
here i check the class properties (class name is pcap):
void bgW_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//check the properties and update the UI
labelPacketSent.Text = pcap._numberOfSendPackets.ToString("#,##0");
progressBar1.Value = e.ProgressPercentage;
}

You have to use BackGroundWorker for it. I am adding a small example for it.
private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
backgroundWorker.ReportProgress(80, 15000);
}
private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
var numberOfPackets = int.parse(e.UserState);
MessageBox.Show("Percentage: " + e.ProgressPercentage );
MessageBox.Show("Packets sent :" + numberOfPackets);
}
The worker can send the percentage of completion or any other data you want through UserState.

The idea is to have a PacketSender class which uses a BGWorker, and registers to it's Progress events, etc, and has a progress property or events of itself, to allow binding / listening.
Then, the PacketSender class will receive some big task to do, and will let it's BGWorker do it. Your BGWorker-Work method will be on a separate thread, and every time you call ReportProgress from within it, you will get it in your listening method in PacketSender in the main thread, and will be able to bubble it upwards to PacketSender.ProgressChanged listeners or change a ProgressChanged property of percents complete, etc.
The right way to do it would be getting the data for the task in the PacketSender ctor, and immediately start the BGWorker, to prevent having multiple tasks on the same PacketSender, or have a Start and Stop method which will check if the BGWorker is working, and will prevent multi-tasking a single PacketSender.

Its better to use BackgroundWorker here. It's new and better than defining custom events to update your progress bar. Check MSDN.

Related

Windows form UI freezing and unable to execute user action when too much data is coming in

Created a simple window form to receive and process data from serial port
also logging the data in textfile and displaying in the rich-text box.
For some reason, it is going into unresponsive state and not able to execute user action and freeze.
According to my understanding, earlier code was using two threads one UI and another one for data received event. Is this correct
But now as i am using background worker, it should create anther thread to process and append in the log and richtext box. Is this correct?
This is my first project in c# so pardon me if it is already answered somewhere else as i am unable to correlate this situation with the given answers and not able to implement them.
Is it a good idea to background worker if not then how can i solve this problem.
Thanks in advance.
Earlier the entire application was running on UI thread. Now i have tried to use background to create a new thread to store data receiving from serial port and processing inside that thread
//earlier code
void DataReceived_Event(object sender, SerialDataReceivedEventArgs e)
{
if (Port.IsOpen)
{
int bytes = Port.BytesToRead;
byte[] buffer = new byte[bytes];
Port.Read(buffer, 0, bytes);
receivedBytes.AddRange(buffer);
ProcessRecievedBytes(null);
}
}
//latest code with background worker
void DataReceived_Event(object sender, SerialDataReceivedEventArgs e)
{
if (Port.IsOpen)
{
int bytes = Port.BytesToRead;
byte[] buffer = new byte[bytes];
Port.Read(buffer, 0, bytes);
receivingBytes.AddRange(buffer);
if (!essentialBgWorker.IsBusy)
{
receivedBytes.AddRange(receivingBytes);
receivingBytes.Clear();
essentialBgWorker.RunWorkerAsync();
}
}
}
private void essentialBgWorker_DoWork(object sender, DoWorkEventArgs e)
{
foreach (byte hexByte in receivedBytes)
{
//color = Color.Gray;
if ((Config.Data.Serial_DisplayLevel == GLOBAL.HEX_LEVEL_NONE))
{
if ((hexByte == '\n') || ((hexByte >= 0x20) && (hexByte <= 0x7E)))
{
String tmpString = new String((char)hexByte, 1);
//essentialBgWorker.ReportProgress(0, tmpString);
//in here i am putting in the log file and appending in the richtext box
PreprocessAppend(tmpString, Color.Black, false);
}
}
}
process.ProcessData(receivedBytes);//in here i am processing the data
receivedBytes.Clear();
}
private void essentialBgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
string str = e.UserState.ToString();
logWriter.Write(str);
logWriter.Flush();
if (e.ProgressPercentage == 0)
{
AppendSerial(str, Color.Black, false);
}
else if (e.ProgressPercentage == 1)
{
AppendSerial(str, Color.Black, false);
}
}
SerialTab.SerialPort.AppendSerial += delegate (string data, Color txtColor, bool newLineCheck)
{
this.BeginInvoke((MethodInvoker)(delegate ()
{
if (newLineCheck && (serialTextBox.Text != "") && (serialTextBox.Text[serialTextBox.TextLength - 1] != '\r') && (serialTextBox.Text[serialTextBox.TextLength - 1] != '\n'))
{
data = "\n" + data;
}
AppendTextbox(serialTextBox, data, txtColor);
}));
};
void AppendTextbox(RichTextBox tb, string data, Color txtColor)
{
if (data == null)
{
return;
}
int start = tb.TextLength;
tb.AppendText(data);
int end = tb.TextLength;
// Textbox may transform chars, so (end-start) != text.Length
tb.Select(start, end - start);
tb.SelectionColor = txtColor;
//reset color to defaults
tb.SelectionLength = 0;
tb.SelectionColor = serialTextBox.ForeColor;
//move caret to bottom of page
ScrollToBottom(tb);
//ensure text buffer stays below 15000 characters
checkTextBoxLength(tb);
}
void checkTextBoxLength(RichTextBox box)
{
//ensure text buffer in text box gets too large
if (box.Text.Length > 15000)
{
box.ReadOnly = false;
box.SelectionStart = 0;
box.SelectionLength = box.TextLength - 10000;
box.SelectedText = "";
box.ReadOnly = true;
}
}
Don't access windows controls from any thread other than the one that created them. When using a BackgroundWorker:
add the backgroundworker to the form designer
set its ReportsProgress property to true
attach an event handler to DoWork and another to ProgressChanged
in the DoWork event, do your background work such as reading from the serial port. Any time you want to update a windows control, call the backgroundworker ReportProgress() method with an object argument for the user state that contains some data you want to use in the control
I tend to use the progress int to also specify something, such as running a switch statement to chose one of several text boxes to update
The background worker will correctly ensure the ProgressChanged event is executed by the UI thread, meaning you can update controls from within it
Looking at your code, it seems you were going along these lines because I can see a commented out ReportProgress call. Show the contents of your ProgressChanged event handler. Make absolutely sure the only time you ever access any windows control (read or write any property or call any method) is in ProgressChanged, NOT DoWork
Edit/Update
Now I can see more of your code, it looks like you've embarked on a path of making it all way too complicated. I'll make another answer
I see what you are trying to do and you kind of have the right idea, I think you are just having a threading issue. Do you have the code for your PreprocessAppend method? You probably need to use BeginInvoke in that function and that should fix your issue.
Personally, I don't think you need a backgroundworker, as the Serial DataReceived event is threaded. I would recommend what the other answer said and use ReadExisting as that will grab all the characters in the received buffer and you can determine what to do from there. Just be careful because the DataReceived event can fire whenever it determines is a good time, so you could only get a partial line back. If you go this route you'll have to build your string until you know you have the whole thing and then process it.
In my example below, I'm expecting a Line Feed as my terminator so I build a string until I have the whole line then I process it.
//private variables
private SerialPort sp;
private StringBuilder sb;
private char LF = (char)10;
//function to initialize all my objects
public void init_state_machine()
{
sp = new SerialPort(currentSettings.ComPort, currentSettings.BaudRate);
sp.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
sb = new StringBuilder();
sb.Clear();
}
private void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string currentLine = "";
string Data = sp.ReadExisting();
foreach (char c in Data)
{
if (c == LF)
{
sb.Append(c);
//because it's threaded its possible to enter this code while processing so we will
//clear our string building immediately
currentLine = sb.ToString();
sb.Clear();
//process your line here or whatever
processReceivedData(currentLine);
}
else
{
sb.Append(c);
}
}
}
//this is where you process the response. For a simple example I just append the string
//to our textbox, but you could do any computations in here.
private void processReceivedData(string s)
{
this.BeginInvoke((MethodInvoker)delegate
{
serialTextBox.Text += s;
});
}
I recommend you junk all of your existing code, and proceed with using something like this, derived from the example from MSDN
namespace WindowsFormsApp3
{
public partial class Form1 : Form
{
SerialPort mySerialPort = new SerialPort("COM1");
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
mySerialPort.BaudRate = 9600;
mySerialPort.Parity = Parity.None;
mySerialPort.StopBits = StopBits.One;
mySerialPort.DataBits = 8;
mySerialPort.Handshake = Handshake.None;
mySerialPort.RtsEnable = true;
mySerialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
mySerialPort.Open();
}
private void DataReceivedHandler(
object sender,
SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string indata = sp.ReadExisting();
textBox1.InvokeIfRequired(ctrl => ctrl.AppendText(indata));
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
mySerialPort.Close();
}
}
public static class ControlHelpers
{
public static void InvokeIfRequired<T>(this T control, Action<T> action) where T : ISynchronizeInvoke
{
if (control.InvokeRequired)
{
control.Invoke(new Action(() => action(control)), null);
}
else
{
action(control);
}
}
}
}
Your DataReceived handler is quite complex. The MSDN example uses a far simpler interface where it takes care internally of the reading and buffering etc with ReadExisting. You might want to attach to it and just keep appending the data you received into some kind of buffer (stringbuilder?), and regularly inspect the buffer to see if it contains a full message that you want to process

Application lags on each timer tick

I have an application that periodically pings a server to give you the latency of your connection. From what I have read the System.Timers.Timer is run on a separate thread from the UI.
public MainForm()
{
InitializeComponent();
_timer = new Timer();
_timer.Tick += new EventHandler(timer_Tick);
_timer.Interval = 1000;
_timer.Start();
}
I have a NotifyIcon with a ContextMenu that displays the result of this ping. however I noticed that the ContextMenu lags every time the timer ticks and I have no idea why.
EDIT: completely forgot to add the timer_tick function
var selectedServer = Properties.Settings.Default.SelectedServer;
PingReply reply;
switch (selectedServer)
{
case "NA":
reply = _pvpnetClient.Send("64.7.194.1");
break;
case "EUW":
reply = _pvpnetClient.Send("95.172.65.1");
break;
case "EUN":
reply = _pvpnetClient.Send("66.150.148.1");
break;
default:
reply = _pvpnetClient.Send("64.7.194.1");
break;
}
if (reply == null || reply.Status != IPStatus.Success) return;
var returnedPing = reply.RoundtripTime;
LoLPing.Text = #"Server: " + selectedServer + #" - Ping: " + reply.RoundtripTime + #"ms";
PingText.Text = #"Ping: " + reply.RoundtripTime + #"ms";
if (returnedPing < 120f)
{
LoLPing.Icon = Properties.Resources.GreenIcon;
}
else if (returnedPing > 120f && returnedPing < 200)
{
LoLPing.Icon = Properties.Resources.YellowIcon;
}
else
{
LoLPing.Icon = Properties.Resources.RedIcon;
}
http://msdn.microsoft.com/en-us/library/system.timers.timer(v=vs.100).aspx
"The server-based Timer is designed for use with worker threads in a multithreaded environment."
It doesn't automatically generate it's own thread. If it did generate it's own thread, you'd get an exception when trying to update your control without the use of Invoke or BeginInvoke.
I would do this with a BackgroundWorker object, who's DoWork handler contained a loop with a Thread.Sleep in it. Then do all the slow ping work there in the DoWork loop, and have one GUI function that takes returnedPing and does the icon update. Call this GUI function with Invoke to get the GUI actions back on the GUI thread.
class SlowOperation
{
BackgroundWorker m_worker;
void StartPolling()
{
m_worker = new BackgroundWorker();
m_worker.WorkerSupportsCancellation = true;
m_worker.WorkerReportsProgress = true;
m_worker.DoWork += m_worker_DoWork;
m_worker.ProgressChanged += m_worker_ProgressChanged;
}
void m_worker_DoWork(object sender, DoWorkEventArgs e)
{
while (!m_worker.CancellationPending)
{
int returnedPing = 0;
// Get my data
m_worker.ReportProgress(0, returnedPing);
Thread.Sleep(1000);
}
}
void m_worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
myForm.Invoke(myForm.UpdateMyPing((int)e.UserState));
}
}
It all depends on how long the Send method of _pvpnetClient takes to run.
You are running a System.Windows.Timer (I know because of the Tick event), so this method will be invoked on the main thread, and it will block all GUI updates until it is done. If you want to do the work on another thread, you could use the System.Timers.Timer object, but you would have to invoke back to the main thread to update the GUI elements.

progress bar and backgroundworker in C#

Currently I am working on a project which need to consume large amount data from web services,
There is service class sending input date to the server and get back the result,
due to it time consuming process, it is required to user combined progressbar and backgroundworker to show user the process percentage. I have browsing quite a few sample code on this topic, but still could not figure out the best way to do it. Would you please help,
My code is following,
private MyCollection[] callWebService(string[] Inputs, string method)
{
List<string> results = new List<string>();
string fiel dNames = ""; // todo - fix this if nothing left in loop
int sizeOfArray = 500;
for (int i = 0; i < Inputs.Length; i = i + sizeOfArray)
{
string[] outputRecords;
int errorCode;
string errorString;
string[] thisFiveHundred = createSubArray(Inputs, i, sizeOfArray);
iq.NameValuePair[] namevaluepairs = new iq.NameValuePair[0];
fieldNames = iqOfficeWebservice.BatchStan(method, thisFiveHundred, null, "", out outputRecords, out errorCode, out errorString);
results.AddRange(outputRecords);
}
results.ToArray();
IAddress[] formattedResults = convertStringsToInputs(fieldNames, results);
return formattedResults;
}
private void cmdButton_Click(object sender, EventArgs e)
{
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
worker.RunWorkerAsync();
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 0; i < 101; i++)
{
worker.ReportProgress(i);
System.Threading.Thread.Sleep(1000);
}
}
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
lblProgress.Text = ("Progress: " + e.ProgressPercentage.ToString() + "%");
}
Additional info can be found here.
Apart from the technical implementation in WPF or Winforms for example there is an essential aspect to consider.
Do you get feedback of the progress from the web services?
If not, you are likely not able to predict correctly the time the web service will need. This will depend on factors you cannot influence (like server load, network traffic, ...). In this case a progress bar is not recommended as it will give the user a weird experience.
Then you have options like displaying an text information that the request could take minutes and display a progress with an IsIndeterminate flag set (WPF) to show continuous progress feedback. A sandhour cursor is not an option as you are using a background thread.
An alternative is to break down the big request into smaller parts for which you can report progress.
I've just put together a variation of Adil's answer that encapsulates the work and updates, as well as properly detaching events and disposing of the worker. Please upvote Adil's answer if you upvote mine.
private void cmdButton_Click(object sender, EventArgs e)
{
var worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
DoWorkEventHandler doWork = (dws, dwe) =>
{
for (int i = 0; i < 101; i++)
{
worker.ReportProgress(i);
System.Threading.Thread.Sleep(100);
}
};
ProgressChangedEventHandler progressChanged = (pcs, pce) =>
{
lblProgress.Text = String.Format("Progress: {0}%", pce.ProgressPercentage);
};
RunWorkerCompletedEventHandler runWorkerCompleted = null;
runWorkerCompleted = (rwcs, rwce) =>
{
worker.DoWork -= doWork;
worker.ProgressChanged -= progressChanged;
worker.RunWorkerCompleted -= runWorkerCompleted;
worker.Dispose();
lblProgress.Text = "Done.";
};
worker.DoWork += doWork;
worker.ProgressChanged += progressChanged;
worker.RunWorkerCompleted += runWorkerCompleted;
worker.RunWorkerAsync();
}

WinForm Multithreading. Use backgroundWorker or not?

I have a simple app which fires of a series of data intensive tasks. I'm not very experienced with WinForms and I was wondering the best way to do this without locking the interface. Can backgroundWorker be re-used, or is there another way to do this?
Thanks
BackgroundWorker is a thread that also includes notification synchronization. For example, if you wanted to update your UI when the scan completes, a regular Thread cannot access the UI objects (only the UI thread can do that); so, BackgroundWorker provides a Completed event handler that runs on the UI thread when the operation completes.
for more info see: Walkthrough: Multithreading with the BackgroundWorker Component (MSDN)
and a simple sample code:
var worker = new System.ComponentModel.BackgroundWorker();
worker.DoWork += (sender,e) => Thread.Sleep(60000);
worker.RunWorkerCompleted += (sender,e) => MessageBox.Show("Hello there!");
worker.RunWorkerAsync();
backgroundWorker can be used.
its benefit - it allows you to update a progress bar and interact with UI controls. (WorkerReportsProgress)
Also it has a cancellation mechanism. (WorkerSupportsCancellation)
You can use BackgroundWorker for such requirements. Below is a sample which updates a label status based on percentage task [long running] completion. Also, there is a sample business class which sets some value and the value is set back to UI via ProgressChanged handler. DoWork is the place where you write your long running task logic. Copy-Paste the code below after adding a label and backgroundworker component on a Winforms app & give it a shot. You may debug across various handler [RunWorkerCompleted, ProgressChanged, DoWork] and have a look at InitWorker method. Notice the cancellation feature too.
using System.ComponentModel;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form3 : Form
{
private BackgroundWorker _worker;
BusinessClass _biz = new BusinessClass();
public Form3()
{
InitializeComponent();
InitWorker();
}
private void InitWorker()
{
if (_worker != null)
{
_worker.Dispose();
}
_worker = new BackgroundWorker
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
_worker.DoWork += DoWork;
_worker.RunWorkerCompleted += RunWorkerCompleted;
_worker.ProgressChanged += ProgressChanged;
_worker.RunWorkerAsync();
}
void DoWork(object sender, DoWorkEventArgs e)
{
int highestPercentageReached = 0;
if (_worker.CancellationPending)
{
e.Cancel = true;
}
else
{
double i = 0.0d;
int junk = 0;
for (i = 0; i <= 199990000; i++)
{
int result = _biz.MyFunction(junk);
junk++;
// Report progress as a percentage of the total task.
var percentComplete = (int)(i / 199990000 * 100);
if (percentComplete > highestPercentageReached)
{
highestPercentageReached = percentComplete;
// note I can pass the business class result also and display the same in the LABEL
_worker.ReportProgress(percentComplete, result);
_worker.CancelAsync();
}
}
}
}
void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
// Display some message to the user that task has been
// cancelled
}
else if (e.Error != null)
{
// Do something with the error
}
}
void ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label1.Text = string.Format("Result {0}: Percent {1}",e.UserState, e.ProgressPercentage);
}
}
public class BusinessClass
{
public int MyFunction(int input)
{
return input+10;
}
}
}
The background worker would be a good choice to start with
For more info look here
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

BackgroundWorker slow

i am developing a project (WPF) and i have a Datagrid the load more than 5000 records from the database so i used a BackgroundWorker to advice the user the data is loading but it is so slow , i need to wait almost 2 minutes to load the data from the database,instead if i don't use the BackgroundWorker i need to wait just 3 second to load the data in the Datagrid.
Here i write down the code snippet that i use for the BackgroundWorker :
private void RunWorker()
{
worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.WorkerSupportsCancellation = true;
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
worker.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
worker.RunWorkerAsync();
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker senderWorker = sender as BackgroundWorker;
dc = new DataClasses1DataContext();
var query = from c in dc.Contact_DDBB_Xavis
select
new
{
c.ContactID,
c.Continent,
c.Country,
c.City,
c.PostalCode,
c.CompanyName,
c.UserCreated,
c.DateCreated,
c.UserModified,
c.DateModified
};
if (query.Count() > 0)
{
for (int i = 0; i < query.Count(); i++)
{
int progressInPercent = (int)(((decimal)(i + 1) / (decimal)query.Count()) * 100);
worker.ReportProgress(progressInPercent, i);
System.Threading.Thread.Sleep(10);
e.Result = query.ToList();
}
}
if (senderWorker.CancellationPending)
{
e.Cancel = true;
}
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error == null)
{
this.dataGrid.DataContext = e.Result;
backGround.Visibility = Visibility.Collapsed;
duracel.Visibility = Visibility.Collapsed;
txtBackWORK.Visibility = Visibility.Collapsed;
}
}
private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
for (double i = 0.0; i < e.ProgressPercentage; i++)
{
duracel.pthFiller.Width = 0;
double max = 312;
max = (double)e.ProgressPercentage;
duracel.pthFiller.Width = e.ProgressPercentage * 3.12;
duracel.txtStatus.Text = e.ProgressPercentage + " %";
txtBackWORK.Text = String.Format("Loading " + e.ProgressPercentage + " %");
}
}
now i don't know if there is something wrong in my code so i ask you some advice to how load faster the data from database without wait so long time.
Thanks for your attention.
Have a good time.
Cheers
Each time you call query.Count(), you're running another SQL query.
You should call Count() once, and store it in a local variable.
Also, you should only call `ReportProgress if the progress actually changed. (There's no point in calling it 1,000 times)
Umm... you are calling System.Threading.Thread.Sleep() in your code, in a loop, which appears to be calling the query multiple times.
Your update code also seems to be needlessly looping from 0 to the current percentage... not sure why?
Get rid of the whole progress indicator block as it exists. You are iterating over every single record, pausing your thread, re-calling the query and assigning it to e.Result and generally incurring overhead 5,000 times after your data has already loaded. This is useless.
If the data loads in a matter of seconds, show a marquee progressbar on the UI thread and everyone will be happy.

Categories