question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Proposal: Improve ContentDialog API and Prevent Crashes

See original GitHub issue

Proposal: Improve ContentDialog API and Prevent Crashes (applies to MessageDialog as well)

Multiple ContentDialog instances are not supported which leads to crashes when the app attempts to open the second one. While the framework does not support multiple dialogs, it also does not provide a reliable way for closing/detecting an already open one. This creates a bad combination for application developers.

To make this more robust we need two things:

  1. Provide a rock-solid API for the app to manage already open ContentDialogs/MessageDialogs
  2. Allow multiple ContentDialogs (and, if possible and not removed from the platform, MessageDialogs) to be displayed on top of each other (like classic Windows allows) and make it the responsibility of the App to manage them correctly. This is only to prevent crashes when the app doesn’t manage things correctly – it’s a fail-safe for robustness.

Note: Number 2 would be difficult to do on mobile platforms with the Uno architecture. (We’ll see how WinUI evolves for Surface Duo!)

Summary

  1. Provide a rock-solid API for the app to manage already open ContentDialogs.

// As named, returns true if a ContentDialog is already open
Application.IsContentDialogOpen

// Will not directly close the ContentDialog but will synchronously return a reference 
// to it so the application developer can decide how best to close it.
Application.GetOpenContentDialog() 

// Overload to ShowAsync() to specify what to do if a ContentDialog is already open
ContentDialog.ShowAsync(HandleExistingDialogOption existingDialogOption) 

enum HandleExistingDialogOption
{
    /// <summary>
    /// Closes any already open dialog and returns ContentDialogResult.None 
    /// (or an empty command for MessageDialog)
    /// </summary>
    CloseExisting, 

    /// <summary>
    /// Does not show the new dialog and immediately returns ContentDialogResult.None
    /// (or an empty command for MessageDialog)
    /// </summary>
    DoNotShow,

    /// <summary>
    /// Dialog will be enqueued and shown once all previous dialogs are closed.
    /// </summary>
    Enqueue
}
  1. As stated, allow multiple ContentDialogs to be displayed on top of each other

Remove the platform restriction of only one ContentDialog being open. Also definitely prevent a hard-crash if the application attempt to open a second. Two ContentDialogs is understood to be bad practice but there are some edge cases this helps protect against. Number 1 is still the primary solution.

Rationale

Currently, only one content dialog can be open at a time in the UI. This makes sense as it’s meant to be blocking waiting for user input.

However, there are some scenarios where notifications are being sent from the backend to the frontend (not as a result of direct user input) and they should be displayed in a blocking content dialog to the user.

The problem occurs when multiple notifications are sent from the backend and the user hasn’t yet closed the first one. In this case the app crashes when it tries to create the second ContentDialog. As a work around, apps can attempt to close dialogs themselves; however, this does not always work. If a request to open a content dialog comes fast enough a crash still occurs.

Applications should not crash so easily when opening a ContentDialog. Work-arounds such as the example code below are not reliable as they are somewhat dependent on timing.

    public static bool IsContentDialogOpen(Window window = null)
        {
            // By default use the current window
            if (window == null)
            {
                window = Window.Current;
            }

            // Get all open popups in the window. A ContentDialog is a popup.
            var popups = VisualTreeHelper.GetOpenPopups(window);

            foreach (var popup in popups)
            {
               if(popup.Child is ContentDialog)
               {
                  // A content dialog is open
                  return (true);
               }
            }

            return (false);
        }

or

var popups = VisualTreeHelper.GetOpenPopups(Window.Current);
foreach(var popup in popups)
{
    if (popup.Child is ContentDialog)
    {
        ((ContentDialog)popup.Child).Hide();
    }
}

Issue Analytics

  • State:open
  • Created 4 years ago
  • Reactions:16
  • Comments:18 (17 by maintainers)

github_iconTop GitHub Comments

7reactions
robloocommented, Nov 27, 2019

@mrlacey We could talk about application architecture endlessly but that would be a bit out of scope I think. However, since you are curious here is the full scenario:

  • User starts a search which runs in the backend (Here it is possible to press ‘Enter’ very rapidly in the frontend and schedule two searches one after the other. Yes, that could be changed/filtered but complexity goes up a lot compared to just allowing it.)
  • The backend completes the first search but finds no results. It notifies the frontend that ‘Search is complete with no results’
  • The frontend displays the confirmation ContentDialog ‘Search is complete with no results’. The user does nothing (and has no chance to due to the speed)
  • The backend completes the second search but finds no results. It again notifies the frontend that ‘Search is complete with no results’
  • The frontent detects the first ContentDialog is open and attempts to close it. However, a lot of the WinUI code is not syncronous and there are some timing issues I cannot control. It’s possible without any async code on my part that the second ContentDialog is opened before the first has a chance to fully close. (I would have to wait for some ridiculous long time to be safe which is just bad.)
  • In the majority of cases the first ContentDialog is closed successfully by my applicaiton using the example code above. However, in some cases – just depending on timing – the app will crash.

So I try to close any already open ContentDialogs but the APIs to do so just are not there. Eventually the app will crash if requests are coming fast enough. I do of course agree that showing multiple ContentDialogs is bad but there are some edge cases as @yaichenbaum also mentions.

The point is we can’t adequately manage ContentDialogs because the API just isn’t there:

  1. There is no way to reliably detects when a ContentDialog is open
  2. There is no way to reliably close the open ContentDialog (synchronously before the next opens)
  3. There is also no parameter in ContentDialgo.ShowAsync() specifying what should happen to any existing ContentDialogs.

You can’t have the platform hard-crash when a second ContentDialog is being opened and then not provide an API to manage ContentDialogs (instead relying on the user to do it). On top of that – the limit of one ContentDialog open should not be enforced by crashing… classic Windows or WPF never did that. The framework should allow multiple ContentDialogs to be open for the cases where the app doesn’t manage them correctly (assuming they get the API to do so).

Crashes are bad, ContentDialogs should not be this fragile.

I’m going to reword my proposal a bit asking for the API to manage ContentDialogs and also for the app not to crash when a second is opened. I think we need both to robustly fix this for application developers.

4reactions
yaira2commented, Dec 1, 2021

I have a Notepad app using a content dialog to let users jump to a different line. If the user closes the notepad app when the dialog is still open, it’ll crash when the save dialog is shown. I don’t need two dialogs open at once but the API should handle scenarios like this properly instead of crashing.

Read more comments on GitHub >

github_iconTop Results From Across the Web

'Value does not fall within the expected range.' on Content ...
I'm triyng to make a login system in my UWP (WinUI3) app and when I try to lauch de Login Content Dialog it...
Read more >
ContentDialog Class (Windows.UI.Xaml.Controls)
Represents a dialog box that can be customized to contain checkboxes, hyperlinks, buttons and any other XAML content.
Read more >
Failed to Configure the Organization Error When Trying ...
This issue occurs when you have an invalid API key in your configuration that isn't recognized by Coveo. Resolution. You need to regenerate...
Read more >
Change Log | GreenArrow Studio
Studio: Added ability to delete subscribers via the UI and API. Studio: Introduced a new configuration directive to prevent the deletion of subscribers:....
Read more >
BEE Plugin Tech Docs | Content Services API
Enhance your customers' experience outside of BEE; In a nutshell ... The API provides some useful services that offer additional message formats, ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found