如果我多次按下登录按钮,则会触发消息:“异步操作未正确启动。任何时候都只能打开一个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;
}
}
最佳答案
通常,启动登录方法时,需要同时启用登录按钮,以避免多次单击。您的解决方案也可用,直到显示上一个对话框后该按钮才起作用。
并且我创建了new 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
将同时打开。