.Net forms, controls, threading

Started by
2 comments, last by outRider 20 years, 3 months ago
(Just started learning C#, .Net, Forms.) I have a form with a custom PictureBox (i.e inherited from PictureBox), with a new method Transition(). In Transition I hand the work off to a work thread and return immediately so the UI doesn''t hang. In the work thread I draw on PictureBox.Image and call PictureBox.Invalidate() in a finite loop to see the results as they occur. I kept getting a "The object is currently in use elsewhere." prompt and a break on the PictureBox.Image object or it''s associated Graphics object and have come to find out that controls should not be manipulated in threads other than the ones that created them. That''s the dilemma. So instead of calling this.Invalidate after drawing on this.Image (this being my custom PictureBox), I did this.Draw(), Draw() being the following:

delegate void HelperDelegate();

private void Draw()
{
	if (this.InvokeRequired)
		this.Invoke(new HelperDelegate(this.Draw));
	else
		this.Invalidate();
}
 
...but I still get the same problem when accessing Image, which means that I can''t touch any part of PictureBox within the work thread, even Image, which you would think is equivalent to any other memory bitmap, but I guess PictureBox tries to access it over in the main thread from time to time to update itself while I''m drawing on it. This makes asynchronous drawing in another thread very very difficult. Does anyone have any suggestions? The only thing I can think of is that I should run the message pump in the drawing loop all in the main thread... though I''m not quite sure how to manually call the message pump using Forms... :/ Thanks in advance to anyone who can help. ------------ - outRider -
Advertisement
i havent used C# or even any other of the .NET languages but i supose you could solve that problem using a timer control.

in longhorn.msdn.microsoft.com i got this info:

system.windows.forms.timer is a control that will make something (a method for example) happen in X time.

so imagine this:

Timer *t = new Timer;
t.set_Interval( 50 ); //you can set it to how may milisecs you want

t.add_Tick( new EventHandler( this, &class.method ) );

you just pass by reference (if C# accept it, i dont know) the method you want to be executed apart from the main one.

it will be executed once every 50milisecs.

if you just want it to be executed once you can set it off with:

t.set_Enabled( false );

in that way you can make something without causing the UI to hang.

i hope ive been helpful, any question ill try to answer it.

[edited by - a2ps on January 3, 2004 12:36:20 AM]
yet, another stupid signature..
That won''t work if my animation is slow (not that it is) because it will still hang the UI for as long as it takes to execute.

I seem to have found a fix. Instead of drawing to PictureBox.Image I draw to another Bitmap. Then I copy that to Image and Invalidate() after calling Invoke and switching to the main thread.

------------
- outRider -
Hey, I just read about this issue last night. According to Tom Miller, who wrote MDX, controls can only properly be accessed by the thread that they were created in. Otherwise Bad Things can happen. So if you''ve got a multithreaded app, you have to have some kind of callback(s) in the thread that created the picturebox that manipulate the Image data.

So if I were trying to transition between two images, I would load local copies of both in the worker thread, and then invoke the callback on the picturebox thread whenever a new frame was completed, so that it could update the picturebox image.

Now, I don''t understand threading in C# very well, and I don''t really understand how Invoke works, so I apologize if this isn''t too helpful. But I think you want to use the asychronous invoke call - BeginInvoke(). I''ve never used it, so the best I can give is this code snippet from my MDX book:

Here, the author is updating the text of an editbox control on the GUI thread from a message handler thread:


private void OnDataReceive(object sender, ReceiveEventsArgs e)
{
string newtext = "New Player ID: " + e.Message.SenderID.ToString();
this.BeginInvoke(new AddTextCallback(AddText), new object[] { newtext });
}


Sorry, I can''t illuminate the nature of the funky syntax :-(, and I''ve never posted code before so I might have used the wrong tag.


----------------------------------------
Let be be finale of seem, seems to me.
----------------------------------------

Coding:
http://www.stanford.edu/~jjshed/coding

Miscellany:
http://www.stanford.edu/~jjshed

Shedletsky's Bits: A Blog | ROBLOX | Twitter
Time held me green and dying
Though I sang in my chains like the sea...

This topic is closed to new replies.

Advertisement