任何时候都只能打开一个ContentDialog

时间:2018-05-23 11:07:02

标签: c# xaml uwp async-await

如果我多次按下我的登录按钮,它会触发消息:“异步操作未正确启动。任何时候都只能打开一个ContentDialog。” (延迟表示应用程序联系服务器以查看用户是否有效所需的时间。)

如果我使用MessageDialog一切正常,但我想使用ContentDialog提供的额外自定义。

This链接没有帮助。我下面的代码示例显示了我尝试使用它。

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>

代码背后:

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;
        }
    }
}

从上述链接中借用的代码:

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); }
    }
}

我将DoingStuff添加到Button_Click(),这可以防止错误消息,但我认为必须有更好的方法:

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;
    }
}

4 个答案:

答案 0 :(得分:1)

在打开下一个对话框之前尝试此操作。

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

答案 1 :(得分:1)

通常,当您启动登录方法时,您需要同时启用登录按钮以避免多次单击。并且您的解决方案也可用,按钮在上一个对话框显示之前无法工作。

我创建了新ContentDialogMaker。有关更多信息,请参阅以下内容。

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;
}

唯一的区别是ActiveDialog事件处理程序方法中已清空ActiveDialog_Closing。并且它可以确保在显示之后将清除先前的对话框。因此,只有一个ContentDialog会同时打开。

答案 2 :(得分:0)

在处理点击时禁用该按钮。

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;
    }
}

答案 3 :(得分:0)

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;
}
}
}