3

我使用带绑定的ProgressBar来显示从远程设备接收文件时的进度。如何从异步方法有效更新用户界面?

<ProgressBar Width="500" Height="50" Value="{Binding ProgressFileReceive}"/> 

ProgressFileReceive是在具有百分比完成我的视图模型属性(double)。所以要更新进度条,我添加了这个数字。

的问题是我有一个不同async方法的文件传输方法,所以访问该属性,我必须使用下面的代码:

await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, 
    () => 
    { 
     // do something on the UI thread 
     ProgressFileReceive = (double)i/fileSize * 100; 
    }); 

这工作,但使整个过程非常缓慢,因为在每次迭代时(自从我逐字节读取以来,有超过一千个循环),该方法必须使用分派器来更新UI。接收整个文件需要几倍的时间,比如果我没有更新UI时需要多长时间。

我该如何更有效地做到这一点,以加快这一进程?

+0

一个简单的方法:只更新进度条每隔X迭代,其中X是足够大,不处理太多的放缓,但不会大到让进度条锯齿。 – stuartd

+0

@Aniruddha Varma,您不需要手动将绑定数据封送到UI线程,因为您正在使用绑定。 WPF关心它。 –

+0

@stuartd谢谢。是的,我会设置一个柜台,只要表面看起来或多或少光滑,就应该可以工作。 –

回答

2

的问题是我有一个不同的异步方法

这并不一定按照文件传输方法。您不应该明确需要使用CoreDispatcher。异步方法默认在UI线程上恢复。


对于进度报告,您应该使用IProgress<T>。你可以用结构用它来报告进度,因为这样的:

public struct ProgressReport 
{ 
    public double Progress { get; set; } 
    public double FileSize { get; set; } 
} 

async Task FileTransferAsync(IProgress<ProgressReport> progress) 
{ 
    ... 
    if (progress != null) 
    { 
    progress.Report(new ProgressReport 
    { 
     Progress = (double)i, 
     FileSize = fileSize 
    }); 
    } 
    ... 
} 

然后你就可以用IProgress<T>实现消费它。由于需要用户界面限制,您可以使用one that I wrote that has built-in throttling

using (var progress = ObservableProgress<ProgressReport>.CreateForUi(value => 
    { 
     ProgressFileReceive = (double)value.Progress/value.FileSize * 100; 
    })) 
{ 
    await FileTransferAsync(progress); 
} 
+0

谢谢。我试过了,但是我得到了一个'COMException - 应用程序调用了RaisePropertyChanged()方法中ProgressFileReceive的set访问器内部针对不同线程编组的接口。 –

+0

@AniruddhaVarma:你必须在UI线程上构建'ObservableProgress'。 –

+0

我明白了。但是该任务必须从异步方法的范围内开始,因此我将第二段代码封装在CoreWindow.Dispatcher中,以便在UI线程中运行它。这不会引发错误,但进度条仅在任务结束时更新,直接跳到100%。 –

相关问题