如果我多次按下我的登录按钮,它会触发消息:“异步操作未正确启动。任何时候都只能打开一个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;
}
}
通常,当您启动登录方法时,您需要同时启用登录按钮以避免多次单击。并且您的解决方案也可用,按钮在上一个对话框显示之前无法工作。
我创造了newContentDialogMaker
。有关更多信息,请参阅以下内容。
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
将同时开放。
在打开下一个Dialog之前尝试此操作。
ContentDialogMaker.ActiveDialog?.Hide();
// Show new Dialog here.
处理点击时禁用该按钮。
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;
}
}