如何在MAUI(WinUI3)项目中替换Acr.UserDialogs?
在MAUI WinUI3中替代Acr.UserDialogs实现进度与提示对话框
需求背景
将基于UWP的Xamarin项目迁移至MAUI WinUI3,原项目使用Acr.UserDialogs实现进度对话框和提示框,但该组件不支持MAUI,需寻找等效方案,具体需实现:
- 数据导入期间显示带进度更新的对话框
- 导入完成/出错时显示提示对话框
原UWP代码参考
using Acr.UserDialogs; public class ImportDataForWin : IImportDataForWin { private IProgressDialog progress; public async Task ImportData() { var picker = new Windows.Storage.Pickers.FileOpenPicker { ViewMode = Windows.Storage.Pickers.PickerViewMode.Thumbnail, SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.PicturesLibrary }; picker.FileTypeFilter.Add(".xlsx"); picker.FileTypeFilter.Add(".xls"); var file = await picker.PickSingleFileAsync(); if (file != null) { var config = new ProgressDialogConfig() .SetTitle("Importing Data") .SetIsDeterministic(false); progress = UserDialogs.Instance.Progress(config); progress.PercentComplete = 0; progress.Show(); // Some code var countMax = itemsToAdd.Count(); var rowCount = 0; foreach (var item in itemsToAdd) { rowCount++; await SaveData(item); progress.PercentComplete = (rowCount * 100) / countMax; } progress.Hide(); UserDialogs.Instance.Alert("errorMessage"); } } }
MAUI WinUI3实现方案
我们可以通过依赖服务+WinUI3原生控件实现需求,既保留WinUI3的原生体验,又符合MAUI的架构规范。
步骤1:定义跨平台服务接口
在MAUI共享项目中定义统一的对话框服务接口:
public interface IProgressDialogService { // 显示进度对话框 Task ShowProgressDialog(string title, bool isIndeterminate = false); // 更新进度百分比 Task UpdateProgress(int percent); // 关闭进度对话框 Task HideProgressDialog(); // 显示提示对话框 Task ShowAlert(string title, string message, string cancelButtonText); }
步骤2:WinUI3平台实现服务
在MAUI的WinUI项目中实现上述接口,使用WinUI3原生ContentDialog:
using Microsoft.UI.Xaml.Controls; using Microsoft.Maui.ApplicationModel; using Microsoft.Maui.Controls; [assembly: Dependency(typeof(WinUIProgressDialogService))] namespace YourAppNamespace.WinUI { public class WinUIProgressDialogService : IProgressDialogService { private ContentDialog _progressDialog; private ProgressBar _progressBar; private TextBlock _progressText; public async Task ShowProgressDialog(string title, bool isIndeterminate = false) { await MainThread.InvokeOnMainThreadAsync(() => { // 创建进度条和文本控件 _progressBar = new ProgressBar { IsIndeterminate = isIndeterminate, Width = 300, Margin = new Microsoft.UI.Xaml.Thickness(0, 10, 0, 10) }; _progressText = new TextBlock { Text = "0%", HorizontalAlignment = Microsoft.UI.Xaml.HorizontalAlignment.Center }; // 组装对话框内容 var contentPanel = new StackPanel(); contentPanel.Children.Add(_progressBar); contentPanel.Children.Add(_progressText); // 初始化对话框 _progressDialog = new ContentDialog { Title = title, Content = contentPanel, PrimaryButtonText = "", CloseButtonText = "", IsPrimaryButtonEnabled = false, IsCloseButtonEnabled = false, XamlRoot = Window.Current.Handler.PlatformView.XamlRoot }; // 显示对话框 _ = _progressDialog.ShowAsync(); }); } public async Task UpdateProgress(int percent) { await MainThread.InvokeOnMainThreadAsync(() => { if (_progressBar != null && !_progressBar.IsIndeterminate) { _progressBar.Value = percent; _progressText.Text = $"{percent}%"; } }); } public async Task HideProgressDialog() { await MainThread.InvokeOnMainThreadAsync(() => { _progressDialog?.Hide(); _progressDialog = null; _progressBar = null; _progressText = null; }); } public async Task ShowAlert(string title, string message, string cancelButtonText) { await MainThread.InvokeOnMainThreadAsync(async () => { var alertDialog = new ContentDialog { Title = title, Content = message, CloseButtonText = cancelButtonText, XamlRoot = Window.Current.Handler.PlatformView.XamlRoot }; await alertDialog.ShowAsync(); }); } } }
步骤3:共享项目中使用服务
修改原ImportDataForWin类,注入并使用服务,同时替换文件选择器为MAUI跨平台版本:
using Microsoft.Maui.Storage; public class ImportDataForWin : IImportDataForWin { private readonly IProgressDialogService _progressDialogService; // 通过构造函数注入服务 public ImportDataForWin(IProgressDialogService progressDialogService) { _progressDialogService = progressDialogService; } public async Task ImportData() { // 使用MAUI跨平台文件选择器 var excelFileType = new FilePickerFileType(new Dictionary<DevicePlatform, IEnumerable<string>> { { DevicePlatform.WinUI, new[] { ".xlsx", ".xls" } } }); var fileResult = await FilePicker.Default.PickAsync(new PickOptions { FileTypes = excelFileType, PickerTitle = "Select Excel File" }); if (fileResult != null) { await _progressDialogService.ShowProgressDialog("Importing Data", isIndeterminate: false); try { // 模拟获取导入数据项 var itemsToAdd = GetImportItems(fileResult.FullPath); var totalCount = itemsToAdd.Count(); var currentCount = 0; foreach (var item in itemsToAdd) { currentCount++; await SaveData(item); // 更新进度 await _progressDialogService.UpdateProgress((currentCount * 100) / totalCount); } // 导入成功提示 await _progressDialogService.ShowAlert("Success", "Data imported successfully!", "OK"); } catch (Exception ex) { // 错误提示 await _progressDialogService.ShowAlert("Error", ex.Message, "OK"); } finally { // 确保关闭进度对话框 await _progressDialogService.HideProgressDialog(); } } } // 辅助方法:读取Excel文件获取数据项 private List<object> GetImportItems(string filePath) { // 这里替换为实际的Excel读取逻辑 return new List<object>(); } // 辅助方法:保存单条数据 private async Task SaveData(object item) { // 这里替换为实际的数据保存逻辑 await Task.Delay(100); // 模拟耗时操作 } }
关键说明
- 文件选择器:使用MAUI内置的
FilePicker替代UWP原生控件,实现跨平台兼容,同时针对WinUI3配置特定的文件类型。 - 线程安全:所有UI操作必须通过
MainThread.InvokeOnMainThreadAsync执行,避免跨线程访问UI控件的异常。 - 灵活性:通过依赖服务实现平台特定逻辑,后续如需扩展其他平台(如Android、iOS),只需添加对应平台的服务实现即可。
内容的提问来源于stack exchange,提问作者Monal
相关产品推荐
相关产品推荐

