I want to show an alert dialog from a thread (for example when an error occur).
What is the best way to do that ?
I 've done that way :
My thread subclass have a method named “ShowError” that activate a timer :
[code] timer.Period = 10
timer.Mode = timer.ModeSingle
self.isWaiting = True
When this timer action fire, it call another method of my thread subclass “ErrorTimerAction” that raise a custom event “Error” :
self.isWaiting = False
My thread is added in a window. In the Error event of this instance of my thread, I show the alert dialog.
Is it the right way or must I change ? Can I use app.YieldToNextThread for that ?
I use CallMethodOnMainThreadMBS from the Monkeybread plugins.
On Window1 I have a method like this:
Sub MsgBoxMain(value1 As Variant)
In a thread I have code similar to this:
If imDatabase.Error Then
Dim msg As String = "ERROR : " + imDatabase.ErrorMessage
Call CallMethodOnMainThreadMBS (Window1, "MsgBoxMain", msg)
app.YieldToNextThread should not be needed.
Of course you can do a me.sleep(5) to put thread on sleep and give main thread a chance to show dialog.
I use a loop with app.YieldToNextThread in order to stop temporary the code execution, show the dialog and wait the user answer. Next, quitting the loop when self.isWaiting is False, I want to continue using the value of the user’s answer.
I think I can not achieve that with me.sleep.
Ah, yes, Christian, I see what your are saying. I’ve misunderstood the sleep method.
Do you say it’s better to use Thread.sleep then app.YieldToNextThread ?
I simply want my thread pause and wait the answer given by the user via my dialog and next, I want my thread continue in one or other direction according to this answer.
Is there a CPU usage, performance or stability advantage using Thread.sleep instead of app.YieldToNextThread ?
I have a second question : Currently, the timer action raise an event in witch the dialog is shown. Can I show the dialog directly in the timer action ? Is it allowed/stable ? In other words, does the Timer action fire in the custom thread or in the main thread. If this is in the custom thread, I suppose I can not, since we are not allowed to update the UI there.
Timers always fire in the main thread. Sleep is probably better in this case than Yield, as yield my end up returning immediately to your thread.
You can use suspend/resume:
In a timersubclass (we’ll call it messageTimer) we have 2 properties “mCaller as weakref” and “mMessage as String” and a method “ShowMessage”.
Sub ShowMessage(message As String)
if mCaller.Value<>nil then thread(mCaller.Value).Suspend
and in the Action Event…
if mCaller.Value<>nil then Thread(mCaller.Value).Resume
then it can be called like so.
dim mErrorTimer as new ErrorTimer
mErrorTimer.ShowMessage "An error ocurred"
//the thread will suspend here until the timer resumes it.
This approach also works well to get feedback from the user in the middle of a thread. You could add a result property to the timer subclass and set that from a dialog (rather than using msgbox), then the thread can look at the messageTimer.result to decide what to do next.
dim mMessageTimer as new messageTimer
mMessageTimer.ShowMessage "An error ocurred"
Your solution is simple, clear and, I think, more natural . I will go that way.
Thank you. And thank you all that help me find the best way.