In MainWindow I have async
method which displays busy Indicator
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);
}
}
Loading Panel looks like :
<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>
Control Loading Panel has 2 additional methods :
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);
}
We want to show loader only if it realy takes time. Cause when some task executes less than some delay - it is like blink.
When I need to show indicator I try next :
_mainWindow.BusyLoaderAsync(() => _resultViewModel.InitChart(lineChart, generalChart)).ConfigureAwait(false); // code which initialize WPF toolkit chart as example
Problem - when indicator is shown, it doesn't spining, it is freezed. I think it is because UI thread is blocked.
Is it possible to check what block UI thread and is it possible to check it from code above?
It is problematic implementation of BusyLoaderAsync(Action doWorkAction)
because it depends on doWorkAction
implementation. If doWorkAction
is synchronous like:
BusyLoaderAsync(() =>
{
Debug.WriteLine(" == Action Start ");
Thread.Sleep(8000);
Debug.WriteLine(" == Action End ");
});
then it locks UI thread, and nothing updates in UI until doWorkAction
ends. After it ends, tokenSource.Cancel();
cancels the busy indicator, and it can never updates.
If doWorkAction
is asynchronous like:
BusyLoaderAsync(async () =>
{
Debug.WriteLine(" == Action Start ");
await Task.Delay(8000);
Debug.WriteLine(" == Action End ");
});
then doWorkAction
runs faster then StartSpinAsync
and eventually tokenSource.Cancel();
cancels the busy indicator before it starts, and it also never indicates.
In synchronous case, if doWorkAction
can run in another thread, BusyLoaderAsync
can be as following
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;
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.