To get used to and get trained using Backgroundworker for my Project, i used a sample code which runs smoothly except when it comes to handling error condition it doesn't allow me to use (e.Error!=null) facility of RunWorkerCompletedEventArgs e.I want to handle error like the way cancel and successful completion works for me.
Suggestions please!
Following is the code:
private void DoWork(object sender, DoWorkEventArgs e)
{
Random rand = new Random();
for (int i = 0; i < 10; i++)
{
if (this.backgroundWorker.CancellationPending)
{
e.Cancel = true;
break;
}
// report progress
this.backgroundWorker.ReportProgress(-1, string.Format("Performing step {0}...", i + 1));
// simulate operation step
System.Threading.Thread.Sleep(rand.Next(1000, 10000));
//setting simulateError to true after inducing error(a button)
if (this.simulateError)
{
this.simulateError = false;
//needs a code to use (e.Error!=null) in
RunWorkerCompleted().
//A jump to RunWorkerCompleted is required here.
}
}
}
private void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// hide animation
this.pictureBox.Image = null;
// show result indication
if (e.Cancelled)
{
////works nice
this.labelProgress.Text = "Operation cancelled by the user!";
this.pictureBox.Image = Properties.Resources.WarningImage;
}
else
{
//doesn't execute at all....why?
if (e.Error != null)
{
this.labelProgress.Text = "Operation failed: " + e.Error.Message;
this.pictureBox.Image = Properties.Resources.ErrorImage;
}
else
{
//works nice
this.labelProgress.Text = "Operation finished successfuly!";
this.pictureBox.Image = Properties.Resources.InformationImage;
}
}
// restore button states
this.buttonStart.Enabled = true;
this.buttonCancel.Enabled = false;
this.buttonError.Enabled = false;
}
I induce error using simulateError ,for the purpose to show peculiar error message how should i use
if (e.Error != null)
{
this.labelProgress.Text = "Operation failed: " + e.Error.Message;
My Program isn't coming to private void RunWorkerCompleted(object sender, ,RunWorkerCompletedEventArgs e) in case of error. In other cases(cancellation,succesful completion) it executes right.
To get used to and get trained using Backgroundworker for my Project
Why would you do that? Task.Run() is better than BackgroundWorker in every way.
Now to your actual question: to cause an error in a BackgroundWorker, use the standard mechanism for that in .Net: exceptions:
if (this.simulateError)
{
this.simulateError = false;
throw new Exception("Simulating error.");
}
Related
i am new in C# so please be patient with me .
i want to make progress bar work with any functions i make in my program
i have class to check if INTERNET available and the connection of database status
and i have "progressBar1" , style is "Marquee"
i just want to indicate that there is a process work "Function" in the program and i don't need to have step or timer to increment it
just make the progress work until the function finish its code and the functions will work in button event (when i push button)
this is my code
class checkInternet
{
[DllImport("wininet.dll")]
private extern static bool InternetGetConnectedState(out int Description, int ReservedValue);
public bool checkInternetAvailable()
{
int Desc;
bool result = false;
if (InternetGetConnectedState(out Desc, 0) == true)
{
try
{
dbConnection StartConn = new dbConnection();
SqlConnection MyConnetion = StartConn.GetConnection();
MyConnetion.Open();
if (MyConnetion.State == ConnectionState.Open)
{
result = true;
}
MyConnetion.Close();
}
catch (Exception)
{
result = false;
MessageBox.Show("The database connection does not available, May be because of this reasons: \n\n1- there is a new version of the program avalible. \n2- database has some maintenance. \n\n Please check later :)", "Conection status");
}
}
else
{
result = false;
MessageBox.Show("No internet connection avalible , Please check later :) \nThanks.", "Conection status");
}
return result;
}
}
and this is what i have in my button event
private void button1_Click(object sender, EventArgs e)
{
checkInternet check = new checkInternet();
progressBar1.Value = 0;
do
{
progressBar1.PerformStep();
} while (check.checkInternetAvailable());
}
how can i implement that ?
thanks
As I understand you want user to see progressbar while your check connection task executes in background. checkInternetAvailable would be your background operation and I wouldn't suggest showing messages directly form it. Instead return a custom struct :
public struct ConnectionCheckResult
{
public bool Success;
public string Message;
}
And this will be your button click event handler :
private void button1_Click(object sender, EventArgs e)
{
progressBar1.Style = ProgressBarStyle.Marquee;
progressBar1.Visible = true;
//add code here to be executed on UI thread before connection check
Task.Run(new Action(() =>
{
//Task.Run this code on the thread pool instead of your UI thread. So your code is checking connection while progress bar is still rendering
ConnectionCheckResult res = new checkInternet().checkInternetAvailable();
this.Invoke(new Action(() =>
{
//this.Invoke executes following delegate on UI thread. All UI changes - like progressBar1.Visible = false; need to be made in UI thread.
//add code here to be executed on the UI thread after connection check.
progressBar1.Visible = false;
if (!string.IsNullOrEmpty(res.Message))
MessageBox.Show(res.Message);
}));
}));
//add code to be executed on UI thread at the same time as connection check
}
I know multi-threading is difficult to wrap your head around at first, here's good tutorial with code samples.
Also when your progressbar style is Marquee you don't need to call PerformStep. It will just roll by itself.
EDIT: You should also modify checkInternetAvailable() like so :
public ConnectionCheckResult checkInternetAvailable()
{
int Desc;
ConnectionCheckResult result = new ConnectionCheckResult();
if (InternetGetConnectedState(out Desc, 0) == true)
{
try
{
dbConnection StartConn = new dbConnection();
SqlConnection MyConnetion = StartConn.GetConnection();
MyConnetion.Open();
if (MyConnetion.State == ConnectionState.Open)
{
result.Success = true;
}
MyConnetion.Close();
}
catch (Exception)
{
result.Success = false;
result.Message = "The database connection does not available, May be because of this reasons: \n\n1- there is a new version of the program available. \n2- database has some maintenance. \n\n Please check later :)";
}
}
else
{
result.Success = false;
result.Message = "No internet connection available , Please check later :) \nThanks.";
}
return result;
}
Hello I recently started learning c# in Visual Studio..
I am trying to make a background process for my app.
I created a process and started it but I can't pause it without breaking my application.
public void WorkThreadFunction()
{
run = true;
for (int i = 0; i < 100; i++)
{
string message = "\r\n"+i+" Running...";
if (txtBox.InvokeRequired == true)
txtBox.Invoke((MethodInvoker)delegate { txtBox.Text += message; });
else
txtBox.Text += message;
Thread.Sleep(1000);
}
}
private void btnCapture_Click(object sender, EventArgs e)
{
Thread thread = new Thread(WorkThreadFunction);
if (run == false)
{
btnCapture.Text = "Abort";
lblStatus.Text = "Thread status: " + thread.ThreadState;
thread.Start();
}
else
{
btnCapture.Text = "Capture";
lblStatus.Text = "Thread status: " + thread.ThreadState;
//thread.Abort(); thread.Unset(); Thread.Sleep(999999); thread.WaitOne();
txtBox.Text += "Work!";
}
}
Also thread.ThreadState always returns "Unstarted"...
I tried using "ManualResetEvent" but this just freezes my app...
Help? :S
That's correct, you check ThreadState before calling Start(), thus it's unstarted.
As an unrelated note, you don't need that InvokeRequired check, it's always required in this context.
I am trying to build a simple code that joins csv files into one distinct file, but my background worker seems to have a mind of its own and my code gets stuck every time.
Here is my code for joining the file using the background worker:
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
try
{
if (string.IsNullOrEmpty(saveFilePath))
{
this.Invoke(new MethodInvoker(delegate
{
btnBrowseSave.PerformClick();
}));
}
if (!string.IsNullOrEmpty(saveFilePath))
{
if (dragEventArgs != null)
files = (string[])dragEventArgs.Data.GetData(DataFormats.FileDrop);
int filesCount = 0, rowsCount = 0;
foreach (string file in files)
{
filesCount++;
int fileTotalLines = File.ReadAllLines(file).Length;
this.Invoke(new MethodInvoker(delegate
{
lblFileName.Text = "Loading file: " + file.Substring(file.LastIndexOf("\\") + 1);
lblTotalFiles.Text = "File " + filesCount + " of " + files.Length;
}));
using (StreamReader reader = new StreamReader(file))
{
using (StreamWriter writer = new StreamWriter(saveFilePath))
{
while (!reader.EndOfStream)
{
try
{
while (stopPosition > rowsCount)
{
reader.ReadLine();
rowsCount++;
}
string email = reader.ReadLine().Trim();
if (!string.IsNullOrEmpty(email) && !dicEmails.ContainsKey(email))
{
dicEmails.Add(email, null);
writer.WriteLine(email);
}
rowsCount++;
stopPosition++;
backgroundWorker.ReportProgress((rowsCount * 100 / fileTotalLines), (int)ProgressType.Row);
if (backgroundWorker.CancellationPending)
return;
}
catch (Exception ex)
{
hadReadErrors = true;
}
}
}
}
backgroundWorker.ReportProgress(0, (int)ProgressType.Row);
backgroundWorker.ReportProgress((filesCount * 100 / files.Length), (int)ProgressType.File);
}
}
}
catch (Exception ex)
{
hadReadErrors = true;
MessageBox.Show(ex.Message);
}
finally
{
backgroundWorker.Dispose();
}
}
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
try
{
switch ((int)e.UserState)
{
case (int)ProgressType.Row:
lblFileProgress.Text = e.ProgressPercentage + "%";
fileProgressBar.Value = e.ProgressPercentage;
break;
case (int)ProgressType.File:
lblTotalProgress.Text = e.ProgressPercentage + "%";
totalProgressBar.Value = e.ProgressPercentage;
break;
}
}
catch (Exception ex) { }
}
When I run in debug mode and go with the debugger I don't see any problems, but when I let the code run it self it gets stuck and crashes.
Can someone PLEASE help me and tell me what am I missing out here ?
Here is the exception:
Managed Debugging Assistant 'ContextSwitchDeadlock' has detected a problem in
'C:\Users\Develop\Desktop\ExcelBuilder\ExcelBuilder\bin\Debug\ExcelBuilder.vshost.exe'.
Additional information: The CLR has been unable to transition from COM context 0x90fb78
to COM context 0x90fc30 for 60 seconds. The thread that owns the destination
context/apartment is most likely either doing a non pumping wait or processing a very
long running operation without pumping Windows messages. This situation generally has
a negative performance impact and may even lead to the application becoming non
responsive or memory usage accumulating continually over time. To avoid this problem,
all single threaded apartment (STA) threads should use pumping wait primitives
(such as CoWaitForMultipleHandles) and routinely pump messages during long running operations.
I did a small example of your program, trying to guess what it must do (https://github.com/anderson-rancan/stackoverflow_28798348, drag and drop 4 files to the groupbox, lorem?.csv), and there is a few things that you should consider:
never try/catch a unknown exception, every exception or something you cannot deal with (https://msdn.microsoft.com/en-us/library/ms182137.aspx)
when using a BackgroundWorker on a form, use the "sender" for references to it, it's a thread safe object to your method (https://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx)
maybe you are updating too fast your form, change your Invoke method to BeingInvoke, and do the update async (https://msdn.microsoft.com/en-us/library/0b1bf3y3(v=vs.110).aspx)
So, just fixing that was possible to run it, like this:
private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bckw = (BackgroundWorker)sender; // Recommended way, thread safe
try
{
if (string.IsNullOrEmpty(saveFilePath))
{
this.Invoke(new MethodInvoker(delegate
{
btnBrowseSave.PerformClick();
}));
}
if (!string.IsNullOrEmpty(saveFilePath))
{
if (dragEventArgs != null)
files = (string[])dragEventArgs.Data.GetData(DataFormats.FileDrop);
int filesCount = 0, rowsCount = 0;
foreach (string file in files)
{
filesCount++;
double fileTotalLines = File.ReadAllLines(file).Length;
this.BeginInvoke(new MethodInvoker(delegate
{
lblFileName.Text = "Loading file: " + file.Substring(file.LastIndexOf("\\") + 1);
lblTotalFiles.Text = "File " + filesCount + " of " + files.Length;
})); // Invoke async, way too fast this...
using (StreamReader reader = new StreamReader(file))
{
using (StreamWriter writer = new StreamWriter(saveFilePath))
{
while (!reader.EndOfStream)
{
try
{
while (stopPosition > rowsCount)
{
reader.ReadLine();
rowsCount++;
} // why are you using that? it won't get TRUE
string email = reader.ReadLine().Trim();
if (!string.IsNullOrEmpty(email) && !dicEmails.ContainsKey(email))
{
dicEmails.Add(email, null);
writer.WriteLine(email);
}
rowsCount++;
stopPosition++;
bckw.ReportProgress((int)Math.Round(rowsCount * 100 / fileTotalLines, 0), (int)ProgressType.Row);
if (bckw.CancellationPending)
return;
}
catch (Exception ex)
{
hadReadErrors = true;
throw; // Throw it again, or you won't know the Exception
}
}
}
}
bckw.ReportProgress(0, (int)ProgressType.Row);
bckw.ReportProgress((filesCount * 100 / files.Length), (int)ProgressType.File);
}
}
}
catch (Exception ex)
{
hadReadErrors = true;
MessageBox.Show(ex.Message);
}
finally
{
bckw.Dispose();
}
}
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//try
//{
switch ((int)e.UserState)
{
case (int)ProgressType.Row:
lblFileProgress.Text = e.ProgressPercentage + "%";
if (e.ProgressPercentage <= fileProgressBar.Maximum)
fileProgressBar.Value = e.ProgressPercentage;
break;
case (int)ProgressType.File:
lblTotalProgress.Text = e.ProgressPercentage + "%";
totalProgressBar.Value = e.ProgressPercentage;
break;
}
//}
//catch (Exception ex) { } // Don't catch everything
}
Finally, may I suggest another approach?
You're reading the file two times: one to get the number of lines, and another to read each line. Try to do this just once, you'll get a better result.
I've seen some great answers here and was wondering if someone could help me out.
Here's my code:
namespace expandGUIWPF
{
public static string getSHA256b64(string filepath)
{
byte[] bytes = SHA256.Create().ComputeHash(File.ReadAllBytes(filepath));
return Convert.ToBase64String(bytes);
}
private void btnRun_Click(object sender, RoutedEventArgs e)
{
{
string folder = txtFolder.Text;
string filelist = folder + "\\FileList.txt";
string[] test = Directory.GetFiles(folder, "*", System.IO.SearchOption.AllDirectories);
File.WriteAllLines(filelist, test);
int length = File.ReadLines(filelist).Count();
pBar1.Minimum = 1;
pBar1.Maximum = length;
File.WriteAllLines(filelist, test);
using (StreamReader sr = new StreamReader(filelist))
{
string line;
while ((line = sr.ReadLine()) != null)
{
string oldfile = line;
string newfile = oldfile + ".expanded";
string oldhash = "";
string newhash = "";
try
{
ProcessStartInfo startInfo = new ProcessStartInfo(#"C:\test\test.exe", oldfile + " " + newfile);
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
Process.Start(startInfo);
Thread.Sleep(1000);
if (File.Exists(oldfile))
{
oldhash = getSHA256b64(oldfile);
}
if (File.Exists(newfile))
{
newhash = getSHA256b64(newfile);
File.Delete(oldfile);
File.Move(newfile, oldfile);
}
pBar1.Value = pBar1.Value + 1;
txtLog.AppendText(oldfile + "\r\n Old: " + oldhash + "\r\n New: " + newhash + "\r\n");
if (!(oldhash == newhash))
{
txtLog.AppendText("Successfully expanded file \r\n");
}
else
{
txtLog.AppendText("Unable to expand file \r\n");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
}
}
}
}
The problem is that my progressbar isn't updating. I know a little C# but I'm a beginner to WPF and can't get my head around setting up a background worker to update my UI. Would someone be able to give me a few pointers please? Currently the app works fine, but the progressbar jumps to 100% finished and all of the text suddenly appears.
Thanks in advance!
Tom
First you'll want your background worker to handle the processes in its DoWork event. Within that event you can call the ProgressChanged event to update the progress bar. Below is an example:
private void btnRun_Click(object sender, RoutedEventArgs e)
{
if(workerThread.IsBusy == false) // Make sure someone doesn't click run multiple times by mistake
{
pBar1.Value = 0;
workerThread.RunWorkerAsync();
}
}
private void workerThread_DoWork(object sender, DoWorkEventArgs e)
{
// Definitions and so forth
pBar1.Minimum = 0;
pBar1.Maximum = length;
int status = 0;
using (StreamReader sr = new StreamReader(filelist))
{
string line;
while ((line = sr.ReadLine()) != null)
{
// Try/Catch work here
status++;
workerThread.ReportProgress(status);
}
}
private void workerThread_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pBar1.Value = e.ProgressPercentage;
}
Just understand that the thread that's running the Form is the same one that will be used to update the form's controls. So if you have 'stuff' to do - like encrypting / decrypting lines from a file - you need to perform those items on another thread with a callback, otherwise the form display wont update until it's done with your stuff to do. You can raise events from inside a worker thread -- and catch them using an event handler on the main (form) thread to update the progress bar.
It seems that your UI thread is being blocked, in windows forms programming you have one message pump and while you main thread (UI) is doing something else it has to wait before it can process messages. You can fix this problem by setting up a background worker to send updates
For more information on UI thread and the message pump see this
http://www.codeproject.com/Articles/10311/What-s-up-with-BeginInvoke
For infomation on the backgroundworker thread see this
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
Small Example code
// This event handler is where the time-consuming work is done.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
for (int i = 1; i <= 10; i++)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
// Perform a time consuming operation and report progress.
System.Threading.Thread.Sleep(500);
worker.ReportProgress(i * 10);
}
}
}
I have the following code from 'Samples for Parallel Programming with the .NET Framework' MSDN when I was trying to cancel the Genetic generations of monkeys in debugging mode I am getting 'OperationCanceledException was unhandled by user code' on line token.ThrowIfCancellationRequested();. I have added last resort of exception handling 'UnobservedTaskException' but the code is never reaching there. Please help me in finding the problem here:
public MainForm()
{
InitializeComponent();
txtTarget.Text = _targetText;
_uiTasks = new TaskFactory(TaskScheduler.FromCurrentSynchronizationContext());
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
}
void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
e.SetObserved();
}
private int _currentIteration;
private CancellationTokenSource _cancellation;
private void btnRun_Click(object sender, EventArgs e)
{
if (_cancellation == null)
{
_cancellation = new CancellationTokenSource();
GeneticAlgorithmSettings settings = new GeneticAlgorithmSettings { PopulationSize = Int32.Parse(txtMonkeysPerGeneration.Text) };
txtBestMatch.BackColor = SystemColors.Window;
lblGenerations.BackColor = SystemColors.Control;
lblGenPerSec.Text = lblGenerations.Text = "-";
lblElapsedTime.Text = "0";
btnRun.Text = "Cancel";
chkParallel.Visible = false;
_startTime = _lastTime = DateTimeOffset.Now;
timerElapsedTime.Start();
// Run the work in the background
_cancellation = new CancellationTokenSource();
var token = _cancellation.Token;
bool runParallel = chkParallel.Checked;
Task.Factory.StartNew(() =>
{
// Create the new genetic algorithm
var ga = new TextMatchGeneticAlgorithm(runParallel, _targetText, settings);
TextMatchGenome? bestGenome = null;
// Iterate until a solution is found or until cancellation is requested
for (_currentIteration = 1; ; _currentIteration++)
{
token.ThrowIfCancellationRequested();
// Move to the next generation
ga.MoveNext();
// If we've found the best solution thus far, update the UI
if (bestGenome == null ||
ga.CurrentBest.Fitness < bestGenome.Value.Fitness)
{
bestGenome = ga.CurrentBest;
_uiTasks.StartNew(() => txtBestMatch.Text = bestGenome.Value.Text);
// If we've found the solution, bail.
if (bestGenome.Value.Text == _targetText) break;
}
}
// When the task completes, update the UI
}, token).ContinueWith(t =>
{
timerElapsedTime.Stop();
chkParallel.Visible = true;
btnRun.Text = "Start";
_cancellation = null;
switch (t.Status)
{
case TaskStatus.Faulted:
MessageBox.Show(this, t.Exception.ToString(), "Error");
break;
case TaskStatus.RanToCompletion:
txtBestMatch.BackColor = Color.LightGreen;
lblGenerations.BackColor = Color.LemonChiffon;
break;
}
}, _uiTasks.Scheduler);
}
else _cancellation.Cancel();
}
You've probably setup Visual Studio to stop on all thrown exceptions. You can either ignore this (hit continue) or disable this option: Debug menu > Exceptions. Clear the checkbox of "Common Language Runtime Exceptions" Thrown column. Alternatively you can uncheck the specific exception (click the Find button and search for OperationCanceledException).
Playing with Tasks on 4.5 and got the same error but for a different reason.
Posting here as this was the top search result and it took me a while to find the cause.
try
{
await Task.Run(() => DoWork());
label1.Text = "Finished.";
}
catch (OperationCanceledException)
{
label1.Text = "Cancelled.";
}
Which ran:
private async void DoWork()
{
// WORK STUFF
{
workerCancel.Token.ThrowIfCancellationRequested();
}
}
Cancelling would cause the unhandled error because I put void instead of Task:
private async Task DoWork()
The exception was actually handled... To ensure just press F5 to see that is's been caught. To set your debugger not to catch user unhandled exceptions press Ctrl + Alt + E and unselect User-unhandled