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

如何在MvvmCross/WPF应用中处理临时文件清理及异步等待

解决MvvmCross桌面应用关闭时异步任务未完成导致临时文件残留的问题

核心思路

通过在ViewModel中跟踪所有运行中的异步任务,在窗口关闭时拦截关闭请求,等待所有异步任务执行完毕(完成临时文件清理)后再允许应用关闭。以下分WPF和Cocoa平台给出具体实现方案:


1. ViewModel层:维护异步任务生命周期

在ViewModel中添加任务集合,跟踪所有正在执行的异步命令,同时提供等待所有任务完成的方法:

public class TipViewModel : MvxViewModel
{
    // 线程安全集合,存储正在运行的异步任务
    private readonly ConcurrentBag<Task> _runningTasks = new ConcurrentBag<Task>();

    public IAsyncCommand ProcessTempFileCommand => new MvxAsyncCommand(ProcessTempFileAsync);

    private async Task ProcessTempFileAsync()
    {
        var workTask = ExecuteFileOperationsAsync();
        _runningTasks.Add(workTask);
        try
        {
            await workTask.ConfigureAwait(false);
        }
        finally
        {
            // 任务完成后从集合移除
            _runningTasks.TryTake(out _);
        }
    }

    // 实际业务逻辑:创建临时文件+异步操作+清理
    private async Task ExecuteFileOperationsAsync()
    {
        var tempFilePath = Path.GetTempFileName();
        try
        {
            // 模拟耗时异步操作
            await Task.Delay(3000).ConfigureAwait(false);
            // 此处添加实际业务代码
        }
        finally
        {
            // 确保临时文件被清理
            if (File.Exists(tempFilePath))
                File.Delete(tempFilePath);
        }
    }

    // 对外提供的等待所有任务完成的方法
    public async Task WaitForAllTasksAsync()
    {
        if (_runningTasks.Any())
        {
            await Task.WhenAll(_runningTasks).ConfigureAwait(false);
        }
    }
}

2. WPF平台:拦截窗口关闭事件

在继承自MvxWpfView的窗口中,重写OnClosing方法,阻止立即关闭,等待ViewModel任务完成后再关闭窗口:

public partial class TipView : MvxWpfView
{
    protected override void OnClosing(CancelEventArgs e)
    {
        base.OnClosing(e);
        
        var viewModel = DataContext as TipViewModel;
        if (viewModel == null) return;

        // 阻止窗口立即关闭
        e.Cancel = true;
        // 异步等待任务完成后再关闭
        _ = FinishCloseAfterTasks(viewModel);
    }

    private async Task FinishCloseAfterTasks(TipViewModel viewModel)
    {
        try
        {
            await viewModel.WaitForAllTasksAsync().ConfigureAwait(true);
        }
        catch (Exception ex)
        {
            // 此处添加异常日志记录逻辑
        }
        finally
        {
            // 回到UI线程执行窗口关闭
            Dispatcher.Invoke(() => Close());
        }
    }
}

3. Cocoa平台:拦截窗口关闭回调

在继承自MvxWindowController的窗口控制器中,实现WindowShouldClose方法,同步等待ViewModel任务完成:

public class TipWindowController : MvxWindowController
{
    public override bool WindowShouldClose(NSObject sender)
    {
        var viewModel = ViewModel as TipViewModel;
        if (viewModel == null) return true;

        // 同步等待所有异步任务完成(Cocoa关闭回调为同步逻辑)
        viewModel.WaitForAllTasksAsync().GetAwaiter().GetResult();
        
        return true;
    }
}

关键注意事项

  • 死锁避免:ViewModel中的异步方法使用ConfigureAwait(false),避免捕获UI同步上下文导致死锁。
  • 异常处理:等待任务过程中必须捕获异常,防止未处理异常导致应用崩溃。
  • 任务准确性:确保每个异步任务都在finally块中从集合移除,即使任务抛出异常也能维持集合的正确性。

内容的提问来源于stack exchange,提问作者Serg

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 10:32:17