NE.Standard

Dialogs and notifications

A dialog is declared by the view and rendered closed by the shell; a controller or an interaction opens and closes it by key. Notifications are a client effect with nowhere of their own on the tree — they stack up in a corner the view chooses.

Declaring a dialog

Override CreateDialogs() on the view and return a list of UIDialog:

protected override IReadOnlyList<UIDialog> CreateDialogs()
    => [
        new UIDialog
        {
            Key = DialogTestController.ConfirmKey,
            CloseOnBackdrop = false,
            CloseOnEscape = false,
            Content = CreatePanel("Delete this build?", ...,
                CreateButtons(
                    CreateButton("Cancel", nameof(DialogTestController.KeepBuild), UIButtonType.Ghost),
                    CreateButton("Delete", nameof(DialogTestController.DeleteBuild), UIButtonType.Danger)
                )
            )
        }
    ];

UIDialog:

Member Meaning
Key stable string a command or interaction opens/closes it by
Content the root component of the dialog's body
Surface (UISurfaceStyle) what the panel is made of — Background, Raised (default), Tinted
Placement (UIDialogPlacement) Center (default), or a full-length sheet against Left, Right, Top, Bottom
Modal whether it blocks interaction with the view underneath (default true)
CloseOnBackdrop whether clicking the backdrop closes it (default true)
CloseOnEscape whether Escape closes it (default true)

A destructive confirmation turns both CloseOnBackdrop and CloseOnEscape off, so only its own buttons answer it. A non-modal sheet (Modal = false) at an edge, drawn on Surface = Background, is the shape a filter drawer or a side panel takes — the page keeps working beside it.

Opening and closing

From a controller, Context.Dialogs (IUIDialogService):

_ = await Context.Dialogs.ShowAsync(Context.Handle, ProgressKey, cancellationToken).ConfigureAwait(false);
// ... work ...
_ = await Context.Dialogs.HideAsync(Context.Handle, ProgressKey, cancellationToken).ConfigureAwait(false);

ShowAsync/HideAsync push straight to the connection, so the dialog stands open for exactly as long as the command takes — the pattern for a wait dialog nothing on its own body dismisses.

A command can instead return the effect, which is the more common shape when opening or closing is the whole of what the command does:

[UICommand]
public UICommandResult OpenFilters()
    => UICommandResult.Ok([new OpenDialogEffect(FiltersKey)]);

[UICommand]
public UICommandResult SaveEdit()
{
    // ... write the draft back ...
    return UICommandResult.Ok([new CloseDialogEffect(EditKey), new ShowNotificationEffect($"Saved '{Name}'.", UIColorStyle.Success)]);
}

OpenDialogEffect(dialogKey) and CloseDialogEffect(dialogKey) both take just the key. An interaction can raise the same effects directly, with no round trip to the controller at all — see the interactions guide.

Notifications

ShowNotificationEffect(string message, UIColorStyle severity = UIColorStyle.Info) raises a toast:

return UICommandResult.Ok([new ShowNotificationEffect("Build #481 published.", UIColorStyle.Success)]);

Severity is a UIColorStyleInfo, Success, Warning, Danger are the ones the demo uses. Where a view's notifications stack is UIViewOptions.NotificationPlacement (UINotificationPlacement: Bottom — the default — or Top), set once for the view rather than per notification.

When a command fails on its own

The client never reads a raw success/failure flag — both the invoke return and the push channel only apply changes and effects. So a command that throws, or is refused by an authorization check, and returns no effects of its own gets one attached automatically: a ShowNotificationEffect built from UIErrorHandlingOptions, configured through ConfigureErrorHandling:

builder.ConfigureErrorHandling(errors =>
{
    errors.NotifyOnCommandFailure = true;
    errors.IncludeExceptionDetail = false;
    errors.CommandRefusedMessage = "You are not allowed to do that.";
    errors.CommandFailedMessage = "Something went wrong. Please try again.";
    errors.ErrorRoute = "/error";
    errors.NotFoundRoute = "/not-found";
});
Option Meaning
NotifyOnCommandFailure whether a failed command with no effects of its own is reported at all (default true)
IncludeExceptionDetail whether the real exception message reaches the browser — off by default, since an exception routinely carries a connection string, a table name or a file path
CommandRefusedMessage shown for an UnauthorizedAccessException
CommandFailedMessage shown for any other exception, unless IncludeExceptionDetail is on
ErrorRoute where an unhandled exception resolving a view goes; a failing command is reported in place, never routed here
NotFoundRoute where a request for an unregistered route goes

Returning your own effects from a failing command is how it takes over the reporting — the automatic notification only fires when a command's result carries none. All three messages go through the translator, so an application overrides them by localization rather than by re-implementing the mechanism.