如何实现UserControl的异步等待?替代ContentDialog获取返回结果
给UserControl实现类似ContentDialog的ShowAsync异步等待方法
我完全懂你的需求——虽然ContentDialog能搞定这类弹窗任务,但有时候就是想自己用UserControl来实现,还得支持异步等待用户操作完成,拿到结果再继续后续逻辑。下面给你一个直接能用的实现方案:
步骤1:给LoginUserControl添加异步等待逻辑
我们需要在LoginUserControl里加入TaskCompletionSource来控制异步任务的完成,再封装一个ShowAsync方法,把UserControl放到Popup里显示(Popup是UWP原生的弹窗容器,完全符合你的需求)。
LoginUserControl的XAML(示例)
先写个简单的登录界面,包含密码框和操作按钮:
<UserControl x:Class="YourNamespace.LoginUserControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" d:DesignHeight="300" d:DesignWidth="400"> <Grid Background="White" Padding="20" CornerRadius="8" BorderBrush="#E0E0E0" BorderThickness="1"> <StackPanel> <TextBlock Text="请输入密码" Margin="0,0,0,10" FontSize="16"/> <PasswordBox x:Name="PasswordBox" PlaceholderText="输入密码" FontSize="14"/> <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,20,0,0"> <Button x:Name="CancelBtn" Content="取消" Margin="0,0,10,0" Padding="12,6"/> <Button x:Name="LoginBtn" Content="登录" Padding="12,6" Background="#0078D4" Foreground="White"/> </StackPanel> </StackPanel> </Grid> </UserControl>
LoginUserControl的后台代码
核心逻辑在这里,用TaskCompletionSource实现异步等待:
using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using System.Threading.Tasks; namespace YourNamespace { public sealed partial class LoginUserControl : UserControl { private TaskCompletionSource<bool> _taskCompletionSource; // 对外暴露输入的密码 public string EnteredPassword => PasswordBox.Password; public LoginUserControl() { this.InitializeComponent(); // 绑定按钮点击事件 LoginBtn.Click += OnLoginClicked; CancelBtn.Click += OnCancelClicked; } // 封装ShowAsync方法,返回Task<bool>表示用户是否点击了登录 public Task<bool> ShowAsync() { _taskCompletionSource = new TaskCompletionSource<bool>(); // 创建Popup容器来承载UserControl var popup = new Popup { IsLightDismissEnabled = false, // 禁止点击外部关闭,必须手动操作按钮 Child = this, Width = this.Width, Height = this.Height }; // 设置Popup在屏幕居中显示 var windowBounds = Window.Current.Bounds; popup.HorizontalOffset = (windowBounds.Width - this.Width) / 2; popup.VerticalOffset = (windowBounds.Height - this.Height) / 2; // 显示Popup popup.IsOpen = true; // 任务完成后清理Popup资源 _taskCompletionSource.Task.ContinueWith(_ => { popup.IsOpen = false; popup.Child = null; }, TaskScheduler.FromCurrentSynchronizationContext()); // 返回等待的Task return _taskCompletionSource.Task; } private void OnLoginClicked(object sender, RoutedEventArgs e) { // 用户点击登录,标记任务完成,返回true _taskCompletionSource.SetResult(true); } private void OnCancelClicked(object sender, RoutedEventArgs e) { // 用户点击取消,标记任务完成,返回false _taskCompletionSource.SetResult(false); } } }
步骤2:调用ShowAsync方法使用你的UserControl
现在你就能像用ContentDialog一样异步调用了,完全符合你想要的写法:
var loginControl = new LoginUserControl(); bool isLoginConfirmed = await loginControl.ShowAsync(); // 根据用户操作和输入的密码处理逻辑 if (isLoginConfirmed && loginControl.EnteredPassword == "1234") { // 登录成功,执行后续逻辑 // 比如:Frame.Navigate(typeof(MainPage)); } else { // 登录失败或用户取消,提示用户 // 比如:new ContentDialog{Content="密码错误或取消操作", PrimaryButtonText="确定"}.ShowAsync(); }
原理说明
TaskCompletionSource是核心:它能帮我们创建一个可手动控制完成状态的Task,当用户点击登录/取消按钮时,调用SetResult完成这个Task,await就会继续执行后续代码。Popup作为容器:它可以把UserControl显示在当前页面之上,完全替代ContentDialog的弹窗效果,而且更灵活可控。
内容的提问来源于stack exchange,提问作者Mg Bhadurudeen
相关产品推荐
相关产品推荐

