[SOLVED] Invoke/BeginInvoke

Answered Closed
0
0

Hello,

I have an app with a UI thread and network thread.  The network thread communicates with a server and uses Invoke and BeginInvoke to call functions in the UI thread, to update the UI.  I’ve been testing this app with Wisej for a few weeks, but I can’t seem to get anything that uses Invoke or BeginInvoke to work.  The functions appear to execute, but the UI is never updated.

Is this supposed to work, or is it a known problem?  If it’s a known problem, will it be fixed in tomorrow’s release, or a subsequent release?

Thanks,

David Muse

david.muse@firstworks.com

  • You must to post comments
Best Answer
0
0

Hi David,

Thank you for the test case. The issue with your code is that the thread is out of context. There is no way for a thread on the server to know the session that started it unless you pass it to the thread start method, etc.

That’s why we have Application.RunInContext(), Application.StartTask, and Application.Update().  See https://docs.wisej.com/docs/concepts/background-tasks.

When adding Application.Update(this) at the end of your thread method the update works, but it has nothing to update since the code before (adding the panel) couldn’t flag the component as needing an update since the code before the update is running out of context. It can still access all the components, since Wisej components can run in the thread, but the session is not reachable.

To make it short :), this is how to fix your test code: two different ways:

  1. Instead of new Thread(thread), use Application.StartTask(thread). This is the easiest, since Application.StartTask() starts the thread in context.
  2. You can use new Thread(thread), but in the thread() method, wrap the code in Application.Update().
 Application.Update(this, () =>
 {
   Panel p2 = new Panel();
   p2.BackColor = Color.Green;
   p2.Location = new Point(50, 50);
   Controls.Add(p2);
 });

Also, as I mentioned before, you don’t need to use this.Invoke((Action)delegate(){}). It doesn’t do anything with Wisej, it simply calls the delegate.

I also noticed that your Web.config is coming from a mistaken template that we have distributed during the beta. Please change the json handler in Web.config to:

<add name=”json” verb=”*” path=”*.json” type=”System.Web.HttpForbiddenHandler” />

The handler is not necessary at all. However, we thought that some apps may store sensitive information in the configuration json and this setting prevents someone from downloading the json. The mistaken handler we had did exactly the opposite.

HTH

Best,

Luca

 

  • You must to post comments
0
0

I’ve attached a fairly simple example that illustrates the problem that I am having.  It includes nearly identical Wisej and Winforms projects.

The program creates a Form, then adds Red, Green, and Blue panel to it.  The Green panel is added using a thread with Invoke.

The Winforms version works as expected, but the Wisej version doesn’t display the Green panel.

I tried replacing Invoke() with BeginInvoke().  I also tried calling the invoked code directly.  I also tried adding Application.Update(this); after the Controls.Add() call, in all three cases.  No matter what, I always get the same result.

I’m sure I’m doing something wrong, but it’s not clear what.  I’d appreciate any insight.

Thanks,

Dave

david.muse@firstworks.com

Attachment
  • You must to post comments
0
0

Hi David,

In addition to Nic’s reply, I’d like to add that threads don’t really matter in Wisej and you don’t need Invoke() to make cross thread calls. You can simply call any method on any component from any thread.

We have re-implemented Invoke and BeginInvoke to provide similar functionality as WinForms but within a server environment:

  • Control.Invoke(Delegate method) is the same as calling the method directly or using ((Delegate)method).DynamicInvoke(args) in case you saved the delegate and want to use it later.

 

  • Control.BeginInvoke(Delegate method) is a bit different, it allows for something similar to a PostMessage (which is what WinForms did). However since Wisej doesn’t have message or a message loop, it uses Appliction.Post(Action) to defer the call and additionally restores the context, for example:

 

 private void button1_Click(object sender, EventArgs e)
 {
   this.button1.Text = "1";
   this.button1.BeginInvoke((Action)delegate() {
        this.button1.Text += "2";
   });
   this.button1.Text += "3";
 }

The button’s text will be “132” and *not* “123”, because the code in BeginInvoke() is executed *after* everything else is done in Wisej and right before returning to the client. So there is no timer or message overhead, it’s all clean and straightforward.

If you’d like to upload a simple test case showing what you’d like to achieve we can help further.

HTH

Best,

Luca

 

 

  • You must to post comments
0
0

Hi David,

I have a lot of background threads in my application and it took quite a long time for me to work out how to get it all going (with the help of Luca). Basically the “magic” is to wrap any updates on any wisej control on the background thread in an Application.update task – as I understand it this ensures that the wisej framework will then push these updates to the browser assuming you are running in websocket mode (which you won’t be if you are using VS on windows 7).

i.e.

Application.Update(this, () =>

{

//Do something that updates my UI

}

Note: this in my snippet above is any wisej control.

For non-web socket connections you also need to have a wisej.timer on the form attached to an event on the server, even if that event is empty, to ensure that wisej processes your other updates.

HTH

Nic

  • You must to post comments
Showing 4 results