Skip to main content

Modal Workflow

WATCH & LEARN0:50 · Animated tutorial
7 scenesPlay, pause, or scrub at your own pace

In a program, a modal workflow is a mode of operation in which a particular task or feature must be completed before the user can proceed to other tasks or features. This is typically implemented by displaying a modal window or dialog box that requires user interaction before continuing.

Modal workflows are often used when users must complete specific tasks or provide required information. For example, a modal workflow might prompt users to save work before closing a document, or enter login credentials before accessing restricted areas.

Modal workflows help guide users through specific steps or highlight important actions. However, if overused, they can disrupt workflow.

In web applications, supporting modal workflow means:

  • Suspending server-side code execution
  • Waiting for user input
  • Resuming execution with received user information

While straightforward in desktop applications, this becomes challenging in web applications where code executes on the server and the UI runs asynchronously on different machines.

The code and images below demonstrate how Wisej.NET handles modal code execution:

void button1_Click(object sender, EventArgs e)
{
if (MessageBox.Show("Are you sure?", buttons: MessageBoxButtons.YesNo) == DialogResult.Yes)
{
this.button1.BackColor = Color.Green;
this.button1.Text = "You selected: Yes!";
}
}

Before clicking the button.

After clicking the button.

The server code pauses while the user makes a choice in the browser. When the user clicks Yes or No, execution resumes after the modal call, which returns the selected result.

After the user selected Yes.

Wisej.NET supports:

  • Nested modal states
  • Custom DialogResult values
  • Control references in modal dialogs
  • User input data access

Modal workflow works for MessageBox and forms (dialog boxes) with any type of control, data binding, and code-behind. The example above, modified to use a modal dialog, looks like this:

void button1_Click(object sender, EventArgs e)
{
using (new dialog = new EnterCustomerAddress())
{
if (dialog.ShowDialog(this) == DialogResult.OK)
{
AlertBox.Show(dialog.textBoxAddress.Text + " " + dialog.textBoxState.Text);
}
}
}

Regular modal dialogs or MessageBox controls suspend the current thread while waiting for user input. By default the system handles about 32,000 threads. While suspended, threads use no CPU time.

Async Modal Dialogs​

Wisej.NET fully supports the async/await programming pattern for modal dialogs.

Use await with ShowDialogAsync to wait for the dialog to close without keeping the calling thread blocked. Code after the await continues when the dialog returns its result.

info

The async version of MessageBox is MessageBox.ShowAsync(...).

void async button1_Click(object sender, EventArgs e)
{
using (new dialog = new EnterCustomerAddress())
{
if (await dialog.ShowDialogAsync(this) == DialogResult.OK)
{
AlertBox.Show(dialog.textBoxAddress.Text + " " + dialog.textBoxState.Text);
}
}
}

Asynchronous modal dialogs and message boxes do not keep a thread blocked while waiting for user input.

Custom Modal State​

You can implement modal behavior and wait for user input without using modal dialogs or MessageBox controls. Wisej.NET provides Application.DoModal(component) for this purpose.

For example, the PropertyGrid uses Application.DoModal() to suspend code flow while waiting for dropdown selection box closure. Use Application.EndModal(component, result) to terminate the last modal state - modal states are stacked.

// Open the combo box drop down list and wait
// for the user to select an item or close the combo box.
private void button1_Click(object sender, EventArgs e)
{
this.comboBox1.DroppedDown = true;
this.comboBox1.DropDownClosed += ComboBox1_DropDownClosed;
this.comboBox1.SelectedIndexChanged += ComboBox1_SelectedIndexChanged;

// wait for the user to either pick an item or close the drop down.
var result = Application.DoModal(this.comboBox1);

// code execution will resume here.
}

private void ComboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
this.comboBox1.DropDownClosed -= ComboBox1_DropDownClosed;
Application.EndModal(this.comboBox1, DialogResult.OK);
}

private void ComboBox1_DropDownClosed(object sender, EventArgs e)
{
Application.EndModal(this.comboBox1, DialogResult.Cancel);
}

The code above opens a dropdown and waits for user action. DoModal returns DialogResult.Cancel if closed without selection, or DialogResult.OK otherwise.

This provides powerful control over code execution and user action synchronization.

info

Application.DoModalAsync(component) will be added in a future build.