How to allow for multiple popups at once in WinRT?

后端 未结 2 1040
南旧
南旧 2020-12-06 03:42

If you call the ShowAsync command on a MessageDialog object when another MessageDialog object has already been displayed to the user b

2条回答
  •  轻奢々
    轻奢々 (楼主)
    2020-12-06 04:24

    There are many ways to approach it and the choice might depend on your skills, requirements and preferences.

    My personal choice is to avoid using dialog boxes altogether since they are bad for user experience (evil). There are then alternative solutions like displaying a separate screen/page with the UI requiring user to provide some input when it really is required or displaying a non-modal popup somewhere on the side/edge/corner if the user input is optional and hiding it after a moment or some other sort of notification that doesn't break user flow.

    If you disagree or don't have the time, resources or skills to implement an alternative - you can create some sort of a wrapper around MessageDialog.ShowAsync() call to either queue or ignore new requests while a dialog is already shown.

    This class has extension methods to allow to either ignore a new show request when another dialog is already displayed or queue up the requests:

    /// 
    /// MessageDialog extension methods
    /// 
    public static class MessageDialogExtensions
    {
        private static TaskCompletionSource _currentDialogShowRequest;
    
        /// 
        /// Begins an asynchronous operation showing a dialog.
        /// If another dialog is already shown using
        /// ShowAsyncQueue or ShowAsyncIfPossible method - it will wait
        /// for that previous dialog to be dismissed before showing the new one.
        /// 
        /// The dialog.
        /// 
        /// This method can only be invoked from UI thread.
        public static async Task ShowAsyncQueue(this MessageDialog dialog)
        {
            if (!Window.Current.Dispatcher.HasThreadAccess)
            {
                throw new InvalidOperationException("This method can only be invoked from UI thread.");
            }
    
            while (_currentDialogShowRequest != null)
            {
                await _currentDialogShowRequest.Task;
            }
    
            var request = _currentDialogShowRequest = new TaskCompletionSource();
            await dialog.ShowAsync();
            _currentDialogShowRequest = null;
            request.SetResult(dialog);
        }
    
        /// 
        /// Begins an asynchronous operation showing a dialog.
        /// If another dialog is already shown using
        /// ShowAsyncQueue or ShowAsyncIfPossible method - it will wait
        /// return immediately and the new dialog won't be displayed.
        /// 
        /// The dialog.
        /// 
        /// This method can only be invoked from UI thread.
        public static async Task ShowAsyncIfPossible(this MessageDialog dialog)
        {
            if (!Window.Current.Dispatcher.HasThreadAccess)
            {
                throw new InvalidOperationException("This method can only be invoked from UI thread.");
            }
    
            while (_currentDialogShowRequest != null)
            {
                return;
            }
    
            var request = _currentDialogShowRequest = new TaskCompletionSource();
            await dialog.ShowAsync();
            _currentDialogShowRequest = null;
            request.SetResult(dialog);
        }
    }
    

    Test

    // This should obviously be displayed
    var dialog = new MessageDialog("await ShowAsync", "Dialog 1");
    await dialog.ShowAsync();
    
    // This should be displayed because we awaited the previous request to return
    dialog = new MessageDialog("await ShowAsync", "Dialog 2");
    await dialog.ShowAsync(); 
    
    // All other requests below are invoked without awaiting
    // the preceding ones to complete (dialogs being closed)
    
    // This will show because there is no dialog shown at this time
    dialog = new MessageDialog("ShowAsyncIfPossible", "Dialog 3");
    dialog.ShowAsyncIfPossible();
    
    // This will not show because there is a dialog shown at this time
    dialog = new MessageDialog("ShowAsyncIfPossible", "Dialog 4");
    dialog.ShowAsyncIfPossible();
    
    // This will show after Dialog 3 is dismissed
    dialog = new MessageDialog("ShowAsyncQueue", "Dialog 5");
    dialog.ShowAsyncQueue();
    
    // This will not show because there is a dialog shown at this time (Dialog 3)
    dialog = new MessageDialog("ShowAsyncIfPossible", "Dialog 6");
    dialog.ShowAsyncIfPossible();
    
    // This will show after Dialog 5 is dismissed
    dialog = new MessageDialog("ShowAsyncQueue", "Dialog 7");
    dialog.ShowAsyncQueue();
    
    // This will show after Dialog 7 is dismissed
    dialog = new MessageDialog("ShowAsyncQueue", "Dialog 8");
    dialog.ShowAsyncQueue();
    

提交回复
热议问题