Only a single ContentDialog can be open at any time

假如想象 提交于 2019-12-12 19:13:52

问题


If I press my login button multiple times, it triggers the message: "An async operation was not properly started. Only a single ContentDialog can be open at any time." (The delay is there to represent the time it takes for the app to contact the server to see if the user is valid.)

If I use MessageDialog everything works ok, but I want to use the extra customisation that ContentDialog provides.

This link has not helped. My code example below shows me trying to use it.

XAML:

<Page
    x:Class="DuckTracker.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:DuckTracker"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>

        <TextBlock Grid.Row="0" Grid.Column="0" Height="20">Name:</TextBlock>
    <TextBox Grid.Row="0" Grid.Column="1" Height="20"></TextBox>
    <Button Click="Button_Click" Grid.Row="2" VerticalAlignment="Bottom">Login</Button>
    </Grid>
</Page>

Code behind:

using System;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace DuckTracker
{

    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
        }

        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            bool canLogin = await CanLogin(); 

            if (canLogin == false)
            {
                try
                {
                     await AlertWithMessages("Fail", "Could not log in!", "ok");

                }
                catch (Exception ex)
                {

                    var dialog = new Windows.UI.Popups.MessageDialog(ex.Message, "Error");
                    await dialog.ShowAsync();
                }

            }
        }

        public async Task AlertWithMessages(string title, string msg, string confirm)
        {
            ContentDialog dialog = new ContentDialog()
            {
                Title = title,
                Content = msg,
                PrimaryButtonText = confirm
            };

            await ContentDialogMaker.CreateContentDialogAsync(dialog, true);

        }

        public async Task<bool> CanLogin()
        {
            await Task.Delay(1000);

            return false;
        }
    }
}

Code borrowed from link mentioned above:

using System;
using System.Threading.Tasks;
using Windows.UI.Xaml.Controls;

namespace DuckTracker
{
    public static class ContentDialogMaker
    {
        public static async void CreateContentDialog(ContentDialog Dialog, bool awaitPreviousDialog) { await CreateDialog(Dialog, awaitPreviousDialog); }
        public static async Task CreateContentDialogAsync(ContentDialog Dialog, bool awaitPreviousDialog) { await CreateDialog(Dialog, awaitPreviousDialog); }

        static async Task CreateDialog(ContentDialog Dialog, bool awaitPreviousDialog)
        {
            if (ActiveDialog != null)
            {
                if (awaitPreviousDialog)
                {
                    await DialogAwaiter.Task;
                    DialogAwaiter = new TaskCompletionSource<bool>();
                }
                else ActiveDialog.Hide();
            }
            ActiveDialog = Dialog;
            ActiveDialog.Closed += ActiveDialog_Closed;
            await ActiveDialog.ShowAsync();
            ActiveDialog.Closed -= ActiveDialog_Closed;
        }

        public static ContentDialog ActiveDialog;
        static TaskCompletionSource<bool> DialogAwaiter = new TaskCompletionSource<bool>();
        private static void ActiveDialog_Closed(ContentDialog sender, ContentDialogClosedEventArgs args) { DialogAwaiter.SetResult(true); }
    }
}

I added DoingStuff to Button_Click(), which prevents the error message, but I think there must be a better way:

private async void Button_Click(object sender, RoutedEventArgs e)
{
    if (DoingStuff == false)
    {
        DoingStuff = true;

        bool canLogin = await CanLogin();

        if (canLogin == false)
        {
            try
            {

                await AlertWithMessages("Fail", "Could not log in!", "ok");

            }
            catch (Exception ex)
            {

                var dialog = new Windows.UI.Popups.MessageDialog(ex.Message, "Error");
                await dialog.ShowAsync();
            }

        }

        DoingStuff = false;
    }
}

回答1:


In general, when you start the login method, you need to enable your login button at same time to avoid multiple click. And your solution is also available that the button will not work until the previous dialog showed.

And I have created newContentDialogMaker. For more you could refer the following.

public static class ContentDialogMaker
{
    public static async void CreateContentDialog(ContentDialog Dialog, bool awaitPreviousDialog) { await CreateDialog(Dialog, awaitPreviousDialog); }
    public static async Task CreateContentDialogAsync(ContentDialog Dialog, bool awaitPreviousDialog) { await CreateDialog(Dialog, awaitPreviousDialog); }

    static async Task CreateDialog(ContentDialog Dialog, bool awaitPreviousDialog)
    {
        if (ActiveDialog != null)
        {
            if (awaitPreviousDialog)
            {
                ActiveDialog.Hide();
            }
            else
            {
                switch (Info.Status)
                {
                    case AsyncStatus.Started:
                        Info.Cancel();
                        break;
                    case AsyncStatus.Completed:
                        Info.Close();
                        break;
                    case AsyncStatus.Error:

                        break;
                    case AsyncStatus.Canceled:

                        break;
                }
            }
        }
        ActiveDialog = Dialog;
        ActiveDialog.Closing += ActiveDialog_Closing;
        Info = ActiveDialog.ShowAsync();
    }
    public static IAsyncInfo Info;
    private static void ActiveDialog_Closing(ContentDialog sender, ContentDialogClosingEventArgs args)
    {
        ActiveDialog = null;
    }

    public static ContentDialog ActiveDialog;
}

The only difference is that the ActiveDialog was emptied in the ActiveDialog_Closing event handler method. And it could maker sure the previous dialog would be cleared after displayed. So, there is only a single ContentDialog will be open at same time.




回答2:


Try this before you open the next Dialog.

ContentDialogMaker.ActiveDialog?.Hide();
// Show new Dialog here.



回答3:


Disable the button while you are handling the click.

private async void Button_Click(object sender, RoutedEventArgs e)
{
    if (sender is Button button)
    {
        button.IsEnabled = false;
    }

    … handle button click

    if (sender is Button button2)
    {
        button2.IsEnabled = true;
    }
}



回答4:


using System;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;




namespace DuckTracker
{

public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}

private async void Button_Click(object sender, RoutedEventArgs e)
{
bool canLogin = await CanLogin();

if (canLogin == false)
{
try
{
await AlertWithMessages("Fail", "Could not log in!", "ok");

}
catch (Exception ex)
{

var dialog = new Windows.UI.Popups.MessageDialog(ex.Message, "Error");
await dialog.ShowAsync();
}

}
}

public async Task AlertWithMessages(string title, string msg, string confirm)
{
ContentDialog dialog = new ContentDialog
{
Title = title,
Content = msg,
PrimaryButtonText = confirm
};


ContentDialogResult result = await dialog.ShowAsync();


}

public async Task<bool> CanLogin()
{
await Task.Delay(1000);

return false;
}
}
}


来源:https://stackoverflow.com/questions/50486830/only-a-single-contentdialog-can-be-open-at-any-time

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!