Dialogs and overlays
The system overlays — message boxes, the error box, the on-screen keyboard, the browser, and the save
picker — draw on top of the running application and are driven from the frame loop: open one, advance
it once per frame while you keep presenting, then read the result and dispose it. They all live in
SharpProspero.Platform. Toast notifications are the exception: they fire and forget.
On this page
The shared lifecycle
Every overlay dialog on this page follows the same shape. Opening it brings the shared dialog subsystem
up, loads the dialog’s own module, and starts the dialog, in that order. From there you call Update
once per frame and keep presenting the display, because the dialog only advances when you pump it. When
Update reports the dialog has closed, you read its outcome. Disposing shuts the dialog down and unloads
its module, except the browser, which leaves its module loaded. The message, error, keyboard and browser
overlays close the dialog first when it is still open; the save picker leaves that to its shutdown.
flowchart LR
A[Open / Show] --> B{Update once per frame}
B -->|Running| P[Present the frame]
P --> B
B -->|Finished / Closed| R[Read the result]
R --> D[Dispose]
A dialog that you stop updating never closes, and the frame stops presenting, so the whole application looks frozen. Keep the
Updateand present calls running until the dialog reports it is done, and wrap the object inusingso it always tears down.
Message dialogs
MessageDialog shows either a message with buttons or a progress bar the application drives. The
progress bar is what a package installer shows while it works.
Drive a progress bar with SetProgress (0 to 100), and change its caption at any time with
SetProgressMessage:
using var progress = MessageDialog.ShowProgress("Installing...");
while (installing)
{
progress.SetProgress(percentDone);
progress.Update();
display.Present();
}
Ask a question with ShowMessage and a MessageDialogButtons value — Ok, YesNo, or OkCancel.
Poll Update until it returns MessageDialogState.Finished, then read ChosenButton:
using var ask = MessageDialog.ShowMessage("Delete this file?", MessageDialogButtons.YesNo);
while (ask.Update() == MessageDialogState.Running)
display.Present();
bool yes = ask.ChosenButton == MsgDialogButtonId.Ok; // OK and Yes share the first button
ChosenButton is a MsgDialogButtonId (from SharpProspero.Interop.Dialog); its Ok value is the
first button, which stands in for both OK and Yes, and No is the second. MessageDialogState has just
two members, Running and Finished.
| Member | What it does |
|---|---|
ShowMessage(text, buttons, userId) |
Open a message with a button set and wait for a choice. |
ShowProgress(caption, userId) |
Open a progress bar the application drives. |
SetProgress(percent) |
Move the bar to 0-100 (clamped). |
SetProgressMessage(message) |
Replace the caption shown with the bar. |
Update() |
Advance the dialog and report Running or Finished. |
ChosenButton |
The button the user picked, once finished. |
Error dialogs
ErrorDialog presents the console’s own message for an error code, so a utility reports a failure the
way the system does rather than inventing its own wording. Show it for the code, then poll until it
closes.
using var dialog = ErrorDialog.Show(errorCode);
while (dialog.Update() != ErrorDialogState.Closed)
display.Present();
Show takes the integer error code and an optional user id. Update returns
ErrorDialogState.Running or ErrorDialogState.Closed.
Text input
TextInputDialog shows the on-screen keyboard and hands back what the user typed. This is the input
surface a file explorer, browser, or any interactive utility needs to let the user type. Open it, poll
until it closes, then read the text.
using var input = TextInputDialog.Open("Enter a name", maxLength: 64);
while (input.Update() == TextInputState.Running)
display.Present();
if (input.EndStatus == ImeDialogEndStatus.Ok)
Use(input.Text);
Open centres the keyboard on screen. maxLength runs from 1 to 2048 characters and defaults to 128.
Pass an ImeType to choose the layout (Url for a web address, and so on), a placeholder hint, an
initialText value, or an ImeOption — Password masks the field, and Multiline,
NoAutoCapitalization, ExternalKeyboard, NoLearning, FixedPosition and DisableCopyPaste shape
the rest of its behaviour. Poll Update until it returns
TextInputState.Finished, then check EndStatus: ImeDialogEndStatus.Ok means the user accepted the
text, which Text then returns. Text is empty until the keyboard finishes and empty when the user
cancelled. Defaulting userId picks the signed-in user.
A key on a USB keyboard is a position, not a letter. To read typed characters directly from a physical keyboard instead of the on-screen one, see the keyboard input surface and its keycode converter under Input.
The web browser
WebBrowser opens the system browser over the running application. Open it for an address, then poll
until it closes.
using var browser = WebBrowser.Open("https://example.com");
while (browser.Update() != WebBrowserState.Closed)
display.Present();
int result = browser.Result();
Update returns WebBrowserState.Running or WebBrowserState.Closed. Once closed, Result reads the
browser’s result code and throws when it cannot be read. Open takes the URL and an optional user id;
left unnamed, it opens for the user the console started with. The browser matches the id against the
signed-in users, so the system profile is refused — pass a real user id or none at all.
The save picker
SaveDataPicker shows the on-screen list of a user’s saves so the player can pick one, and reports
which they chose. It reads a bit differently from the others: poll TryGetResult, which returns
false while the dialog is still running and true once it finishes, setting the chosen directory (or
null when the user backed out).
using var picker = SaveDataPicker.OpenList(userId);
while (!picker.TryGetResult(out string? directory))
display.Present();
if (directory is not null)
Mount(directory);
OpenList takes the user id and a SaveDataDialogType (defaulting to Load; Save and Delete
change the wording). The Status property exposes the underlying CommonDialogStatus if you would
rather watch the state directly. This picker only chooses a save; mounting the chosen directory and
reading its files is the programmatic side covered in Save data.
Notifications
Notification shows the on-screen toast that slides in at the top of the screen — to confirm a copy,
report a finished install, or show a short message. It is a static call with no lifecycle to pump.
Notification.Show("Installed successfully.");
The message has to fit what a single request holds: 1023 bytes of UTF-8, which is fewer than 1023
characters for anything outside ASCII. Text that does not fit raises ArgumentException, and a refused
request raises ProsperoException. Notification also drives the persistent banner shown beside the
system button. That banner stays up until you take it down, so it suits a background task that should
stay visible while it runs:
Notification.ShowPsButtonBanner(); // optional JSON config: ShowPsButtonBanner("{...}")
// ... work continues, banner stays on screen ...
Notification.HidePsButtonBanner();
Notification.Showreturns immediately and needs no frame-loop pumping, unlike the overlay dialogs above. Pass it a JSON string toShowPsButtonBannerto configure the banner, or nothing for the default.
Whether any of these overlays is available depends on what the running module is permitted to do; see the System services overview for the permission notes.