locked
How to trigger function again from within a Task OnComplete callback.

    Question

  • Hi

    I'm making a Windows 8.1 Surface ( both RT and Pro ) app in C# and I'm using the Ink Recognizer class. While it is doing it's work, a user may draw more strokes, so I can't interrupt the recognizer, I need to fire it again once it is finished. But the recognizer must be called from the main thread, it has no marshalling, I can't see anyway to do this in the Win Store version. A Timer uses a background thread.

    private void DoRecognition()
            {
                bool workToDo;
                int i;
                GetWorkToDoAndWhichOne(out workToDo, out i);
                    if (workToDo && !m_IsRecognizing)
                    {
                        m_IsRecognizing = true;
                        m_needsToBeRegonized[i] = false;
    
                        var recognizers = m_InkManager[i].GetRecognizers();
                        m_InkManager[i].SetDefaultRecognizer(recognizers.First());
                        var task = m_InkManager[i].RecognizeAsync(InkRecognitionTarget.All);
                        task.GetAwaiter().OnCompleted(() =>
                        {
                            var recognitionResults = task.GetResults();

    I have 9 inputs, which are held in the array m_InkManager, m_needsToBeRegonized. Which keeps track of which of the 9 need updating. m_IsRecognizing is used as a global bool that the system is busy and it needs to wait till the next call.

    After results are processed with a bunch of code I want to call GetWorkToDoAndWhichOne again and if there is workToDo fire this function again.

    Seems in Normal c#, there is the Invoke keyword, but not in WS C#. Calling the function from inside the OnCompleted handler seems to dead lock. Although I see code in the forums for using RecogniszeAsync with an await it won't compile for me.

    How to I solve this pattern on WS c#?

    Sunday, July 27, 2014 11:55 AM

Answers

  • Since there is a very limited code that you have posted, I will try to put here a very generic approach to help

    using System;
    using System.Threading.Tasks;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Navigation;
    
    
    namespace MsdnSample21072014
    {
        public class Work
        {
            public bool WorkIsThere { get; set; }
    
            public int WorkItemId { get; set; }
        }
    
        public sealed partial class MainPage : Page
        {
            //This can be used to stop/cancel the task and also see the status.
            //To cancel use cancellation token which i have not used here
            private Task worker;
    
            public MainPage()
            {
                this.InitializeComponent();
    
                this.NavigationCacheMode = NavigationCacheMode.Required;
            }
    
            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                worker = start();
            }
    
            private async Task start()
            {
                while (true)
                {
                    Work work = await isThereSomeWork();
    
                    if (work.WorkIsThere)
                    {
                        bool result = await performWork(work);
                    }
    
                    await Task.Delay(10);
                }
            }
    
            private async Task<Work> isThereSomeWork()
            {
                Random random = new Random();
    
                Work work = new Work();
    
                //This is just a symbolic delay so that I can say this is long running async function
                await Task.Delay(1);
    
                //This is just to show this can read the UI.
                string text = message.Text;
    
                work.WorkIsThere = (random.Next(0, 10) > 5);
    
                if (work.WorkIsThere)
                {
                    work.WorkItemId = random.Next(0, 9);
                }
    
                return work;
            }
    
            private async Task<bool> performWork(Work work)
            {
                //This is just a symbolic delay so that I can say this is long running async function
                await Task.Delay(1);
    
                //This is just to show this can update the UI.
                message.Text = DateTime.Now.ToString();
    
                return true;
            }
        }
    }
    


    -- Vishal Kaushik --

    Please 'Mark as Answer' if my post answers your question and 'Vote as Helpful' if it helps you. Happy Coding!!!

    Monday, July 28, 2014 7:15 AM
  • Hi Icelandic Hitman,

    But the recognizer must be called from the main thread, it has no marshalling, I can't see anyway to do this in the Win Store version.

    You can use dispatcher.

    using Windows.ApplicationModel.Core;
    
    CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,() =>
        { // Your UI code here});
    --James


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.

    Monday, July 28, 2014 7:42 AM
    Moderator

All replies

  • Since there is a very limited code that you have posted, I will try to put here a very generic approach to help

    using System;
    using System.Threading.Tasks;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Navigation;
    
    
    namespace MsdnSample21072014
    {
        public class Work
        {
            public bool WorkIsThere { get; set; }
    
            public int WorkItemId { get; set; }
        }
    
        public sealed partial class MainPage : Page
        {
            //This can be used to stop/cancel the task and also see the status.
            //To cancel use cancellation token which i have not used here
            private Task worker;
    
            public MainPage()
            {
                this.InitializeComponent();
    
                this.NavigationCacheMode = NavigationCacheMode.Required;
            }
    
            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                worker = start();
            }
    
            private async Task start()
            {
                while (true)
                {
                    Work work = await isThereSomeWork();
    
                    if (work.WorkIsThere)
                    {
                        bool result = await performWork(work);
                    }
    
                    await Task.Delay(10);
                }
            }
    
            private async Task<Work> isThereSomeWork()
            {
                Random random = new Random();
    
                Work work = new Work();
    
                //This is just a symbolic delay so that I can say this is long running async function
                await Task.Delay(1);
    
                //This is just to show this can read the UI.
                string text = message.Text;
    
                work.WorkIsThere = (random.Next(0, 10) > 5);
    
                if (work.WorkIsThere)
                {
                    work.WorkItemId = random.Next(0, 9);
                }
    
                return work;
            }
    
            private async Task<bool> performWork(Work work)
            {
                //This is just a symbolic delay so that I can say this is long running async function
                await Task.Delay(1);
    
                //This is just to show this can update the UI.
                message.Text = DateTime.Now.ToString();
    
                return true;
            }
        }
    }
    


    -- Vishal Kaushik --

    Please 'Mark as Answer' if my post answers your question and 'Vote as Helpful' if it helps you. Happy Coding!!!

    Monday, July 28, 2014 7:15 AM
  • Hi Icelandic Hitman,

    But the recognizer must be called from the main thread, it has no marshalling, I can't see anyway to do this in the Win Store version.

    You can use dispatcher.

    using Windows.ApplicationModel.Core;
    
    CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,() =>
        { // Your UI code here});
    --James


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.

    Monday, July 28, 2014 7:42 AM
    Moderator
  • Thanks for the detailed response. Very useful to know.
    Thursday, July 31, 2014 9:59 AM
  • I knew from other posts Dispatcher was what I needed but they all showed it as being in another class. Thank you for showing me the full path. Very helpful.
    Thursday, July 31, 2014 10:00 AM