TargetInvocationException?
-
So, it's been a while since I did any threading and so I thought to review some
BackgroundWorkers
. I made a test program and get this exception I cannot explain. It occurs during theProgressChanged
event when reading a double value. I'm using anArrayList
as argument where the first value is adouble
(for accurate progress report) and the second value is astring
array. The exception gets thrown when trying to assign the value of theArrayList
to a localdouble
variable. Can anyone tell me what went wrong and how I can fix it?private void BW_Text_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
ArrayList arg = (ArrayList)e.UserState;
double progress = (double)arg[0]; //exception gets thrown here
string[] content = (string[])arg[1];textprogress += progress; TSL\_Text.Text = "Status: Reading..." + String.Format("{0:0.##}", textprogress) + "%"; Fill\_ListView(true, content); }
Thanks!
-
So, it's been a while since I did any threading and so I thought to review some
BackgroundWorkers
. I made a test program and get this exception I cannot explain. It occurs during theProgressChanged
event when reading a double value. I'm using anArrayList
as argument where the first value is adouble
(for accurate progress report) and the second value is astring
array. The exception gets thrown when trying to assign the value of theArrayList
to a localdouble
variable. Can anyone tell me what went wrong and how I can fix it?private void BW_Text_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
ArrayList arg = (ArrayList)e.UserState;
double progress = (double)arg[0]; //exception gets thrown here
string[] content = (string[])arg[1];textprogress += progress; TSL\_Text.Text = "Status: Reading..." + String.Format("{0:0.##}", textprogress) + "%"; Fill\_ListView(true, content); }
Thanks!
Rather than just casting the UserState to an ArrayList, check it: use
is
oras
and make sure it is what you think it is - a UserState could in theory be any Object, so it is well worth checking. I would useas
as I like to see explicit null checks. Do the same with the content of the ArrayList: check is is a double. Since you don't say what the exception is, it could be caused by either; but check both - it doesn't add a lot of overhead and it makes your program a lot more robust.Real men don't use instructions. They are only the manufacturers opinion on how to put the thing together.
-
So, it's been a while since I did any threading and so I thought to review some
BackgroundWorkers
. I made a test program and get this exception I cannot explain. It occurs during theProgressChanged
event when reading a double value. I'm using anArrayList
as argument where the first value is adouble
(for accurate progress report) and the second value is astring
array. The exception gets thrown when trying to assign the value of theArrayList
to a localdouble
variable. Can anyone tell me what went wrong and how I can fix it?private void BW_Text_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
ArrayList arg = (ArrayList)e.UserState;
double progress = (double)arg[0]; //exception gets thrown here
string[] content = (string[])arg[1];textprogress += progress; TSL\_Text.Text = "Status: Reading..." + String.Format("{0:0.##}", textprogress) + "%"; Fill\_ListView(true, content); }
Thanks!
In the debugger, check to be sure the actual values are what you expect. But, personally, I wouldn't use the ArrayList, I'd make separate fields in the ProgressChangedEventArgs.
-
So, it's been a while since I did any threading and so I thought to review some
BackgroundWorkers
. I made a test program and get this exception I cannot explain. It occurs during theProgressChanged
event when reading a double value. I'm using anArrayList
as argument where the first value is adouble
(for accurate progress report) and the second value is astring
array. The exception gets thrown when trying to assign the value of theArrayList
to a localdouble
variable. Can anyone tell me what went wrong and how I can fix it?private void BW_Text_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
ArrayList arg = (ArrayList)e.UserState;
double progress = (double)arg[0]; //exception gets thrown here
string[] content = (string[])arg[1];textprogress += progress; TSL\_Text.Text = "Status: Reading..." + String.Format("{0:0.##}", textprogress) + "%"; Fill\_ListView(true, content); }
Thanks!
Three remarks FYI: 1. there is ProgressChangedEventArgs.ProgressPercentage which is of type int; its name suggests the value should be in the range [0,100] however the value is irrelevant to .NET and you can pass any value you choose, from int.MinValue to int.MaxValue, so you have a full 32-bit resolution at your disposal. 2. I don't expect people be interested in a very accurate progress value; if you were to display a progress bar on a display with say 1280 pixels, then you would be able to show no more than 1281 different values anyway; yes you could just show a number, but that does seem a bit awkward. 3. Once you have settled on the exact range and resolution you want to pass around, you should make sure not to call ReportProgress() with the same progress value over and over, as each call causes a thread switch, and achieves nothing as no new information is passed anyway. So create a little method and compare with the previous value, as in:
public void MyReportProgress(int val) {
if (val!=previousVal) {
previousVal=val;
ReportProgress(val);
}
}You may be surprised how much faster your actual operation runs once you stop passing unnecessary progress resolution back and forth (and stop repainting that progress bar abundantly). :)
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles] Nil Volentibus Arduum
Please use <PRE> tags for code snippets, they preserve indentation, and improve readability.
modified on Sunday, August 15, 2010 2:47 PM
-
Rather than just casting the UserState to an ArrayList, check it: use
is
oras
and make sure it is what you think it is - a UserState could in theory be any Object, so it is well worth checking. I would useas
as I like to see explicit null checks. Do the same with the content of the ArrayList: check is is a double. Since you don't say what the exception is, it could be caused by either; but check both - it doesn't add a lot of overhead and it makes your program a lot more robust.Real men don't use instructions. They are only the manufacturers opinion on how to put the thing together.
I told you what the exception is, VS doesn't give any further explanation (which is why I'm so confused). The code that throws it (according to VS) is the Application.Run line in the program class. Though seemingly I was able to get rid of it by properly checking the userstate and always sending new ArrayList. On the other hand, ReportProgress seems sorta broken. It happens once every blue moon compared to the DoWork event. In DoWork I'm running a loop and part of it is the ReportProgress method, yet the first time the event is actually raised happens between randomly the 350th and 400th time of the loop. How come? When debugging I set break points in the DoWork and ReportProgress events and confirmed that DoWork is only actually raised after DoWork looped several times.
-
I told you what the exception is, VS doesn't give any further explanation (which is why I'm so confused). The code that throws it (according to VS) is the Application.Run line in the program class. Though seemingly I was able to get rid of it by properly checking the userstate and always sending new ArrayList. On the other hand, ReportProgress seems sorta broken. It happens once every blue moon compared to the DoWork event. In DoWork I'm running a loop and part of it is the ReportProgress method, yet the first time the event is actually raised happens between randomly the 350th and 400th time of the loop. How come? When debugging I set break points in the DoWork and ReportProgress events and confirmed that DoWork is only actually raised after DoWork looped several times.
Megidolaon wrote:
In DoWork I'm running a loop and part of it is the ReportProgress method, yet the first time the event is actually raised happens between randomly the 350th and 400th time of the loop.
That is perfectly feasible as the ReportProgress method raises the ProgressChanged event asynchronously. Presumably by the time the UI thread gets around to processing the first event the BackgroundWorker has called ReportProgress 350-400 times and quite a backlog has built up. If each ProgressChangedEventArgs references the same ArrayList then you will always see the most recent values and not those that were in force at the time the event was raised. As a guess your code should not raise the event more frequently than once every 1000 loop iterations. Even that will probably be far too frequent and you should aim for no more than 2 per second if a display element is being updated. Alan.
-
Megidolaon wrote:
In DoWork I'm running a loop and part of it is the ReportProgress method, yet the first time the event is actually raised happens between randomly the 350th and 400th time of the loop.
That is perfectly feasible as the ReportProgress method raises the ProgressChanged event asynchronously. Presumably by the time the UI thread gets around to processing the first event the BackgroundWorker has called ReportProgress 350-400 times and quite a backlog has built up. If each ProgressChangedEventArgs references the same ArrayList then you will always see the most recent values and not those that were in force at the time the event was raised. As a guess your code should not raise the event more frequently than once every 1000 loop iterations. Even that will probably be far too frequent and you should aim for no more than 2 per second if a display element is being updated. Alan.
Thanks. I guess I should better collect the data within the DoWork event and then report a while bunch at once. But now the TargetInvocationException is back and I can#t find it, no matter where I set a breakpoint.:confused:
modified on Monday, August 16, 2010 9:47 PM