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

UWP应用上传Google Drive时因跨线程更新UI导致崩溃的问题求助

UWP应用上传Google Drive时因跨线程更新UI导致崩溃的问题求助

你遇到的RPC_E_WRONG_THREAD错误是UWP开发里非常常见的跨线程UI更新问题——Google Drive上传的进度回调是在后台线程触发的,而UWP的UI控件(包括绑定的属性)只能由创建它们的UI线程来更新,直接在后台线程修改绑定属性就会触发这个崩溃。

下面给你两个关键的修复方案,既解决崩溃问题,还能优化上传体验:

1. 强制在UI线程更新绑定属性

首先在你的MyFiles类里添加UI线程调度器的引用,确保属性更新操作跑在UI线程上:

修改MyFiles类

// 添加一个CoreDispatcher字段,用来调度UI线程操作
private CoreDispatcher _uiDispatcher;

public MyFiles(StorageFile file)
{
    // 获取当前UI线程的调度器(因为MyFiles是在UI线程创建的,这里能拿到正确的实例)
    _uiDispatcher = CoreWindow.GetForCurrentThread().Dispatcher;
    
    // 你的原有代码...
    FileInfo fileInfo = new FileInfo(file.Path);
    this.fullpath = file.Path;
    this.Size = fileInfo.Length;
    this.Value = 0;
    this.Name = file.Name;
    this.progress = new Progress<IUploadProgress>();
    this.progress.ProgressChanged += progressChanged; // 修正原代码的语法错误
}

private async void progressChanged(object sender, IUploadProgress e)
{
    if (e.Status == UploadStatus.Uploading)
    {
        var newValue = (e.BytesSent * 100) / this.Size;
        // 用调度器把属性更新操作抛回UI线程
        await _uiDispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
        {
            this.Value = newValue;
        });
    }
}

这里的核心是CoreDispatcher.RunAsync,它会把修改Value属性的操作放到UI线程的消息队列里执行,从根源上避免跨线程问题。

2. 优化上传方法,避免阻塞UI线程

你当前的UploadFile方法用了.Result同步调用异步API,会直接阻塞UI线程,导致上传时界面卡死,还可能加剧线程问题。改成异步版本会更友好:

修改DriveClass的UploadFile方法

// 把方法改成异步返回Task
public async Task UploadFile(int index, IProgress<IUploadProgress> prog)
{
    try
    {
        // 把.AsTask().Result改成await,避免阻塞UI
        StorageFile file = await StorageFile.GetFileFromPathAsync(SavedData.files[index].fullpath);
        var fileMetadata = new Google.Apis.Drive.v3.Data.File()
        {
            Name = Path.GetFileName(file.Name),
            MimeType = "application/octet-stream"
        };

        // 同样用await替代.Result
        using (var stream = await file.OpenStreamForReadAsync())
        {
            var request = this.drive.Files.Create(fileMetadata, stream, "application/octet-stream");
            request.ProgressChanged += (IUploadProgress progressInfo) =>
            {
                switch(progressInfo.Status)
                {
                    case UploadStatus.Completed:
                        Debug.WriteLine($"done!");
                        break;
                    case UploadStatus.Failed:
                        Debug.WriteLine($"Failed To Upload Into Google Drive");
                        break;
                    default:
                        Debug.WriteLine($"{progressInfo.BytesSent} has sent");
                        break;
                }
                prog.Report(progressInfo);
            };

            request.ChunkSize = 262144;
            // 用异步上传方法替代同步Upload()
            await request.UploadAsync();

            var uploadedFile = request.ResponseBody;
            Debug.WriteLine($"File uploaded: {uploadedFile.Name} ({uploadedFile.Id})");
        }
    }
    catch (Exception ex)
    {
        Debug.WriteLine("Can't upload the file because -> " + ex.Message);
    }
}

修改MediaPage的ButtonClick事件

// 把事件处理方法改成async
private async void ButtonClick(object sender, RoutedEventArgs e)
{
    // 如果要串行上传,用foreach+await
    foreach (var file in SavedData.files)
    {
        int index = SavedData.files.IndexOf(file);
        await DriveClass.UploadFile(index, file.progress);
    }

    // 如果要并行上传(更快,但要注意线程安全),可以用Task.WhenAll
    // var uploadTasks = new List<Task>();
    // for (int i = 0; i < SavedData.files.Count; i++)
    // {
    //     uploadTasks.Add(DriveClass.UploadFile(i, SavedData.files[i].progress));
    // }
    // await Task.WhenAll(uploadTasks);
}

额外提醒

你原来的代码里this.progress += progressChanged是语法错误,应该是this.progress.ProgressChanged += progressChanged——这个小错误可能也会导致进度回调没触发,记得修正。

这样修改后,既解决了跨线程崩溃的问题,上传过程中UI也不会卡死,用户体验会好很多。

备注:内容来源于stack exchange,提问作者Ariel P

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.20 06:58:02