任何人都可以告诉我为什么在重度计算期间UI会冻结:
var ret = await Task.Run(() => this._service.CalcFourier(100000, progress));
我有一个绑定'Value'属性的进度条,但在计算完成之前不会更新。当我将断点设置为'CurrentCalcCount'的setter方法并开始计算时,每次都调用'RaisePropertyChanged'。
如何避免阻止UI ...我整天都在努力,我不知道为什么。任何机构都可以修复代码或者有一些解释来帮助我吗?感谢。
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 :(得分:0)
看起来您的处理代码充满了更新的UI。完成一对双精度分割和整数加法不需要很长时间;只需构建进度报告字符串几乎肯定会花费更长的时间。
而不是:
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;
});