RobWarning
Posts: 6
Joined: Fri May 15, 2015 8:47 am

Synchronizing with ui tread

Mon Aug 31, 2015 10:55 am

Hi,
I am trying to build a wind speed sensor. For this I Count te amount of interrupts on a gpio pin that is configured as input in a certain time period.
At the end of this period I like to show the count value in a textbox on the UI.

private void InitAnemoTimer()
{
Anemotimer = new System.Threading.Timer(_ => OnAnemoTimerCallBack(),null, 0, Timer_Constante);
}

private void Windpin_ValueChanged(GpioPin sender, GpioPinValueChangedEventArgs args)
{
if (args.Edge == GpioPinEdge.FallingEdge)
{
windcounter=windcounter+1; //Every windpuls increment the counter.
}
}

private void OnAnemoTimerCallBack()
{
wind = windcounter; //Calculates wind
//windBox.Text = wind.ToString(); //show in texbox: this is not working
windcounter = 0; //Reset windcounter
Anemotimer.Change(0, Timer_Constante); //restarts the timer
}


On problem is that the UI is on a different tread than the system treading timer.
How can I synchronize these treads?

GerritV
Posts: 91
Joined: Fri May 01, 2015 4:16 pm
Location: St Catharines, ON
Contact: Website

Re: Synchronizing with ui tread

Mon Aug 31, 2015 1:08 pm

You can have the main thread/object (ui) register for an event and then in your gpio thread raise an event. You decide what data to pass, even an object.

Read up on RaiseEvent and AddHandler

beta-tester
Posts: 1198
Joined: Fri Jan 04, 2013 1:57 pm
Location: de_DE

Re: Synchronizing with ui tread

Mon Aug 31, 2015 2:16 pm

you can make a call within the ui thread context, by use Windows.UI.Core.CoreDispatcher.RunAsync()
use the dispatcher of the UI element (MainPage)
{ I only give negative feedback }
RPi Model B (rev1, 256MB) & B (rev2, 512MB) & B+, RPi2B (1GB), 64GB microSDXC1 class 10, HDMI 1920x1080, keyboard-mouse-combo (wireless), PiCamera, ethernet-cable, 5V/1.2A power supply, Wifi dongle (rt5370)

haroldpulcher
Posts: 58
Joined: Tue Jun 09, 2015 8:08 pm
Contact: Website

Re: Synchronizing with ui tread

Mon Aug 31, 2015 2:56 pm

For an example bit code you want todo something like:

Code: Select all

            var task = this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
                 winBox.Text = windcounter.ToString();
            });
Last edited by haroldpulcher on Mon Aug 31, 2015 4:47 pm, edited 1 time in total.

RobWarning
Posts: 6
Joined: Fri May 15, 2015 8:47 am

Re: Synchronizing with ui tread

Mon Aug 31, 2015 4:34 pm

Hi Haroldpulcher,

thanks for your code example.
unfortunately this is not working for the raspberry 2 on IOT. The var and Dispatcher objects are not available.
There is the CoreDispatcher class available. Maybe I can use this but I am struggling with the syntax.
I also do not see how to call this “task” from my OnAnemoTimerCallBack routine?

haroldpulcher
Posts: 58
Joined: Tue Jun 09, 2015 8:08 pm
Contact: Website

Re: Synchronizing with ui tread

Mon Aug 31, 2015 4:48 pm

Try putting the keyword "this" in front of the Dispatcher.

I left that off for some reason in my example.

haroldpulcher
Posts: 58
Joined: Tue Jun 09, 2015 8:08 pm
Contact: Website

Re: Synchronizing with ui tread

Mon Aug 31, 2015 4:50 pm

You can also checkout a bit of code thatI am using to demo in my talks at: https://github.com/pulcher/iot-demos

Check the "pushPotBlink" solution. Not the best code, but it does work.

RobWarning
Posts: 6
Joined: Fri May 15, 2015 8:47 am

Re: Synchronizing with ui tread

Mon Aug 31, 2015 5:07 pm

Ok, I suppose I have to do something like this:

Code: Select all

 private void OnAnemoTimerCallBack()
        {
            wind = windcounter;  //Calculates wind
            //windBox.Text = wind.ToString(); //show in texbox 
            this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
            {
                windBox.Text = windcounter.ToString();
            });
            windcounter = 0;  //Reset windcounter
            Anemotimer.Change(0, Timer_Constante); //restarts the timer
        }
When I do this I get the warning : Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the “Await” operator to the result of the call.
A quick fix is proposed but when I accepts that I get this:

Code: Select all

  private void OnAnemoTimerCallBack()
        {
            wind = windcounter;  //Calculates wind
            await
                        //windBox.Text = wind.ToString(); //show in texbox 
                        this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                        {
                            windBox.Text = windcounter.ToString();
                        });            windcounter = 0;  //Reset windcounter
            Anemotimer.Change(0, Timer_Constante); //restarts the timer
        }
and I get a compile error stating that the await operator can only be used within a async methode.

RobWarning
Posts: 6
Joined: Fri May 15, 2015 8:47 am

Re: Synchronizing with ui tread

Mon Aug 31, 2015 5:12 pm

Got It !

Code: Select all

 private async void OnAnemoTimerCallBack()
        {
            wind = windcounter;  //Calculates wind
            await
                        //windBox.Text = wind.ToString(); //show in texbox 
                        this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                        {
                            windBox.Text = windcounter.ToString();
                        });
            windcounter = 0;  //Reset windcounter
            Anemotimer.Change(0, Timer_Constante); //restarts the timer
        }
       
thank you very much putting me on this solution. I only wish I did understand it a little bit better. :roll:

GerritV
Posts: 91
Joined: Fri May 01, 2015 4:16 pm
Location: St Catharines, ON
Contact: Website

Re: Synchronizing with ui tread

Mon Aug 31, 2015 11:27 pm

A lot of overhead and complexity when raising an event is what you really needed. :-) Because in essence you are blocking your timer thread until the await is satisfied. Might or might not have repercussions from that, such as missed counts.

haroldpulcher
Posts: 58
Joined: Tue Jun 09, 2015 8:08 pm
Contact: Website

Re: Synchronizing with ui tread

Tue Sep 01, 2015 12:34 am

I believe it is actually the other way around.

The RunAsync command fires an event with a payload to the UI thread and returns. So you code goes merrily one.

If you were to put a "AsTask().Wait()" on the end of that, then that call will wait till the UI thread is done.

For a better explanation checkout: https://social.msdn.microsoft.com/Forum ... withcsharp

GerritV
Posts: 91
Joined: Fri May 01, 2015 4:16 pm
Location: St Catharines, ON
Contact: Website

Re: Synchronizing with ui tread

Tue Sep 01, 2015 1:42 am

RunAsync doesn't fire events,

Events are less troublesome and lighter weight although what you suggest will probably solve his problem.

This is what happens on Await : https://msdn.microsoft.com/en-us/library/hh191443.aspx

I think you will find events much easier to get your head wrapped around. I use both, but async/await I use for file operation etc that might take a long time (and block the UI from getting time to run)

There are as usual multiple solutions and preferences :-)

beta-tester
Posts: 1198
Joined: Fri Jan 04, 2013 1:57 pm
Location: de_DE

Re: Synchronizing with ui tread

Tue Sep 01, 2015 8:28 pm

RobWarning wrote:Hi Haroldpulcher,

thanks for your code example.
unfortunately this is not working for the raspberry 2 on IOT.
maybe that is more useful to you
do this in your MainPage

Code: Select all

        private void Page_Loaded(object sender, RoutedEventArgs e)
        {
                timer = new Windows.UI.Xaml.DispatchTimer();
                timer.Tick += Timer_Tick;
                timer.Interval = TimeSpan.FromMilliseconds(1000.0);
                timer.Start();
        }

        private void Timer_Tick(object sender, object e)
        {
                // do something in UI thread context
                // e.g. polling your values you want to display on UI
        }
otherwise you have to take the Dispatcher of the UI element you want access to (of your MainPage for example).
if you use a "standalone" none-UI-thread, you can pass the Dispatcher of the UI element to your thread, to be able to access to the Dispatcher to execute/access to UI properties via RunAsync...
and by the way, nobody force you to use "RunAsync()" with "await"...
you can use it without await as well... and in that case it is not blocking the UI thread... that's because it is called async ;)
only in case you need to lineup executions in correct order (because the result od the execution is needed for the followed execution), the easiest way to do so is using "await", but it is indeed not always the best idea then.

and "var" should be available, as long you use all needed references and usings.
GerritV wrote:You can have the main thread/object (ui) register for an event and then in your gpio thread raise an event. You decide what data to pass, even an object.

Read up on RaiseEvent and AddHandler
GerritV wrote:A lot of overhead and complexity when raising an event is what you really needed. :-) Because in essence you are blocking your timer thread until the await is satisfied. Might or might not have repercussions from that, such as missed counts.
an event does not necessarily executes in UI thread context, in case you build your own events from within none-UI-context-threads... in that case you have to switch your execution into UI thread context first to do UI element access via one of the RunAsync calls from an UI elements Dispatcher.
{ I only give negative feedback }
RPi Model B (rev1, 256MB) & B (rev2, 512MB) & B+, RPi2B (1GB), 64GB microSDXC1 class 10, HDMI 1920x1080, keyboard-mouse-combo (wireless), PiCamera, ethernet-cable, 5V/1.2A power supply, Wifi dongle (rt5370)

Return to “Windows 10 for IoT”

Who is online

Users browsing this forum: No registered users and 3 guests