.NET Framework - invoking on the UI thread

Asked By ra on 04-Jun-12 02:03 PM
I read ?The only thread that is allowed to directly access a
property value of a form or one of its controls is the
primary UI thread? (in
http://msdn.microsoft.com/en-us/magazine/cc188732.aspx).

Is there a method in the standard library that I can call to
have a method/delegate/lambda of mine be executed on this UI
thread, preferably with a priority lower than user generated
events (so that the UI thread first handles user inputs,
then calls my method when it would have become idle
otherwise)?

(If someone knows Java: I am searching for a possible
equivalent of Java's ?invokeLater? method of the Java
standard library, tha is
http://docs.oracle.com/javase/7/docs/api/java/awt/EventQueue.html#invokeLater(java.lang.Runnable)
.)




Tom Shelton replied to ra on 04-Jun-12 10:13 AM
Stefan Ram expressed precisely :

I am going to assume windows forms.  Control.Invoke.  All windows forms
and controls inherit from control.

Alternatively, if your threading needs are not to complex - look at the
backgroundworker control.  It can often eliminate the need for explicit
threading and ui syncronization.

--
Tom Shelton
ra replied to Tom Shelton on 04-Jun-12 02:33 PM
Tom Shelton <tom_shelton@comcast.invalid> writes:

But AFAIK Control.Invoke is synchronous, I want something like this:

Public Sub ExampleMethod()
Call DoSomethingOnTheUserInterface()
InvokeOnTheUIThreadLater( New Example( AddressOf ExampleMethod ))
End Sub

What this is intended to do is the following (think of a
game or animation loop):

1. DoSomething on the user Interface
2. process any pending user input
3. when there is no more pending user input, repeat at step 1

The above method is intended to achieve this by

1. Call DoSomethingOnTheUserInterface
2. register itself to be called later, when there are no
more other events pending
(Now the system has time to process any pending user
input and other events. When it is done, it will call
ExampleMethod again, so we will be at step ?1.?, again.)

Effectivly, I want a method of mine to be called, when the
program is ?idle?, i.e., when there are no more pending
events to be processed.
Tom Shelton replied to ra on 04-Jun-12 11:19 AM
Stefan Ram was thinking very hard :

It is...  But, there is an async version - Control.BeginInvoke paired
with Control.EndInvoke.



I am not exactly clear on what you are trying to accomplish.  Using your
example of a game loop - that would typically look something like
(total pseudocode here - and ignoring the whole game clock thing):

while (running)
UpdateGame () ' update the internal game state
DisplayGame() ' update the user interface
end while

Uusally, the udpategame would process input that has occured since the
last tick, calculate positions, etc.  And then, you would render the
current state to the ui.  Assuming your game loop is on another thread
(which, would be unusual) - you would almost certainly want any of your
calls to update the ui state to be synchronous anyway.

So, can you be a little more clear about what your trying to accomplish
and where the trheading is actually comming into play?

--
Tom Shelton
ra replied to Tom Shelton on 04-Jun-12 10:11 PM
Tom Shelton <tom_shelton@comcast.invalid> writes:

I was just not aware that one can program this way in VB.

You say ?udpategame would process input?. How do I do this in VB?
?udpategame would process input? sound as if the program would query
(read) the user input, while AFAIK in VB one instead defines subs such as

Sub Command1_Click()
...
End Sub

which are called by the UI thread whenever appropriate.

I used to think that a loop such as:


need to run in the UI thread, since it is updating the UI,
but then, it will block the processing of events as long as
it is running, since there is only one UI thread and this is
currently busy executing this loop. So what do you do to
?process input? within this loop, when it actually needs to
terminate for input to be processed in the single UI thread?
Tom Shelton replied to ra on 05-Jun-12 03:47 PM
Stefan Ram was thinking very hard :

It seems we are talking about the render loop for a game.  I am not a
games programmer, by any streatch of the imagination - but, it is
something I have played with a bit.  Personally, if I were you - I
would look into using XNA for your game needs - but, I am not sure of
the level of VB support currently.  I am basically a C# guy...  XNA will
handle a lot of the plumbing of the basic render loop, i/o, resource
handeling, etc.  So, it might be worth it to look into it.

That, said - I will try to give you a couple of basic options if your
talking windows forms/gdi+ style games, at least the ones I have used :)

1) In some case simple windows forms timer can be sufficient depending
on how precise your timeing needs to be (if I remember correctly, a
windows forms timer can be +-100ms or so).  You can just set your timer
up in the load event (or as I do, I usually encapsulate all of this
into a game class - but, I am just trying to keep it simple):

GameTimer.Enabled = True
GameTimer.Interval = 1000/ FRAMES_PER_SECOND ' CALCULATE THE DESIRED
INTERVAL


Then you just handle your game stuff in the tick event:

Sub GameTimer_Tick (ByVal sender As Object, ByVal e As EventArgs)
Handles GameTimer.Tick

' handle your game state udpate and drawing here
End Sub

2)  Use an api based timer if you need more percision.  Other than
that, it is similar to above except you have to make use of p/invoke :)
I can help you with that if you go this route.

3) use a render loop with Application.DoEvents() - this my fav :)

Again, I tend to encapsulate a lot of the game into a class. I have a
in progress version of the old basic gorilas game that i've been
tinkering with from time-to-time.  My main method looks like this (this
is C#, but, the VB code would not be all that different:

static void Main ()
{
Application.EnableVisualStyles ();
Application.SetCompatibleTextRenderingDefault ( false );

// show the form and start the game loop
using ( GorillaForm gorillaForm = new GorillaForm () )
{

GorillaGame = new Game ( gorillaForm );
gorillaForm.Show ();
while ( !GorillaGame.GameOver )
{
GorillaGame.Render ();
Application.DoEvents ();
}
}
}

Basically, that lets the loop run as fast as it can - and still window
messages are processed (Application.DoEvents()).  Basically, the
GorillaForm is nothing but a blank form with some default settings
(fixed border, etc).  The game class hooks all of the input events,
etc, and handles them.

I am not endorsing any particular method - but, the point is that you
probably do not need to worry about threading and syncronization, if
this is just a typical game app?

--
Tom Shelton