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%。 –

相關問題