BackgroundWorker capture error - c#

I've been trying to follow this MSDN example, and using the code below. However, e.Error is ALWAYS null in RunWorkerCompleted even when an error does occur in SomeMethod();
private void WorkerDoWork(object sender, DoWorkEventArgs e)
{
getMethod = SomeMethod();
}
private void Worker_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
var result = ModernDialog.ShowMessage("Error occurred.... " +
e.Result, "ErrorTitle", MessageBoxButton.OK);
}
else if (e.Cancelled)
{
}
Else
{
}
}
Can anyone see what I'm doing wrong?
I can get around it by doing the following but I don't really understand why the example in MSDN is not working for me?
private void WorkerDoWork(object sender, DoWorkEventArgs e)
{
try
{
getMethod = SomeMethod();
}
catch(Exception ex)
{
e.Result = ex;
}
}
private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Result is Exception)
{
var result = ModernDialog.ShowMessage("Error occurred.... " + e.Result, "ErrorTitle", MessageBoxButton.OK);
}
//etc
}
Also, using the second method I can't access the .Message from e.Result. For example, in WorkerDoWork I can use ex.Message
Edit: I've setup the worker to create it's own error and I still get e.Error == null. The variable displayed is a bit faint as CTRL+PrtSc makes it fade

I think the problem is your empty exception block in emailWorkerDoWork(). For the result to be an exception you can't catch the exceptions in your background worker.
So something like this should give you the desired result:
private void emailWorkerDoWork(object sender, DoWorkEventArgs e)
{
int value = 1 / int.Parse("0");
}
I found another SO answer that confirms my suspicion and provides a MSFT reference here.

Related

Ending program with a stop button

I am trying to get my program to close when clicking a stop button.
I am using a background worker, but whenever i click stop, the form hangs and then i get an error saying "An exception of type 'OpenQA.Selenium.WebDriverException' occurred in WebDriver.dll but was not handled in user code"
My stop button click code is
private void button2_Click(object sender, EventArgs e)
{
if (backgroundWorker1.WorkerSupportsCancellation)
{
backgroundWorker1.CancelAsync();
}
Application.Exit();
driverGC.Quit();
}
The RunWorkerCompleted is:
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
MessageBox.Show("You've cancelled the backgroundworker!");
}
else if (e.Error != null)
{
MessageBox.Show("Error:" + e.Error.Message);
}
else
{
MessageBox.Show("Done!");
}
}
Yes, i have it supporting cancellation. Any thoughts?
Have you tried:
this.Application.Close();

trying to make a textbox populate a variable that changes every three seconds

I am trying to make a text box in a WPF C# application populate a text box from a variable gathered from an external database using WCF and having little luck. Currently the text box states ScoreBoardClientTest.FeedServiceAgent instead of the value of agentsavailable. I was able to make this exact same code work in a console application when using this line of code inside of OnMessageReceived
console.writeline(e.cmsdata.skill.agentsavailable.tostring());
so I assumed I could do something similar here.
any help understanding where I'm going wrong would be great.
DisplayNumber is the name of the textbox.
public void TextBlock_Loaded(object sender, EventArgs e)
{
using (var data = new FeedServiceAgent())
{
data.MessageReceived += OnMessageReceived;
data.Subscribe("92", 3);
DisplayNumber.Text = data.ToString();
}
}
public static void OnMessageReceived(object sender, MessageReceivedEventArgs e)
{
try
{
if (e == null)
return;
if (e.CmsData == null)
{
e.CmsData.Skill.AgentsAvailable.ToString();
}
// if (!String.IsNullOrEmpty(e.Message))
// Console.WriteLine(e.Message);
}
catch (Exception ex)
{
// logger.Error(" Exception " + ex);
// throw ex;
}
}
Edit
Changed:
DisplayNumber.Text =e.CmsData.Skill.AgentsAvailable.ToString();
to:
Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() => { DisplayNumber.Text = e.CmsData.Skill.AgentsAvailable.ToString() ; }
This will handle multithreaded calls. You might have to add a using System.Threading statement for the DispatcherPriority enum
EndEdit
It is still unclear how to get from the data of Type FeedServiceAgent to a Skill.AgentsAvailable property in your Loaded event handler. We need more information on how to make that navigation. Is the assignment even necessary in the Loaded handler? I've marked the location in the code below.
I've also made what appears to be the necessary changes to the message handler method.
public void TextBlock_Loaded(object sender, EventArgs e)
{
using (var data = new FeedServiceAgent())
{
data.MessageReceived += OnMessageReceived;
data.Subscribe("92", 3);
//DisplayNumber.Text = data.ToString();
//Is this assignment even necessary?
DisplayNumber.Text = /*Still unclear what goes here because we don't know what how to get from `data` to `Skill`*/
}
}
public static void OnMessageReceived(object sender, MessageReceivedEventArgs e)
{
try
{
if (e == null)
return;
if (e.CmsData == null)
{
//e.CmsData.Skill.AgentsAvailable.ToString();
Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() => { DisplayNumber.Text = e.CmsData.Skill.AgentsAvailable.ToString() ; }));
}
// if (!String.IsNullOrEmpty(e.Message))
// Console.WriteLine(e.Message);
}
catch (Exception ex)
{
// logger.Error(" Exception " + ex);
// throw ex;
}
}

C# BackgroundWorker ProgressChanged doesn't get fired until end of function

I have a method in my class that has some loops inside.
Main purpose of this method is converting some files so I put a progressbar in my form that should get updated after each file has been converted.
I tried every possible combination and I read everything I could but I couldn't solve this issue.
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
converterProgressBar.Value = e.ProgressPercentage;
}
is called only after the main loop of my method has been executed.
This is my method:
public string Convert()
{
convertBtn.Enabled = false;
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
totalCount = files.length;
bw.RunWorkerAsync();
if (!Directory.Exists(folder))
{
Directory.CreateDirectory(folder);
}
foreach (string file in files)
{
countFile++;
if (chk.Checked)
{
class1.DoJob();
}
using (// some code))
{
using (//some other code))
{
try
{
using (// again some code)
{
// job executing
}
}
catch (exception
{
}
}
}
convertedVideosL.Text = txtToUpdate;
convertedVideosL.Refresh();
}
countFile = countFile + 1;
MessageBox.Show("Done");
countFile = -1;
return outputFile;
}
And here are the BackgroundWorker Event Handlers:
void bw_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i <= totalCount; i++)
{
if (bw.CancellationPending)
{
e.Cancel = true;
}
else
{
int progress = Convert.ToInt32(i * 100 / totalCount);
(sender as BackgroundWorker).ReportProgress(progress, i);
}
}
}
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
converterProgressBar.Value = e.ProgressPercentage;
}
void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled == false)
{
convertedVideosL.Text = "Finished!";
}
else
{
convertedVideosL.Text = "Operation has been cancelled!";
}
}
But I cannot get to update the progress bar for every file that is converted.
It waits for the foreach loop to end and then calls bw_ProgressChanged.
If I put RunWorkerAsync() inside the foreach loop an exception is thrown that says the BackgroundWorker is busy and cannot execute other tasks.
It seems to me obvious that DoWork() only executes a for loop then it shouldn't be aware of the conversion going on but ProgressChanged should be fired by ReportProgress(progress,i).
Could please someone explain me why and help me with a solution?
Thanks!
Currently the conversion is not executed by the instance of the BackgroundWorker type. The conversion should be called from the DoWork event handler.
Please consider extracting the conversion-related functionality:
if (!Directory.Exists(folder))
{
Directory.CreateDirectory(folder);
}
foreach (string file in files)
{
// Details...
}
into the separate method. After that just call the method from the DoWork event handler.
Pseudo-code to demonstrate the idea:
public void StartConversion()
{
...
TWorkerArgument workerArgument = ...;
worker.RunWorkerAsync(workerArgument);
// No message box here because of asynchronous execution (please see below).
}
private void BackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
{
// Get the BackgroundWorker that raised this event.
BackgroundWorker worker = sender as BackgroundWorker;
e.Result = Convert(worker, (TWorkerArgument)e.Argument);
}
private static TWorkerResult Convert(BackgroundWorker worker, TWorkerArgument workerArgument)
{
if (!Directory.Exists(folder))
{
Directory.CreateDirectory(folder);
}
foreach (string file in files)
{
// Details...
worker.ReportProgress(percentComplete);
}
return ...;
}
private void BackgroundWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Show the message box here if required.
}
Please replace the TWorkerArgument and TWorkerResult types appropriately.
Also, please refer to the example which uses the BackgroundWorker class for the additional details: How to: Implement a Form That Uses a Background Operation, MSDN.

Why sometimes i'm getting exception in Backgroundworker do work event InvalidOperationException?

In the form1 constructor i'm doing:
buttonSnap.Enabled = false;
backgroundWorker1.RunWorkerAsync();
Then i have a button click:
private void buttonSnap_Click(object sender, EventArgs e)
{
ClearGraphics = true;
this.listBoxSnap.Items.Clear();
this.pictureBoxSnap.Image = null;
backgroundWorker1.RunWorkerAsync();
buttonSnap.Enabled = false;
}
And in the backgroundworker do event i'm adding to a listBox items each item is a captured window:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
try
{
if (this.IsHandleCreated)
{
listBoxSnap.Invoke(new MethodInvoker(delegate { this.listBoxSnap.Items.Add("Minimized Windows"); }));
listBoxSnap.Invoke(new MethodInvoker(delegate { this.listBoxSnap.Items.AddRange(WindowSnap.GetAllWindows(true, true).ToArray()); }));
}
}
catch (Exception ee)
{
string t = "exception " + ee.ToString();
}
}
This is a link for WindowSnap.cs class:
WindowSnap.cs
And this is a link for WindowSnapCollection.cs:
WindowSnapCollection.cs
In the WindowSnap.cs there is the method GetallWindows:
public static WindowSnapCollection GetAllWindows(bool minimized, bool specialCapturring)
{
windowSnaps = new WindowSnapCollection();
countMinimizedWindows = minimized;//set minimized flag capture
useSpecialCapturing = specialCapturring;//set specialcapturing flag
EnumWindowsCallbackHandler callback = new EnumWindowsCallbackHandler(EnumWindowsCallback);
EnumWindows(callback, IntPtr.Zero);
return new WindowSnapCollection(windowSnaps.ToArray(), true);
}
Now the exception is throw sometimes on the DoWork event on the line:
listBoxSnap.Invoke(new MethodInvoker(delegate { this.listBoxSnap.Items.AddRange(WindowSnap.GetAllWindows(true, true).ToArray()); }));
The exception is:
Invoke or BeginInvoke cannot be called on a control until the window handle has been created
The full exception message:
System.InvalidOperationException was caught
Message=Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
Source=System.Windows.Forms
StackTrace:
at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.Invoke(Delegate method, Object[] args)
at MinimizeCapture.Form1.backgroundWorker1_DoWork(Object sender, DoWorkEventArgs e) in c:\Temp\Capture\Form1.cs:line 81
InnerException:
Line 81 is:
listBoxSnap.Invoke(new MethodInvoker(delegate { this.listBoxSnap.Items.Add("Minimized Windows"); }));
Now i added in the backgroundworker do work event try and catch and sometimes it stop at the string t...in the catch. Then i added this:
if (this.IsHandleCreated)
So now sometimes it does the same problem but without stopping on the catch and throw the exception.
The same problem still exist sometimes it does the problem the exception describe sometimes not.
This : if (this.IsHandleCreated) didn't solve it.
You're checking this.InHandleCreated which returns whether handle is created for current instance. I presume it is a Form. But, Immediately you call listBoxSnap.Invoke that's the problem. Handle for listBoxSnap might not have been created at that point. You need to use listBoxSnap.InHandleCreated instead.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
try
{
if (listBoxSnap.IsHandleCreated)
{
listBoxSnap.Invoke(new MethodInvoker(delegate { this.listBoxSnap.Items.Add("Minimized Windows"); }));
listBoxSnap.Invoke(new MethodInvoker(delegate { this.listBoxSnap.Items.AddRange(WindowSnap.GetAllWindows(true, true).ToArray()); }));
}
}
catch (Exception ee)
{
string t = "exception " + ee.ToString();
}
}
Also, If this is your real code, You don't need a BackgroundWorker at all. You're not making use of worker thread. All work is done by Main thread only.
I'll suggest you to do the following which is effectively same as your code(because your DoWork does nothing useful).
buttonSnap.Enabled = false;
this.listBoxSnap.Items.Add("Minimized Windows"); }));
this.listBoxSnap.Items.AddRange(WindowSnap.GetAllWindows(true, true).ToArray());

How do you use the value of the combobox selected item?

I've written this code to change the serialport name:
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
serialPort1.PortName = (string)comboBox1.SelectedValue;
}
catch (Exception)
{
MessageBox.Show("The SerialPorts's Name Does Not Change !! ");
}
}
The result is that I get an Exception. The SerialPort's name never changes.
Could be one of many issues.
Is (string)comboBox1.SelectedValue String.Empty?
Is (string)comboBox1.SelectedValue null?
Is serialPort1 open?
It would be easier to answer the question if we had the actual exception message, instead of the custom message you defined.
To use the SelectedValue Mr. JaredPar MSFT explained ComboBox SelectedItem, SelectedValue, SelectedWhat???.
I guess, your trying get the PortName not the SelectedValue
Solution:
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex == -1) return;
if (string.IsNullOrWhiteSpace(comboBox1.Text)) return;
serialPort1.PortName = comboBox1.Text;
}
or
your trying get the SelectedValue not the PortName
Solution:
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedValue == null) return;
if (string.IsNullOrWhiteSpace(comboBox1.Text)) return;
serialPort1.PortName = (int)comboBox1.SelectedValue ;
}
Try to check your properties of ComboBox
Where: Display Member is your PortName
Value Member is your PortId or SelectedValue
You have to put a check in to see if the SelectedIndex is -1 or SelectedValue (or SelectedItem) is null. That's the value when there is no selected item.
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex == -1)
return;
serialPort1.PortName = (string)comboBox1.SelectedValue;
}
In order to figure out what the exception message is, try this:
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
try
{
serialPort1.PortName = (string)comboBox1.SelectedValue;
}
catch (Exception ex) {
MessageBox.Show(ex.Message);
}
}
The problem is that you don't handle exception properly. The exception that is thrown probably tells you what is the problem, but you're not looking at it.
Change your catch statement to
catch (Exception e) { MessageBox.Show(e.Message); }
Then see what is the exception, and fix it accordingly.
The SerialPort.PortName setter can throw an array of exceptions, so you need to know which one is it.

Categories