none
Win RT : Awaiting the Dispatcher.RunAsync()

    Question

  • In trying to re-create code models I have done in Windows 7 WPF I'm running accoss a scenario thats not working out.

    All the new info about running asyncronously in RT is fine but focuses on a model where the GUI thread initiates a request, and when the request is fufilled the thread returns back to the GUI thread. Thats great but I have a model where my non-GUI thread is running in a loop forever and needs to make updates into the GUI thread.

    In W7/WPF I can can update back to the GUI thread by creating an action and passing in an object array of paramters then execute via Dispatcher.BeginInvoke(action,paramters)

    I wanted to do same in RT but nto an option. I was able to put together a program that gets most of the way there but has some problems.

    using Dispatcher.RunAsync(priority, delegate(some_function)) I am able to call updates to the GUI but has some problems. It non-GUI thread does not block waiting for the update to return. Visual Studio is outright giving me a code warning that it will not, and that I should 'consider applying await operater to the result of the call' I tryied a few things but I cannot seem to get the sytax right. What is the correct syntax to get the non-GUI thread to block while it calls the GUI thread to update?

    Also, how do I pass in parameters to the call the to dispatcher.RunAsync() ?

    When I setup this test originally the program ran ok, but as I added complexity to the GUI update call and made it take longer, the program would crash. The error that comes out of that is "WinRT information : Invoke request processing error" I assume that if I can get the GUI update call to block that I wont get this.

    I have sudo sovled that problem right now adding a call to 'Wait(30)' on the 'task'. But this is not a good solution as the wait time is a guess and is wasting my proc cycles.

    Thanks,

    Matt

    Tuesday, May 22, 2012 5:50 PM

Answers

  • Hi Matt,

    You would call Task.Wait from the non-GUI thread and it will wait until Dispatcher.RunAsync's Task has finished running. This essentially makes the RunAsync call synchronous. The UI thread doesn't need to do anything to trigger it other than exit out of the end of the delegate. Depending on your specific calling pattern you could also await the Task, but that would allow your function's caller to continue without blocking.

    Here is a code snippet to demonstrate it: Item 1 will always occur before Item 2.

    Dispatcher.RunAsync(CoreDispatcherPriority.Norma, new DispatchedHandler( () =>
    {
        // update the UI
        // Item 1
    })).AsTask().Wait();
    // Item 2

    If you just call Dispatcher.RunAsync without calling AsTask().Wait(); then this is completely asynchronous and Item 2 may occur before Item 2.

    Here is a similar code-snippet to the previous one demonstrating storing the handler function in an object which can package up arguments:

    internal class ArgumentObject
    {
       public string text;
       public TextBlock textBlock;
    
       public void OnDispatched()
       {
           textBlock.Text = text;
       }
    }
    
    ArgumentObject ao = new ArgumentObject();
    o.text = "Test output";
    o.textBlock = this.textBlock; // control in our Xaml page
    Dispatcher.RunAsync(
        CoreDispatcherPriority.Normal,
        new DispatchedHandler(ao.OnDispatched)
    ).AsTask().Wait();
    
    
    --Rob

    Thursday, May 24, 2012 9:38 PM
    Owner

All replies

  • Since you're on a background thread you can call Task.Wait() to wait indefinitely until the task completes. You don't need to include the timeout.

    The DispatchedHandler delegate doesn't take any parameters do you can't pass any parameters directly. You can work around this by creating an class with the data you need and call a delegate within an instance of that class. Essentially, you pass the method to the data rather than the data to the method.

    --Rob

    Wednesday, May 23, 2012 12:29 AM
    Owner
  • Rob thanks for post, but not seeing your solution.

    If I call task.wait from the GUI thread the Non-GUI thread will execute until the GUI has a chance to call it, which does not garuentee the task will be waited at the moment i want it too. If I call task.wait from inside the Non-GUI thread I will need to resume it from the GUI thread when my updates are done and that seems pretty hokie,, a step backwards from current capabilities.

    Is there not a synchronous calll I can make from the NON-GUI thread to update the GUI thread,, OR is there not a way to make Dispatcher.RunAsync block until the called function completes?

    I know there is a Dispatcher.Invoke() but I am not able to figure out the syntax of how to use it, but looks promising....

    Thanks,

    Matt

    Wednesday, May 23, 2012 3:11 PM
  • Hi Matt,

    You would call Task.Wait from the non-GUI thread and it will wait until Dispatcher.RunAsync's Task has finished running. This essentially makes the RunAsync call synchronous. The UI thread doesn't need to do anything to trigger it other than exit out of the end of the delegate. Depending on your specific calling pattern you could also await the Task, but that would allow your function's caller to continue without blocking.

    Here is a code snippet to demonstrate it: Item 1 will always occur before Item 2.

    Dispatcher.RunAsync(CoreDispatcherPriority.Norma, new DispatchedHandler( () =>
    {
        // update the UI
        // Item 1
    })).AsTask().Wait();
    // Item 2

    If you just call Dispatcher.RunAsync without calling AsTask().Wait(); then this is completely asynchronous and Item 2 may occur before Item 2.

    Here is a similar code-snippet to the previous one demonstrating storing the handler function in an object which can package up arguments:

    internal class ArgumentObject
    {
       public string text;
       public TextBlock textBlock;
    
       public void OnDispatched()
       {
           textBlock.Text = text;
       }
    }
    
    ArgumentObject ao = new ArgumentObject();
    o.text = "Test output";
    o.textBlock = this.textBlock; // control in our Xaml page
    Dispatcher.RunAsync(
        CoreDispatcherPriority.Normal,
        new DispatchedHandler(ao.OnDispatched)
    ).AsTask().Wait();
    
    
    --Rob

    Thursday, May 24, 2012 9:38 PM
    Owner
  • Hey,

    I want to use Dispatcher.RunAsync as asynchronous call. In that case how should I remove the warning?

    Thursday, June 21, 2012 3:07 AM
  • IAsyncAction asyncAction = Dispatcher.RunAsync(
                                CoreDispatcherPriority.Normal,
                                new DispatchedHandler(ao.OnDispatched)
                            ); // removes the warning

    Dispatcher.RunAsync(CoreDispatcherPriority.Normal, new DispatchedHandler(ao.OnDispatched)).AsTask(); // equally removes warning


    Thursday, June 21, 2012 5:45 AM