簡體   English   中英

UI線程被阻止

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM