[SOLVED] Updating UI elements from other threads?

Answered Closed
0
0

Hi,

I’m trying to understand if it is possible to update UI elements from other threads in the application. I’ve seen the Application.Update() method in the background tasks sample but I can’t seem to make it work for my example (trying to toggle the colour of a panel using a system.timers.timer as the “other” thread):

public partial class Window1 : Form
{
    System.Timers.Timer timer = new System.Timers.Timer();

    public Window1()
   {
       InitializeComponent();
       timer.Interval = 2000;
         timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
       timer.Start();
    }

     void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
         // Toggle the colour
         panel1.BackColor = (panel1.BackColor == System.Drawing.Color.AliceBlue ? System.Drawing.Color.Purple : System.Drawing.Color.AliceBlue);
         Application.Update();
     }
}

The timer call happens and the panel background colour is changed in code but nothing changes in the browser. Where am I going wrong?

 

Thanks

Nic

  • You must to post comments
Best Answer
0
0

Hi Nic,

With this last update we have enhanced the way the context is restored. In your sample you don’t need to restore the context anymore since you don’t use Application.Update().

Now you need to save and restore the context only when:

  • Updating controls from a different thread not started using Application.StartTack() and using WebSocket and using Application.Update().

In all other cases it’s not necessary anymore.

Best,

Luca

  • You must to post comments
0
0

Luca / Frank,

Thank you for all your help. I had not realised that all the updates for the control also need to be inside the using(new Application.Context()). With that in place my application works as expected.

Thanks again for all your patience.

Nic

  • You must to post comments
0
0

Hi Nic,

please see Luca´s 2nd post in this thread, It contains what´s missing in your sample.

Here is your modified code sample that should work fine now:

public Window1()
{
InitializeComponent();

t.AutoReset = true;
t.Interval = 2000;
t.Start();

this.context = Application.Context;
t.Elapsed += t_Elapsed;
}

void t_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
using (new ApplicationContext(this.context))
{
panel1.BackColor = (panel1.BackColor == System.Drawing.Color.Aquamarine ? System.Drawing.Color.Red : System.Drawing.Color.Aquamarine);
Application.Update();
System.Diagnostics.Debug.Print(“Colour: ” + panel1.BackColor.ToString());
}
}

Best regards
Frank

 

  • You must to post comments
0
0

Thanks for the sample app (for the session timeout question) which works. However my sample (attached) does not. I cannot explain it except for the difference in how the task is run?

Nic

Attachment
  • You must to post comments
0
0

I have seen it working, we have several tests. I will send you one later on today.

Make sure the timer is ticking and *there is a handler attached* Basically every time there is a round trip all pending updates are sent back.

Best,

Luca

  • You must to post comments
0
0

Luca,

Just to update you on this. I’m still stuck on Windows 7 (new machine on order :)) so I tried the timer work around you suggested. It doesn’t appear to make any difference. I still do not see the changes made on the second thread. Maybe it just won’t work without websockets?

Nic

  • You must to post comments
0
0

Thanks Luca,

Given what you have said its probably because my development machine is still windows 7 so no websocket support. I’ll get on and build a new development machine on Windows 10 and see what happens.

Thanks again

Nic

  • You must to post comments
0
0

And make sure you don’t have

<httpProtocol allowKeepAlive=“true” />

In Web.config, as it was erroneously suggested to add it by me…

  • You must to post comments
0
0

It works here. Which means that you probably don’t have WebSocket enabled. In Chrome use F12 and Network and you will see that it never switches to WebSocket.

Apparently IIS 8 Express supports WebSocket but only from Windows 8 up: http://www.iis.net/learn/extensions/introduction-to-iis-express/iis-80-express-readme

Without WebSocket you can still update the client asynchronously but you need a request (any request) to be started from the client. If you add a Wisej Timer component to the form it will fire an event every interval and cause a client update. The thread code above will still work but the client will be updated at the timer interval.

  • You must to post comments
0
0

Forgot: you can also check using

Application.IsWebSocket

 

  • You must to post comments
0
0

Hi Nic,

I have just tried the sample you attached and it works fine here.

Did you try with the latest Wisej build ?

Best regards
Frank

  • Luca (ITG)
    It’s the WebSocket that is not enabled on Nic’s end.
  • You must to post comments
0
0

Hi Luca,

Thanks for the explanation and the sample but my test program (attached) stubbornly refuses to change the colour of my panel. Any chance you can tell me what I am doing wrong?

TIA

Nic

Attachment
  • You must to post comments
0
0

Hi Nic,

The background task sample uses Application.StartTask which internally restores the context before calling the task method. To use Application.Update() in a different thread other than the “request thread” (which has the session restored, including a reference to the ResponseManager connected to the WebSocket) you have to save the context and then restore it in the new thread.

The easiest way is to use a closure, change your  test code like this:

var context = Application.Context;
timer.Elapsed += (s, e) => {

  // restore the context on the current thread.
  using (new Wisej.Base.ApplicationContext(context))
  {
    // here you can call any other method, or place the code to run in the new thread, or a thread loop.

    // to test it I did this:
    Application.OpenForms[0].Text = Thread.CurrentThread.ManagedThreadId.ToString();

    // this works now because the context has been restored by the using statement.
    Application.Update();
  }
}



When running in the main (or request thread) you can call Application.Update() at any time and force the client to update. The downside of having long running operations in the request thread is that Wisej on the client side will automatically show a mask and a loading gif covering the control that fired the event and that is not receiving an answer within a certain amount of time.

HTH

Best,

Luca

  • You must to post comments
Showing 13 results