How can I efficiently update the UI from an async method?

核能气质少年 提交于 2019-11-28 01:47:02

问题


I'm using a ProgressBar with binding to show the progress when receiving a file from a remote device.

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

ProgressFileReceive is a property (double) in my View Model which has the percentage completion. So to update the Progress Bar, I add to this number.

The problem is I have the file transfer method in a different async method, and so to access this property I must use the following code :

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

This works but makes the whole process extremely slow, since at each iteration (there are over a thousand loops since I read byte-by-byte) the method has to use the dispatcher to update the UI. It takes several times longer to receive the whole file, than it would take if I was not updating the UI.

How can I do this more efficiently so as to speed up the process ?


回答1:


The problem is I have the file transfer method in a different async method

That doesn't necessarily follow. You shouldn't need to use CoreDispatcher explicitly. Asynchronous methods resume on the UI thread by default.


For progress reporting, you should use IProgress<T>. You can use it with a structure to report progress, as such:

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
    });
  }
  ...
}

Then you can consume it with an IProgress<T> implementation. Since you need UI throttling, you can use 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);
}


来源:https://stackoverflow.com/questions/38247499/how-can-i-efficiently-update-the-ui-from-an-async-method

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!