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
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:
In all other cases it’s not necessary anymore.
Best,
Luca
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
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
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
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
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
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
And make sure you don’t have
<httpProtocol allowKeepAlive=“true” />
In Web.config, as it was erroneously suggested to add it by me…
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.
Forgot: you can also check using
Application.IsWebSocket
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
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
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