UWP 中的任务和界面

问题描述 投票:0回答:1

我正在构建一个将文件上传到 Google 云端硬盘的应用程序。当我绑定属性并调用它们时,它会因以下错误而崩溃:

System.Runtime.InteropServices.COMException: 'The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))'

我的代码->

我的文件类:

propfull Progress<IUploadProgress> progress;
propfull double Value;
propfull string Name;
propfull double Size;
propfull string fullpath;

//each one of properties has `OnPropertyChanged()` in SET
//More properties...

public virtual void OnPropertyChange([CallerMemberName] string propertyName = null)
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    Debug.WriteLine($"~~~~~~{propertyName} invoked!");
}

public MyFiles(StorageFile file)
{
    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; //prog.Report() is calling this
}

private void progressChanged(object sender, IUploadProgress e)
{
    if (e.Status == UploadStatus.Uploading)
    {
        this.Value = (e.BytesSent * 100) / this.Size; 
        //invoke(this.value) property.
        //Binding to ProgressBar.Value
    }
}

MediaPage.xaml
文件:

<ListView x:Name="myListView" Grid.Row="1" Grid.Column="1" Height="600" Width="700">
    <ListView.ItemTemplate>
        <DataTemplate>
            <Grid Height="70">
                <StackPanel Orientation="Horizontal">
                    <Grid>
                        <TextBlock Text="{Binding Name}" VerticalAlignment="Center" Margin="10,20" FontSize="20"  Grid.Row="0" FontFamily="Yu Gothic UI Semibold"/>
                        <ProgressBar Value="{Binding Value}" Tag="{Binding Name}" Height="5" Width="200"/>
                    </Grid>
                </StackPanel>
            </Grid>

        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>
<Button x:Name="upload_btn" Click="ButtonClick" Height="40" Width="150" Content="Upload All Files"/>

代码在

MediaPage.xaml.cs

public MediaPage()
{
    this.InitializeComponent();
    SavedData.files = new ObservableCollection<MyFiles>();
    StorageFile file = ...; // testing file
    SavedData.files.Add(new MyFiles(file));

    myListView.ItemsSource = SavedData.files;
}

private void ButtonClick(object sender, RoutedEventArgs e)
{
    for (int i = 0; i < SavedData.files.Count; i++)
    {
        DriveClass.UploadFile(i, SavedData.files[i].progress); //(index,progress)
    }
}


DriveClass
代码:

public void UploadFile(int index, IProgress<IUploadProgress> prog)
{

    try
    {
        StorageFile file = StorageFile.GetFileFromPathAsync([SavedData.files[index].fullpath).AsTask().Result;

        var fileMetadata = new Google.Apis.Drive.v3.Data.File()
        {
            Name = Path.GetFileName(file.Name),
            MimeType = "application/octet-stream"
            
        };

        using (var stream = file.OpenStreamForReadAsync().Result)
        {
            

            var request = this.drive.Files.Create(fileMetadata, stream, "application/octet-stream");

            request.ProgressChanged += (IUploadProgress progressInfo) =>
            {
                if (progressInfo.Status == UploadStatus.Completed)
                {
                    Debug.WriteLine($"done!");
                    prog.Report(progressInfo);
                }
                else if (progressInfo.Status == UploadStatus.Failed)
                {
                    Debug.WriteLine($"Failed To Upload Into Google Drive");
                    prog.Report(progressInfo);
                }
                else
                {
                    Debug.WriteLine(progressInfo.BytesSent + " has sent");
                    prog.Report(progressInfo);

                }
            };

            request.ChunkSize = 262144;
            request.Upload();

            var uploadedFile = request.ResponseBody;
            Debug.WriteLine($"File uploaded: {uploadedFile.Name} ({uploadedFile.Id})");

        }
    }
    catch (Exception ex)
    {
        Debug.WriteLine("Cant uplaod the file because -> " + ex.Message);
    }
}

这是整个团队。一切正常,直到我按下按钮并呼叫

UploadFile()

UploadFile()
中,当 request.progressChanged 处于活动状态时,它会调用
files[i].progress.ProgressChanged()

ProgressChanged()
正在更新
files[i].Value
invoke()
以更改
ProgressBar.Value = "{Binding Value}"

应用程序在

Invoke()
行崩溃,因为我无法更新 UI。

c# uwp interface task
1个回答
0
投票

经过搜索,我发现了一些有帮助的东西。

调用UI所连接的属性的方法是将这种调度程序添加到

OnPropertyChanged()

public async virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
    CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.High, () =>
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    });

}

添加此

Dispatcher
后,代码正在运行,但应用程序卡住了。所以,我将
UploadFile()
改为
Task
而不是
void
并将以下代码添加到
ButtonClick()
 中的 
MediaPage.xaml.cs

事件中
Task UploadFileTask = Task.Run(() => DriveClass.UploadFile(index,progress));

这也将继续上传进度。

Here how the ProgressBar looks and what I wanted to do

我在这个问题中看到了答案。

© www.soinside.com 2019 - 2024. All rights reserved.