locked
Wait for user input in middle of method

    Question

  • I have a method in the middle of which I want to give the user a chance to click one of several Buttons. Here is the basic design of the method:

    Private Sub MyMethod() 'Code before I need extra input 'This is where I want to wait for the user to click a Button 'This is where I will be using the results from the clicked Button 'The waiting for input and using the results will happen multiple times inside a loop End Sub


    The code is in a loop, so exiting the method and putting the rest of the code in the Button handler would not be appropriate. How can I ask the user for input and then return that input to the method where I left? I seem to be tempted to use some kind of async method, but since the input will be coming from the user (not another method), that doesn't seem like it would be right (but I don't have a huge amount of experience with async, so I could be wrong about that). Can anybody help me? Thanks.

    Nathan Sokalski njsokalski@hotmail.com http://www.nathansokalski.com/

    Wednesday, April 29, 2015 10:33 PM

Answers

  • Hi Nathan,

    You're on the right track: you'll need to await an Async function to put a delay in the middle of your method. The button click will notify the async function to finish.

    You could write a custom function which returns a Task and waits for the notification from the button:

    Task WaitForButtonClickAsync()
    {
         // wait for button click
    }
    

    and then await that in your main function:

    async void BigNastyFunction()
    {
        // .... 
        await WaitForButtonClickAsync();
        // ....
    }

    The next question is how to let the button click notify WaitForButtonClickAsync to return.

    We could spin up a worker thread and have it block waiting on a notification, but there is no need to complicate things like that: WaitForButtonClickAsync can just return Task.Delay(timeout, cancellation token) and then when the button click handler fires it can cancel the delay.


    See Asynchronous Programming with Async and Await and Async Cancellation: Bridging between the .NET Framework and the Windows Runtime for more information on cancelling a task.

    Thursday, April 30, 2015 7:44 PM
    Owner
  • The first argument to Task.Delay is how long to wait. You're setting a 0 second delay. You probably want something substantially longer.

    Friday, May 1, 2015 1:15 AM
    Owner

All replies

  • I will ask about it.


    I sale myself ONLY half CNY!

    Thursday, April 30, 2015 1:53 PM
  • Hi Nathan,

    You're on the right track: you'll need to await an Async function to put a delay in the middle of your method. The button click will notify the async function to finish.

    You could write a custom function which returns a Task and waits for the notification from the button:

    Task WaitForButtonClickAsync()
    {
         // wait for button click
    }
    

    and then await that in your main function:

    async void BigNastyFunction()
    {
        // .... 
        await WaitForButtonClickAsync();
        // ....
    }

    The next question is how to let the button click notify WaitForButtonClickAsync to return.

    We could spin up a worker thread and have it block waiting on a notification, but there is no need to complicate things like that: WaitForButtonClickAsync can just return Task.Delay(timeout, cancellation token) and then when the button click handler fires it can cancel the delay.


    See Asynchronous Programming with Async and Await and Async Cancellation: Bridging between the .NET Framework and the Windows Runtime for more information on cancelling a task.

    Thursday, April 30, 2015 7:44 PM
    Owner
  • That is definitely very information, but I'm obviously still doing something wrong after looking at it, since my code is still not waiting for me to make a selection. Here is my current code.

    My main function:

    Private Async Sub PlayCards() 'Create a new CancellationTokenSource() Me.selectrowcancel = New CancellationTokenSource() 'Wait for Me.selectedrow to be set by Row_Tapped Try : Await Me.WaitForRowSelection() Catch op As OperationCanceledException : System.Diagnostics.Debug.WriteLine(op.Message) Catch ex As Exception : System.Diagnostics.Debug.WriteLine(ex.Message) End Try System.Diagnostics.Debug.WriteLine("Me.selectedrow: {0}", Me.selectedrow) End Sub


    The function that waits for the button click:
    Private Function WaitForRowSelection() As Task
    	Return Task.Delay(0, Me.selectrowcancel.Token)
    End Function

    The handler for the Button:
    Private Sub Row_Tapped(sender As Object, e As TappedRoutedEventArgs)
    	Me.selectrowcancel.Cancel()
    	Me.selectedrow = Grid.GetRow(CType(sender, Card))
    End Sub

    Like I said, I am new to this area of code, so I may have misunderstood or incorrectly written what you said, but it is not waiting for me to select a row at this point. What is wrong in my code?

    Nathan Sokalski njsokalski@hotmail.com http://www.nathansokalski.com/

    Friday, May 1, 2015 12:13 AM
  • The first argument to Task.Delay is how long to wait. You're setting a 0 second delay. You probably want something substantially longer.

    Friday, May 1, 2015 1:15 AM
    Owner
  • That may have been what was confusing me. I want to wait until the user clicks a Button, not a specified amount of time. I replaced the WaitForRowSelection method with:
    Private Function WaitForRowSelection() As Task
    	Return Task.Delay(-1, Me.selectrowcancel.Token)
    End Function

    And it seems to have fixed it (the -1 represents forever, right?). Thanks!

    Nathan Sokalski njsokalski@hotmail.com http://www.nathansokalski.com/

    Friday, May 1, 2015 2:08 AM