Overview
A Workspace provides the execution context for WorkUnit instances in UI applications.
It is responsible for:
- executing one or more WorkUnits asynchronously
- integrating with the native Eyeshot progress bar
- handling cancellation initiated by the user
- managing execution lifecycle and status propagation
Workspace does not define the work itself.
Instead, it executes WorkUnit instances, adding UI integration and lifecycle management on top of the WorkUnit execution model.
Executing WorkUnits
A WorkUnit can be executed through a Workspace either synchronously or asynchronously.
Synchronous execution
workspace.DoWork(workUnit);This method:
- executes the WorkUnit synchronously on the calling thread
- invokes
WorkUnit.DoWork() - invokes
WorkUnit.WorkCompleted()upon successful completion
Synchronous execution is suitable for scenarios where blocking execution is acceptable, or when running in non-UI contexts.
Asynchronous execution (recommended for UI applications)
await workspace.DoWorkAsync(workUnit);DoWorkAsync is the recommended execution method in UI applications.
It:
- executes one or more WorkUnits asynchronously
- keeps the UI responsive during execution
- integrates with the native Eyeshot progress bar by default
- supports user-initiated cancellation
- returns a
Taskthat represents the execution lifecycle
When a WorkUnit is executed through a Workspace, the appropriate lifecycle method is invoked automatically based on the execution outcome:
- WorkCompleted on successful completion
- WorkCancelled if execution is cancelled
- WorkFailed if execution fails
Asynchronous execution example
The following example shows the recommended pattern for executing a WorkUnit asynchronously through a Workspace in a UI application.
private async Task ExecuteWorkUnitAsync(Workspace workspace, WorkUnit workUnit)
{
await workspace.DoWorkAsync(workUnit);
// The WorkUnit lifecycle hooks are invoked automatically
// by the Workspace execution pipeline
}In this scenario:
- progress reporting is handled automatically
- cancellation is driven by the UI
- lifecycle hooks do not need to be invoked manually
Executing multiple WorkUnits
Workspace.DoWorkAsync supports executing multiple WorkUnits as part of a single asynchronous operation.
await workspace.DoWorkAsync(workUnit1, workUnit2);Workspace also supports queuing additional WorkUnits when DoWorkAsync is invoked while another batch is still running.
If multiple calls are performed without awaiting completion, there is no guarantee on the order of execution among batches.
External progress reporting
Applications can provide a custom progress handler to update an external progress UI (for example, a custom progress bar) without relying on event-based notifications.
var progress = new Progress<WorkUnit.ProgressChangedEventArgs>(e =>
{
// Update custom progress UI
});
await workspace.DoWorkAsync(progress, workUnit);Progress can be reported through the provided handler while the native Eyeshot progress bar remains updated. To hide the built-in progress bar, set ProgressBar.Active to false.
External progress reporting (multiple WorkUnits)
var progress = new Progress<WorkUnit.ProgressChangedEventArgs>(e =>
{
// Update custom progress UI
});
await workspace.DoWorkAsync(progress, workUnit1, workUnit2);In the PaperDemo source code sample, you can find a practical example of the modern Workspace.DoWorkAsync execution model applied to multiple WorkUnits.
Progress bar integration
When executing WorkUnits asynchronously without providing an external progress handler, Workspace automatically:
- displays the native Eyeshot progress bar
- updates progress based on progress notifications
- handles UI thread marshaling
This eliminates the need for custom progress handling in most UI scenarios.
Cancellation support
Workspace provides built-in cancellation support.
When the user cancels an ongoing operation:
- the associated
CancellationTokenis triggered - the WorkUnit is expected to stop cooperatively
-
WorkUnit.WorkCancelledis invoked automatically - the returned
Taskcompletes in a cancelled state
Legacy execution model (deprecated)
The following APIs are part of the legacy event-based execution model and are deprecated:
Workspace.StartWork- Workspace execution events (
ProgressChanged,WorkCompleted,WorkCancelled,WorkFailed) WorkUnit.ProgressChangedWorkManager<T>ISupportWorkManager
For new development, prefer Workspace.DoWorkAsync and IProgress<T>-based progress reporting.
When to use Workspace
Use Workspace when:
- developing UI applications (WinForms or WPF)
- you want built-in progress bar integration
- user-driven cancellation is required
- you prefer standardized lifecycle handling
Use direct WorkUnit execution when:
- running in non-UI contexts
- full control over execution flow is required
- progress and cancellation are handled manually
Comments
Sounds great, but would it be possible to also call WorkFailed() for a synchronous execution that fails? That way, both asynchronous and synchronous execution could share the same basic error handling structure.
Hello Matthias,
Previously, Workspace events were raised during asynchronous execution through the legacy event-based pipeline. Synchronous execution, however, always relied on direct exception propagation.
In the latest Beta build, we have refined the execution model. Workspace.DoWorkAsync(...) is now fully Task-based and no longer raises Workspace events. The event-driven behavior remains available only through Workspace.StartWork(...), which is now marked as obsolete as part of the legacy model.
As a result, both synchronous execution and the new DoWorkAsync implementation surface failures through standard exception propagation (directly in synchronous calls, and through the awaited Task in asynchronous calls).
For this reason, we intentionally do not invoke WorkFailed() during synchronous execution, as the recommended execution model no longer relies on event-based notifications.
We have just published an updated Beta build and revised this article accordingly.
Please sign in to leave a comment.