I’m working on a new Windows-specific app that runs for long periods and, at times, may need to pause and wait for a user decision.
I’m using the Task class interface to sync the thread and the UI and it works very well for the combination of a fast backend and keeping the UI interactive.
However, I can’t come up with a design that I feel comfortable with which will allow the threaded process to pause, display a user choice dialog, and then continue or exit depending on the user’s selection from the displayed dialog.
So far, my “least” problematic mechanism is to add a timer to the parent window to open the user selection dialog and set global properties to populate the displayed dialog and accept the user’s choice.
When the point in the loop for a decision occurs, I set the property values for the dialog, set the Boolean to watch for the user’s selection from the dialog, and then fire the open timer. In the thread, I pause in a sleep loop that looks like this:
Do
Me.Sleep(250, True)
Loop Until b_InputSelected
This all sounds logical as I type, but the real code feels like a total kludge.
Would it not be cleaner if the thread processing was split into two (before user input and after user input)?
The first thread would run the processing loop until user input was required.
At that point the thread loop would exit with the thread’s last command being whatever was required to invoke the user input on the main thread.
The second thread would then be started after all of the user input had been collected.
Depending on what you do before and after the user input, this probably doesn’t have to be two different thread classes. Just the same thread that has some state held in instance variables.
I personally would find it cleaner than pausing and resuming the thread. If the user input stage has the ability to abort then it would mean that you just don’t start the ‘after’ thread rather than having to kill the paused thread.
That’s the way I wrote the original code - the problem is that the rules changed in those 10 years :S
That can’t be done as the run is a loop and there’s no “do this before” and then “do this after” situation. It’s more like:
Do this very long process that must run contiguously
Prompt user to change CD
OK
Continue doing this
Prompt user to change CD
OK
Continue doing this
Prompt user to change CD
Cancel / or finished
Stop doing this
How would this work? In the Timer where I open the dialog call theThreadID.suspend and then after the input is satisfied call theThreadID.Resume? Does that guarantee that the pause will occur at a specific spot in the thread’s run loop?
So I call tmDisplayMessageDialog.Mode = 1 followed by me.Suspend? And then call theThreadID.Resume in the method that actually opens the dialog and accepts the user selection?
I tried that and it appears that the thread resumed at the top of the loop instead of on the next line in the loop since some of the logic following the pause did not execute.
Just in case it makes a difference, this is 17r1.1 on Windows 10.
Tim, the loop is the issue here. You should replace it by a C-style loop.
Static i = minvalue
if i < maxvalue then
//do stuff
else
i = minvalue
end if
You can exit such a loop at any time, and when you come back to it, it resumes where it was.
I would use a boolean window property called comeback or something like that, initiated when I pause the thread, so when I resume, I can test for it and go directly to the loop.
If not comeback then
// Do first half of the thread
//
//
comeback = True
end if
'// My loop
Static i as integer
i = minvalue
if i < maxvalue then
//do stuff
else
end if
That will enable you to stop the thread while the loop is executing, and when you come back to it, it simply continue where it was.
[quote]
That can’t be done as the run is a loop and there’s no “do this before” and then “do this after” situation. It’s more like:
Do this very long process that must run contiguously
Prompt user to change CD
OK
Continue doing this
Prompt user to change CD
OK
Continue doing this
Prompt user to change CD
Cancel / or finished
Stop doing this[/quote]
It should be quite easy to do that.
When you need to prompt the user, exit the loop and invoke the UI code on the main thread. If the user does not cancel you just run the thread again.
For this to work you will have to make some change to the code that runs in the thread:
a) Convert variables that hold important state from local variables to instance variables so that their values aren’t lost when the thread ends.
b) Move any initialisation out of the method that performs the looping into a separate function and call that function before you start the thread for the very first time.