Advanced Patterns
Common usage patterns for progress reporting, parallel tasks, events, error handling, cancellation and task chaining.
1. Progress reporting
Update loTask.Progress (0-100) from inside the task procedure. Read the value from the main thread using a Timer.
* Inside task procedure (MyTasks.prg):
PROCEDURE LongImport(loParams, loTask)
LOCAL i, lnTotal
lnTotal = loParams.rowCount
FOR i = 1 TO lnTotal
* ... process row i ...
loTask.Progress = INT((i / lnTotal) * 100)
NEXT
loTask.Result = TRANSFORM(lnTotal) + " rows imported."
ENDPROC * In main thread -- Timer event (interval 500 ms):
PROCEDURE Timer1_Timer
oProgressBar.Value = loTask.Progress
IF loTask.Status == "Done" OR loTask.Status == "Failed"
Timer1.Enabled = .F.
ENDIF
ENDPROC 2. Parallel tasks with RunAll
RunAll executes an array of procedure names in parallel, up to the MaxWorkers limit. It returns an array of Task objects.
LOCAL loCore, laProcs[3], loResults
loCore = CREATEOBJECT("FoxCore.FoxCoreClass")
loCore.MaxWorkers = 3
laProcs[1] = "Task_ImportFile"
laProcs[2] = "Task_GenerateReport"
laProcs[3] = "Task_SendEmails"
loResults = loCore.RunAll(@laProcs)
* loResults is an array of Task objects, one per procedure
? loResults[1].Status
? loResults[2].Status
? loResults[3].Status 3. Event callbacks
Assign a procedure name (as a string) to OnComplete, OnFailed or OnProgress before calling Run(). FoxCore invokes the procedure on the main thread when the event occurs.
LOCAL loCore, loParams, loTask
loCore = CREATEOBJECT("FoxCore.FoxCoreClass")
loParams = CREATEOBJECT("Empty")
ADDPROPERTY(loParams, "filePath", "C:dataimport.csv")
loTask = loCore.Run("Task_ImportCSV", loParams)
loTask.OnComplete = "HandleTaskDone"
loTask.OnFailed = "HandleTaskError"
loTask.OnProgress = "HandleProgress"
* ...
PROCEDURE HandleTaskDone(loTask)
MESSAGEBOX("Done: " + loTask.Result)
ENDPROC
PROCEDURE HandleTaskError(loTask)
MESSAGEBOX("Failed: " + loTask.Error)
ENDPROC
PROCEDURE HandleProgress(loTask)
oProgressBar.Value = loTask.Progress
ENDPROC 4. Error handling
If the task procedure throws an uncaught exception, the Task moves to Status="Failed" and loTask.Error contains the message. Always check status before reading Result.
loCore.WaitFor(loTask, 10000)
DO CASE
CASE loTask.Status == "Done"
? "Result: " + loTask.Result
CASE loTask.Status == "Failed"
MESSAGEBOX("Error: " + loTask.Error, 48, "Task Failed")
CASE loTask.Status == "Cancelled"
? "Task was cancelled."
ENDCASE 5. Cancellation
Call loCore.Cancel(loTask) to request cancellation. The Task moves to Status="Cancelled". The task should check status periodically if it wants to respond quickly.
* Request cancellation from main thread:
loCore.Cancel(loTask)
* Inside the task procedure -- check periodically:
PROCEDURE Task_LongProcess(loParams, loTask)
LOCAL i
FOR i = 1 TO 1000
IF loTask.Status == "Cancelled"
EXIT
ENDIF
* ... do work ...
loTask.Progress = i / 10
NEXT
IF loTask.Status != "Cancelled"
loTask.Result = "Completed."
ENDIF
ENDPROC 6. Sequential tasks
Use WaitFor() to chain tasks: the second task receives the result of the first as a parameter. This pattern is safe only outside UI events.
LOCAL loCore, loParams1, loParams2, loTask1, loTask2
loCore = CREATEOBJECT("FoxCore.FoxCoreClass")
loParams1 = CREATEOBJECT("Empty")
ADDPROPERTY(loParams1, "source", "https://api.example.com/data")
* Step 1: Fetch remote data
loTask1 = loCore.Run("Task_FetchData", loParams1)
loCore.WaitFor(loTask1, 15000)
IF loTask1.Status == "Done"
* Step 2: Process the fetched data
loParams2 = CREATEOBJECT("Empty")
ADDPROPERTY(loParams2, "data", loTask1.Result)
loTask2 = loCore.Run("Task_ProcessData", loParams2)
loCore.WaitFor(loTask2, 10000)
? loTask2.Result
ELSE
? "Fetch failed: " + loTask1.Error
ENDIF Next: API Reference ->