|
Hi there!
I've got a question which I haven't been able to solve.
I have a code which involves a huge load of calculations. To keep track of where I am in the calculations I do some "this.Refresh()"-es in my code and I also update some labels.
Regardless, if I click to another application and click my app again, the form is just blank again and it's not refreshed at all. Also when I don't change to another application my form stops refreshing after some calculations. For example say my app does a calculation 100 times and it keeps the user updated about the number of calculations done. I kept looking at it and after the counter (label) reached say 53 it just stopped refreshing.
When I write 'huge load of calculations' I really mean it. The last run took 13 minutes.
So do you have any suggestions? It'd be great to improve my apps.
Thanks a lot!
Han
|
|
|
|
|
You need to perform the long-running code on a background thread. Then, to update the form, you need to use Invoke to avoid cross-thread problems.
|
|
|
|
|
It sounds like you are keeping the main thread busy, preventing it from taking care of the GUI (except for the few times you call Refresh). This is not the right way to handle windows nor Windows.
You need to perform your calculations on some other thread, maybe a ThreadPool one, maybe a BackgroundWorker. And then you need a safe way to have that one update your GUI, and that gets explained here[^].
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]
I only read formatted code with indentation, so please use PRE tags for code snippets.
I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).
|
|
|
|
|
Oh, man, I need coffee...
"the more logical control.Invoke(delegate {control.Text=text;}); does not compile!"
Should there be empty parentheses after delegate ?
|
|
|
|
|
That probably is what I meant to say, however when given
control.Invoke(delegate() { control.Text=text; });
(as it is in my test program) VS2008 complains with
Cannot convert anonymous method to type 'System.Delegate' because it is not a delegate type
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]
I only read formatted code with indentation, so please use PRE tags for code snippets.
I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).
|
|
|
|
|
When this came up last week, I whipped up a little app, including the method:
private void
ToggleEnable
(
object sender
,
System.EventArgs e
)
{
if ( this.InvokeRequired )
{
this.Invoke ( new System.EventHandler ( ToggleEnable ) , sender , e ) ;
}
else
{
System.Windows.Forms.Control c = sender as System.Windows.Forms.Control ;
if ( c != null )
{
c.Enabled = !c.Enabled ;
}
}
return ;
}
|
|
|
|
|
which is a bit of a strange whip as:
1. the return is redundant
2. the EventArgs are unused
3. you are implicitly relying on this being a Control, and sender (if a Control), being both created by the same thread.
Maybe what you intended was this:
private void ToggleEnable(object sender,System.EventArgs e) {
System.Windows.Forms.Control c = sender as System.Windows.Forms.Control;
if (c!=null) {
if (c.InvokeRequired) {
c.Invoke(new System.EventHandler(ToggleEnable), sender, e);
} else {
c.Enabled = !c.Enabled;
}
}
}
(or same without EventArgs)
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]
I only read formatted code with indentation, so please use PRE tags for code snippets.
I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).
|
|
|
|
|
Okay, I'll try to figure something out of this whole bunch of replies
So I understand, that by taking away resources from my main thread, the GUI can't be refreshed, so I have to do the background calculations in a separate thread. I'll try to do that and hopefully I won't have to write again.
|
|
|
|
|
Hankyaku wrote: calculations in a separate thread
always good.
Hankyaku wrote: hopefully I won't have to write again
if you mean rewrite your calculation code, no it remains the same; just launch the method from a thread (or call it from a BackgroundWorker.DoWork handler). If you mean, ask another question here, don't hesitate when you feel a need.
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]
I only read formatted code with indentation, so please use PRE tags for code snippets.
I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).
|
|
|
|
|
Sure, I meant the last one. I was completely sure, that I don't have to change my calculation code. I'm just simply not used to multithreading. So thanks for the comment, and in case I don't get it working, you can count on my questions, just as I do count on your answers.
|
|
|
|
|
The nice thing about it is you are using a params.
I did not know Control.Invoke took params, it is not in the documentation, but it does show in intellisense.
[ADDED]
However, your example does not need real data (such as a string in my SetText example), so using EventHandler seems not a general solution. Or do you see a way to generalize without much expense?
[/ADDED]
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]
I only read formatted code with indentation, so please use PRE tags for code snippets.
I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).
modified on Wednesday, May 19, 2010 12:05 PM
|
|
|
|
|
Well, then we both learned something.
(Not about the return ; I know the language doesn't require it, but it should, just as C used to require parameters parentheses around the value. "Every method should have exactly one return statement." It at least provides a convenient place for a breakpoint.)
modified on Wednesday, May 19, 2010 12:57 PM
|
|
|
|
|
PIEBALDconsult wrote: I know the language doesn't require it, but it should
I could live with that, similar to breaks in switch cases.
PIEBALDconsult wrote: just as C used to require parameters around the value
you mean parentheses? Did it really? I can't recall; I do recall I used to always put them, and then, some ten years ago, I stopped doing that.
K&R, in appendix A on syntax said:
return ;
return expression ;
but they also did put parentheses on their examples.
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]
I only read formatted code with indentation, so please use PRE tags for code snippets.
I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).
|
|
|
|
|
Luc Pattyn wrote: similar to breaks in switch cases
switches shouldn't use break at all. Stopping (not falling through) should be the normal flow without using a break statement.
Luc Pattyn wrote: you mean parentheses?
Yes...
A while (years) back, the subject came up and I found that Dennis Ritchie had put some of his old (circa 1974) C compiler code online and I looked through it and found that they appeared to be required, and his 1974 document says:
"
9.10 Return statement
A function returns to its caller by means of the return statement, which has one of the forms
return ;
return ( expression ) ;
In the first case no value is returned. In the second case, the value of the expression is returned to the caller of the
function. If required, the expression is converted, as if by assignment, to the type of the function in which it appears.
Flowing off the end of a function is equivalent to a return with no returned value.
"
That got relaxed some time later, but the habit got passed on to me in the '80s.
|
|
|
|
|
cases not falling through without a change-of-flow statement such as break would be rather confusing for programmers with a C-family heritage.
especially so when several cases get grouped, as in the empty case C# supports:
switch(myInt) {
case 0:
case 1:
...
break;
case 2:
case 5:
case 6:
case 7:
...
break;
}
I then certainly would want case lists (and case ranges): case 2, 5-6:
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]
I only read formatted code with indentation, so please use PRE tags for code snippets.
I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).
|
|
|
|
|
But had it been that way from the start...
And if braces (as I use them) were required instead it would be clearer.
switch ( myInt )
{
case 0:
case 1:
{
...
}
case 2:
case 5:
case 6:
case 7:
{
...
}
}
|
|
|
|
|
FWIW: in C the normal curly brackets allow local variable declarations, which sometimes comes in handy:
switch ( myInt ) {
int x, y;
case 1:
x=...;
y=...;
return x*y;
case 7:
x=...;
y=...;
return x/y;
}
C# does not like the idea. It does accept
switch ( myInt ) {
case 1:
int x=2;
int y=3;
return x*y;
case 7:
x=3;
y=4;
return x/y;
}
which is quite ugly IMO.
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]
I only read formatted code with indentation, so please use PRE tags for code snippets.
I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).
|
|
|
|
|
I would have loved (in an evil and twisted way) to do this:
switch (myInt)
{
case 1:
int x = 2;
int y = 3;
return x * y;
case 7:
return x / y;
}
But sadly it complains about the unassigned x and y ..
|
|
|
|
|
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]
I only read formatted code with indentation, so please use PRE tags for code snippets.
I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).
|
|
|
|
|
I just pulled out my VAX C 3.0 book (circa 1989) to see what it says on the matter.
It says that you can declare, but not initialize variables defined "in the compound statement within a switch statement".
switch ( x )
{
int i = 42 ; // Will be uninitialized (no warning?)
case 1 :
{
int j = 42 ; // This, of course, is limited to this scope
}
}
The C99 spec I have seems to agree with this, but it's hard to understand.
|
|
|
|
|
Luc Pattyn wrote: do you see a way to generalize without much expense
I'm hoping there is a way, but at the moment I have no need of one (which doesn't usually prevent me from trying anyway ).
When I whipped that up, I had the idea that it might serve as a general template for other such handlers that might require data from a derived EventArgs. At least it uses the pre-existing delegate.
I was just trying to make a generic version, but it's not as straight-forward as I would hope and probably not very useful. I would expect an anonymous method could be passed in that would do the actual work.
My feeling is that checking InvokeRequired and Invoking as necessary should be built into the classes and the application shouldn't need to worry about it. So what if slows down the code a little when it isn't required.
|
|
|
|
|
Okay, guys it seems that right now a "thank you" is all I have to say in this thread.
Thank you for the help guys! I checked multi threading, and I'm using the backgroundworker. Just as you've said, it produced the cross thread errors, but I got rid of them relatively easily. So I'm on my way, thank you again!
|
|
|
|
|
you're welcome.
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]
I only read formatted code with indentation, so please use PRE tags for code snippets.
I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).
|
|
|
|
|
Luc Pattyn wrote: generalize without much expense
Code is cheap.
I defined an abstract class EventArgsWrapper which derives from EventArgs then derived EnabledEventArgs (to hold a bool) and TextEventArgs (to hold a string). My DoSomething method can then use the provided EventArgs to decide what task is requested.
private void
DoSomething
(
object sender
,
System.EventArgs e
)
{
System.Windows.Forms.Control c = sender as System.Windows.Forms.Control ;
if ( c == null )
{
throw ( new System.InvalidCastException ( "sender must be a System.Windows.Forms.Control" ) ) ;
}
if ( c.InvokeRequired )
{
c.Invoke ( new System.EventHandler ( DoSomething ) , sender , e ) ;
}
else
{
EventArgsWrapper w = e as EventArgsWrapper ;
if ( w == null )
{
throw ( new System.InvalidCastException ( "e must be an EventArgsWrapper" ) ) ;
}
if ( w is EnabledEventArgs )
{
c.Enabled = ((EnabledEventArgs) w).Enabled ;
}
else if ( w is TextEventArgs )
{
c.Text = ((TextEventArgs) w).Text ;
}
}
return ;
}
// sender is already known to be a Control in this case
string temp = sender.Text ;
this.DoSomething ( sender , new EnabledEventArgs ( false , e ) ) ;
this.DoSomething ( sender , new TextEventArgs ( "Wait..." , e ) ) ;
/* Long-running process */
System.Threading.Thread.Sleep ( 5000 ) ;
this.DoSomething ( sender , new TextEventArgs ( temp , e ) ) ;
this.DoSomething ( sender , new EnabledEventArgs ( true , e ) ) ;
I suppose I could use Reflection to enumerate the public properties of the EventArgs and use them to set the sender's properties that match by name (and type?)... nah, far too much work. Maybe a Dictionary...
|
|
|
|
|
Yes, that looks OK.
I'm not sure I would have a EventArgsWrapper class, TextEventArgs could derive from EventArgs; a simple null test would filter the real nulls, the sequence of if(e is ...) would take care of the rest anyway.
Your example is still limited to properties that exist for all Controls; it becomes tedious when a property exists only for some, such as SelectionStart (TextBox, ComboBox, MonthCalendar, ...). Maybe use your style for the popular ones, and reflection for the others.
Luc Pattyn [Forum Guidelines] [Why QA sucks] [My Articles]
I only read formatted code with indentation, so please use PRE tags for code snippets.
I'm not participating in frackin' Q&A, so if you want my opinion, ask away in a real forum (or on my profile page).
|
|
|
|
|