Vixen
dd8b0a81
csharp
public sealed class DialogService

An application's modal questions: confirm, prompt, choose, and one it is handed.

Read the guide page for this →

Remarks

Drawn, not native, and doc 20 is explicit about why. A modal that is an OS window cannot be screenshotted by a golden-image suite and cannot be driven by a headless harness — so every question an application asks about its own state is a Dialog in its own document. A file picker is the opposite case and belongs to the platform: that one is about the user's disk rather than the application's state, and a drawn one has none of the places, tags or sandbox permissions a real picker carries.

⚠ Asynchronous, and the continuation runs on the frame loop. The answer is completed from Pump rather than from the click handler, so an await ConfirmAsync(…) resumes on the thread that owns the document, between two frames, with nothing half-dispatched underneath it. Nothing here posts to the thread pool and nothing here blocks — a dialog that blocked the loop would be a dialog that never drew.

⚠ The pump is the document's tick, and there is nothing to wire. The service subscribes to Ticked for its lifetime, so an application that calls Tick — which every host must, every frame, whether anything happened or not — has working dialogs without knowing this method exists. Update would have been the wrong half of the frame for the same reason CommandsInvalidated is not raised from it: it returns early when nothing dirtied the document, and a dialog being answered does not dirty one. Pump stays public because a test wants to step a frame's worth of dialog without a clock.

⚠ One at a time, and a second ask waits for the first. Two backdrops over each other is a picture with no answer in it: the lower dialog is visible, unreachable, and still holds the focus scope. Queued rather than refused, because the callers are commands and "your Save prompt was dropped because a rename was open" is the failure that loses work.

⚠ One thread, and never a blocking wait. Everything here happens on the thread that ticks the document; the returned Task`1 is completed from Pump and its continuations therefore run inline, on that thread, from inside Pump. So await is the only correct way to consume one: a caller that blocks on .Result or .Wait() blocks the thread that would have pumped the answer, and that is a deadlock rather than a slow frame. Re-entrancy is allowed and is the ordinary case — a command that answers one dialog by opening another is asking from inside Pump, and the new ask is presented later in the same call.

Fields and properties (3)

  • public Dialog? Current

    The dialog on screen, or .

  • public bool IsOpen

    Whether something is being asked.

  • public int Pending

    How many asks are waiting behind it.

Methods (9)

  • public DialogService(UiDocument document)

    Creates the service over a document, and hangs its pump on that document's tick.

  • public void Dispose()

    Answers everything outstanding and stops pumping.

  • public Task<bool> ConfirmAsync(string title, string? message = null, string? confirm = null, string? cancel = null, bool danger = false)

    Asks a yes-or-no question.

  • public Task<string?> PromptAsync(string title, string? message = null, string? initial = null, string? confirm = null, string? cancel = null)

    Asks for a line of text.

  • public Task<int> ChooseAsync(string title, string? message, params ReadOnlySpan<string> choices)

    Asks the user to pick one of several.

  • public Task<TResult?> ShowAsync<TResult>(string title, Action<DialogSession<TResult>> build, Func<TResult?>? dismissed = null)

    Shows a dialog a caller fills in.

  • public void Present(Dialog dialog, bool asking)

    Shows a dialog a panel owns for as long as the panel's own state says to.

  • public void Pump()

    Opens whatever is waiting, and completes whatever has been answered.

  • public void CancelAll()

    Answers the dialog on screen and everything queued behind it, and refuses more.

Used by (18)

  • ShellHelloUi
  • DialogTestsVixen.Ui.Controls.Tests
  • DocumentClosePromptVixen.Ui.Controls
  • DocumentClosePromptTestsVixen.Ui.Controls.Tests
  • StateDialogSheetVixen.Ui.Controls.Tests
  • StateDialogTestsVixen.Ui.Controls.Tests
  • AssetPickerVixen.Editor.App
  • AssetPickerTestsVixen.Editor.App.Tests
  • BrowserSavedFilterTestsVixen.Editor.App.Tests
  • ClosingTestsVixen.Editor.App.Tests
  • EditorApplicationVixen.Editor.App
  • EditorSessionVixen.Editor.Testing
  • EditorShellVixen.Editor.Ui
  • ExpiredRefusalTestsVixen.Editor.App.Tests
  • PartDVerbTestsVixen.Editor.App.Tests
  • ProjectBrowserTestsVixen.Editor.App.Tests
  • ScenarioTestsVixen.Editor.App.Tests
  • ThumbnailTestsVixen.Editor.App.Tests