A question on threading

  • Thread starter Thread starter Rahul
  • Start date Start date
R

Rahul

Hello,

I am writing a program related to image compression in C# (GUI
Application). In that I have a "heavy, long running" method which
among other things, calls this.Invalidate(); to make the screen
refresh to display the changes in image during processing.

The problem is that, once the program enters this method, the GUI
Window becomes non-responsive (but GUI gets updated regularly due to
this.Invalidate()).

So, I want the GUI to stay responsive while executing this method.

I tried running the method in another thread but then I cannot call
this.Invalidate() because "this" is in parent thread, and it throws
error.

How can I keep my window responsive while running this method? Any
ideas?
 
Hello,

I am writing a program related to image compression in C# (GUI
Application). In that I have a "heavy, long running" method which
among other things, calls this.Invalidate(); to make the screen
refresh to display the changes in image during processing.

The problem is that, once the program enters this method, the GUI
Window becomes non-responsive (but GUI gets updated regularly due to
this.Invalidate()).

So, I want the GUI to stay responsive while executing this method.

I tried running the method in another thread but then I cannot call
this.Invalidate() because "this" is in parent thread, and it throws
error.

How can I keep my window responsive while running this method? Any
ideas?

Try using a backgroundworker.
 
Rahul said:
Hello,

I am writing a program related to image compression in C# (GUI
Application). In that I have a "heavy, long running" method which
among other things, calls this.Invalidate(); to make the screen
refresh to display the changes in image during processing.

The problem is that, once the program enters this method, the GUI
Window becomes non-responsive (but GUI gets updated regularly due to
this.Invalidate()).

So, I want the GUI to stay responsive while executing this method.

I tried running the method in another thread but then I cannot call
this.Invalidate() because "this" is in parent thread, and it throws
error.

How can I keep my window responsive while running this method? Any
ideas?

Application.DoEvents() will force your thread to process messages from the
UI. Its probably not the right way to do it, but it will very probably work.
Just stick it in somewhere you expect to be called at least 50 times per
second and the UI should work just fine.
 
Try using a backgroundworker.

I tried to call the function through BackgroundWorker.

The "this.Invalidate()" runs properly. But this.Update() (which is the
next statement) does not work.
It throws the same exception "Cross-thread operation not valid:
Control '<FormName>' accessed from a thread other than the thread it
was created on."

this.Update() is necessary to ensure that GUI gets updated quickly, so
as to make the changes visible in pseudo-real-time.

Thanks for the reply.

Any other ideas?
 
Application.DoEvents() will force your thread to process messages from the
UI. Its probably not the right way to do it, but it will very probably work.
Just stick it in somewhere you expect to be called at least 50 times per
second and the UI should work just fine.

Peter,

A brilliant hack!! Although this might not be the best possible way...
it gets the job done.

Unless someone suggests a more "elegant" solution, this would do just
fine.

Thanks a lot! :)
 
Hi,

The UI only should be updated by the same thread that created the Control's
windows handle.
To do that, you can use Control.Invoke which receives a delegate pointing to
the code you want to execute.
For the delegate you can use a MethodInvoker such as the following.

this.Invoke(new MethodInvoker(this.Update));

HTH
 
Hi,
refresh to display the changes in image during processing.

what kind of changes? Do you send some kind of data to the gui that does
some drawings related work on the gui ??
among other things, calls this.Invalidate(); to make the screen

i dont do much gui programming, but if I look in the msdn and see the help
for Invalidate() method of Control class, it says this method causes paint
message to be sent to the control, calling which made sense when u were
executing the compression code inside the gui thread. But now that you
managed to run the compression code inside another thread, why would you
want to do something to send the paint message in the gui so it could
refresh, bcuz I think it would now be refreshing on its own whenever the
need is to do so.

I may have some suggestions but it depends on your answers to the questions
above.

...ab
 
[...]
Application.DoEvents() will force your thread to process messages from
the
UI. [...]

Peter,

A brilliant hack!! Although this might not be the best possible way...
it gets the job done.

Unless someone suggests a more "elegant" solution, this would do just
fine.

Do NOT accept that advice. It is the worst way to deal with this issue.

As mentioned by others, you can use more appropriate techniques such as
using a BackgroundWorker in conjunction with the ProgressChanged event, or
simply calling Control.Invoke() or Control.BeginInvoke() from your worker
thread to update the UI.

Note also that there's no need to call Control.Update() directly if you're
doing things correctly. For a control where you're doing your own
painting, simply calling Invalidate() will have the intended effect, and
of course for other controls, just changing their state will result in the
control itself doing the necessary invalidation.

I've yet to see an application that call Application.DoEvents() that
wasn't just plain broken. I doubt they exist and I'm certain, given your
description, that it's absolutely the wrong way to approach the issue in
your case.

Pete
 
Peter Duniho said:
[snip]
I've yet to see an application that call Application.DoEvents() that
wasn't just plain broken. I doubt they exist and I'm certain, given your
description, that it's absolutely the wrong way to approach the issue in
your case.

I agree with everything you've said there. I recently HAD to resort to
Application.DoEvents(), but only because I couldn't find a cleaner way to
get the behavior I wanted. The problem had to do with the way the finalizer
thread cleans up COM objects (by invoking onto the main thread) and a custom
popup menu control that has its own message pump (unfortunately, it was
written by someone who wasn't really qualified to do the work and we can't
afford a rewrite at this time). If the menu popped up at just the right
moment, it would, somehow, interfere with the custom windows messages invoke
uses and cause the finalizer thread to hang. Never could figure out
precisely how the messages were getting interrupted, but I discovered that
if I did the following:

GC.Collect();
GC.WaitForPendingFinalizers();
Thread.Sleep(40);
Application.DoEvents();

that it fixed the problem. Removing any of those 4 lines failed to fix the
problem.

My argument behind the code was as follows:

GC.Collect() would force a cleanup. GC.WaitForPendingFinalizers() would
force the finalizer stuff to get done. The Thread.Sleep() would give the
finalizer time to perform its invokes and the Application.DoEvents() would
ensure that the invoke messages were processed by the main app message pump.
Problem solved.

And no, there was nothing intrinsically wrong with the message pump. If the
finalizer thread did cleanup once the message pump was up and operating,
those messages went through just fine. It was just if the messages came
right as the menu was popping up.

But I agree, the code is fundamentally broken. Sometimes circumstances for
you to hack, though...
 
Hi,

The UI only should be updated by the same thread that created the Control's
windows handle.
To do that, you can use Control.Invoke which receives a delegate pointing to
the code you want to execute.
For the delegate you can use a MethodInvoker such as the following.

this.Invoke(new MethodInvoker(this.Update));

HTH

Hello Alfred,

I will definitely try this approach.

Thanks a lot.
 
Hi,


what kind of changes? Do you send some kind of data to the gui that does
some drawings related work on the gui ??


i dont do much gui programming, but if I look in the msdn and see the help
for Invalidate() method of Control class, it says this method causes paint
message to be sent to the control, calling which made sense when u were
executing the compression code inside the gui thread. But now that you
managed to run the compression code inside another thread, why would you
want to do something to send the paint message in the gui so it could
refresh, bcuz I think it would now be refreshing on its own whenever the
need is to do so.

I may have some suggestions but it depends on your answers to the questions
above.

..ab

@Abubakar,

My code actually modifies the bitmap that I'm going to display. This
bitmap contains the pixel information of the compressed output image.

Since the bitmap is a data structure, there is no event associated
with it that can trigger a GUI update.

So I am explicitly telling the window that "I have modified the
bitmap, please render it" using this.Invalidate(); + this.Update()

I hope this clarifies my approach in rendering the image. I am a
student and not especially skilled in this language so please guide me
if I'm doing this the wrong way. I'm trying to implement the JPEG
compression scheme (just for fun... hoping to learn something while at
it.)

I appreciate you taking time to help me out.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top