You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在MAUI(WinUI3)项目中替换Acr.UserDialogs?

在MAUI WinUI3中替代Acr.UserDialogs实现进度与提示对话框

需求背景

将基于UWP的Xamarin项目迁移至MAUI WinUI3,原项目使用Acr.UserDialogs实现进度对话框和提示框,但该组件不支持MAUI,需寻找等效方案,具体需实现:

  1. 数据导入期间显示带进度更新的对话框
  2. 导入完成/出错时显示提示对话框

原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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 13:09:50