[英]UI thread is blocked
在MainWindow中,我有一個顯示忙碌指示器的async
方法
public async Task BusyLoaderAsync(Action doWorkAction)
{
using (var tokenSource = new CancellationTokenSource())
{
await loadingPanel.StartSpinAsync(tokenSource.Token).ConfigureAwait(false);
await this.Dispatcher.InvokeAsync(doWorkAction);
tokenSource.Cancel();
await loadingPanel.StopSpinAsync().ConfigureAwait(false);
}
}
加載面板看起來像:
<Grid Panel.ZIndex="1000" HorizontalAlignment="Stretch" Grid.RowSpan="3" Visibility="{Binding PanelLoading, Converter={StaticResource BoolToVis}}">
<controls:LoadingPanel x:Name="loadingPanel" VerticalAlignment="Stretch"
IsLoading="{Binding PanelLoading}"
Message="Calculating..."
SubMessage="Wait a minute"
/>
</Grid>
控制加載面板還有2種其他方法:
public async Task StartSpinAsync(CancellationToken cancellationToken)
{
int delay;
if (!int.TryParse(ConfigurationManager.AppSettings["ApplicationDelay"], out delay))
{
delay = 0;
}
await Task.Delay(delay, cancellationToken);
await this.Dispatcher.InvokeAsync(() => IsLoading = true,
System.Windows.Threading.DispatcherPriority.Normal, cancellationToken);
}
public async Task StopSpinAsync()
{
await this.Dispatcher.InvokeAsync(() => IsLoading = false,
System.Windows.Threading.DispatcherPriority.Normal);
}
我們只想顯示加載程序,除非確實需要時間。 當某些任務執行的時間少於延遲時的原因-就像眨眼一樣。
當我需要顯示指標時,我嘗試下一個:
_mainWindow.BusyLoaderAsync(() => _resultViewModel.InitChart(lineChart, generalChart)).ConfigureAwait(false); // code which initialize WPF toolkit chart as example
問題-顯示指示器時,它沒有旋轉,而是凍結了。 我認為這是因為UI線程被阻止了。
是否可以檢查哪個塊UI線程,並且可以從上面的代碼中對其進行檢查?
這是BusyLoaderAsync(Action doWorkAction)
有問題的實現,因為它依賴於doWorkAction
實現。 如果doWorkAction
是同步的,例如:
BusyLoaderAsync(() =>
{
Debug.WriteLine(" == Action Start ");
Thread.Sleep(8000);
Debug.WriteLine(" == Action End ");
});
然后它將鎖定UI線程,直到doWorkAction
結束之前,UI中都不會更新。 結束后, tokenSource.Cancel();
取消忙碌指示器,它永遠不會更新。
如果doWorkAction
是異步的,例如:
BusyLoaderAsync(async () =>
{
Debug.WriteLine(" == Action Start ");
await Task.Delay(8000);
Debug.WriteLine(" == Action End ");
});
然后doWorkAction
運行速度更快,然后StartSpinAsync
並最終tokenSource.Cancel();
在開始之前取消忙碌指示器,並且也從不指示。
在同步情況下,如果doWorkAction
可在另一線程中運行, BusyLoaderAsync
可如下
public async Task BusyLoaderAsync(Action doWorkAction)
{
using (var tokenSource = new CancellationTokenSource())
{
var tasks = new[] { Task.Run(doWorkAction), Task.Delay(1000) };
var result = Task.WaitAny(tasks);
if (result == 1)
{
loadingPanel.IsLoading = true;
await tasks[0];
loadingPanel.IsLoading = false;
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.