Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Languages / C# / March 2008

Tip: Looking for answers? Try searching our database.

A question on threading

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Rahul - 02 Mar 2008 12:38 GMT
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?
Mugunth - 02 Mar 2008 12:47 GMT
> Hello,
>
[quoted text clipped - 15 lines]
> How can I keep my window responsive while running this method? Any
> ideas?

Try using a  backgroundworker.
Rahul - 02 Mar 2008 13:19 GMT
> > Hello,
>
[quoted text clipped - 17 lines]
>
> 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?
Peter Webb - 02 Mar 2008 13:10 GMT
> Hello,
>
[quoted text clipped - 15 lines]
> 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.
Rahul - 02 Mar 2008 13:28 GMT
On Mar 2, 5:10 am, "Peter Webb" <webbfam...@DIESPAMDIEoptusnet.com.au>
wrote:

> > Hello,
>
[quoted text clipped - 20 lines]
> 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! :)
Alfred Myers - 02 Mar 2008 14:12 GMT
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

> On Mar 2, 5:10 am, "Peter Webb" <webbfam...@DIESPAMDIEoptusnet.com.au>
> wrote:
[quoted text clipped - 35 lines]
>
> Thanks a lot! :)
Rahul - 03 Mar 2008 02:31 GMT
> Hi,
>
[quoted text clipped - 50 lines]
>
> > Thanks a lot! :)

Hello Alfred,

I will definitely try this approach.

Thanks a lot.
Peter Duniho - 02 Mar 2008 20:20 GMT
> [...]
>> Application.DoEvents() will force your thread to process messages from  
[quoted text clipped - 8 lines]
> 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
Fredo - 02 Mar 2008 22:00 GMT
[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...
Abubakar - 02 Mar 2008 14:19 GMT
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

> Hello,
>
[quoted text clipped - 15 lines]
> How can I keep my window responsive while running this method? Any
> ideas?
Rahul - 03 Mar 2008 02:44 GMT
> Hi,
>
[quoted text clipped - 38 lines]
> > How can I keep my window responsive while running this method? Any
> > ideas?

@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.

Rate this thread:







Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.