2014-01-17 46 views
0

誰能教我UI凍結爲什麼UI繁重的計算期間凍結:MvvmCross - 當我打電話Task.Run

var ret = await Task.Run(() => this._service.CalcFourier(100000, progress)); 

我有是有約束力的「值」屬性的進度條,但其棒沒有更新,直到計算完了。當我將斷點設置爲'CurrentCalcCount'的setter方法並開始計算時,每次都會調用'RaisePropertyChanged'。

如何避免阻塞用戶界面...我一整天都在工作,我不知道爲什麼。任何機構都可以修復代碼或有一些解釋來幫助我?謝謝。

CalcView.xaml

<Grid Grid.Row="0"> 
     <TextBlock Text="Calculate pi with fourier transform method." Margin="3" /> 
    </Grid> 
    <StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center"> 
     <TextBlock Text="Calc time:" Margin="3" VerticalAlignment="Center"/> 
     <TextBox Text="{Binding CalculationCount, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" MinWidth="150" Margin="3"/> 
     <Button Content="Start" Margin="3,0,3,3" Command="{Binding CalcCommand}" /> 
    </StackPanel> 
    <StackPanel Grid.Row="2"> 
     <ProgressBar MinHeight="25" Margin="5" Maximum="{Binding CalculationCount}" Value="{Binding CurrentCalcCount}" /> 
     <Button Content="Cancel" MaxWidth="100" Command="{Binding CancelCommand}"/> 
    </StackPanel> 
    <TextBlock Grid.Row="3" Text="{Binding ProgressText}" HorizontalAlignment="Center"/> 

'CalcCommand' 和其它性質定義如下:

CalcViewModel.cs在模型

private MvxCommand _calcCommand; 

    public ICommand CalcCommand 
    { 
     get 
     { 
      return _calcCommand ?? 
        (_calcCommand = new MvxCommand(DoCalcCommand,() => !InProgress)); 
     } 
    } 

    private async void DoCalcCommand() 
    { 
     try 
     { 
      InProgress = true; 

      var progress = new Progress<CalcProgressInfo>(info => Dispatcher.RequestMainThreadAction(() => 
      { 
       CurrentCalcCount = info.CurrentCount; 
       ProgressText = info.Message; 
      })); 

      var ret = await Task.Run(() => this._service.CalcFourier(this._calculationCount, progress)); 

      ProgressText += Environment.NewLine + ret; 
     } 
     catch (Exception e) 
     { 
      ProgressText = e.Message; 
     } 
     finally 
     { 
      InProgress = false; 
     } 
    } 

CalcFourier命令:

CalcService。 cs

private bool _cancel; 

    public double CalcFourier(int count, IProgress<CalcProgressInfo> progress) 
    { 
     var sigma = 0.0; 
     var n = 1; 

     foreach (
      var i in 
       Enumerable.Range(1, count).TakeWhile(_ => !_cancel)) 
     { 
      progress.Report(new CalcProgressInfo(i, 
       string.Format("Calculation is in progress now. - {0}/{1}", i, count))); 

      sigma += 1.0/n/n; 
      n += 2; 
     } 

     progress.Report(this._cancel 
      ? new CalcProgressInfo(0, "Calculation has canceled.") 
      : new CalcProgressInfo(count, "Calculation has completed.")); 
     _cancel = false; 

     return Math.Sqrt(sigma * 8); 
    } 
+0

看看MSDN上的【如何調用Visual C#方法異步(http://support.microsoft.com/kb/315582)頁面。 – Sheridan

+0

我認爲它凍結,因爲你正在等待這個過程,因爲它是你的'命令'的一部分,所以而不是[await](http://msdn.microsoft.com/en-us/library/hh156528.aspx) 你可以試試[BackgroundWorker(http://msdn.microsoft.com/en-us/library/cc221403%28v=vs.95%29.aspx) – WiiMaxx

+0

我想我現在就明白了。我將繼續學習異步模式。謝謝。 – ailen0ada

回答

0

它看起來像你的處理代碼充斥着用戶界面的更新。執行一對雙精度分割和整數加法並不需要很長時間;只是你的進度報告字符串的構建幾乎肯定會花費更長的時間。

相反的:

progress.Report(new CalcProgressInfo(i, 
    string.Format("Calculation is in progress now. - {0}/{1}", i, count))); 

考慮嘗試這樣的:

if (i % 100 == 0) 
{ 
    progress.Report(new CalcProgressInfo(i, 
     string.Format("Calculation is in progress now. - {0}/{1}", i, count))); 
} 

而且具有更高/更低的值打替換100,直到你可以在一個合理的速度看你的更新(可讀,但不太慢了)。

你根本沒有看到任何更新的原因是由於UI消息循環的優先級;諸如「更新此進度值」之類的「代碼」消息具有比「繪製」消息更高的優先級。因此,如果循環充斥着更新消息,它永遠不會重新繪製UI。

P.S.沒有必要使用Dispatcher; Progress<T>將封送到適當的線程默認:

var progress = new Progress<CalcProgressInfo>(info => 
{ 
    CurrentCalcCount = info.CurrentCount; 
    ProgressText = info.Message; 
}); 
+0

非常感謝您的詳細解釋。我不瞭解UI消息循環。 從現在起我會考慮消息的優先級。再次感謝。 – ailen0ada

相關問題