简体   繁体   中英

Indeterminate progress bar not animating

Here is the code that instantiate a window with an indeterminate progress bar, this code is called in a viewmdodel of some view :

Views.InstallingWindow installing = new Views.InstallingWindow();
installing.Show();
Application.Current.Dispatcher.Invoke(timeConsumingMethod, DispatcherPriority.Normal);
installing.Close();

And here is the xaml of the window

<Window x:Class="Blabla.Views.InstallingWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:PatcherClient.Views"
    mc:Ignorable="d"
    Title="InstallingWindow" Height="150" Width="300"
    WindowStartupLocation="CenterScreen">
<Grid>
    <StackPanel Margin="10">
        <ProgressBar Width="200" Height="20" Margin="10" Orientation="Horizontal" IsIndeterminate="True" />
        <TextBlock HorizontalAlignment="Center" Name="StatusText" Margin="10" Height="50" Foreground="Black" Text="Installing ..."/>
    </StackPanel>
</Grid>

On my computer, the progress bar does not animate. How to fix it ?

This will execute timeConsumingMethod on the dispatcher thread:

Application.Current.Dispatcher.Invoke(timeConsumingMethod, DispatcherPriority.Normal);

And the dispatcher cannot both execute your method and animate the ProgressBar simultaneously.

You want to execute timeConsumingMethod on a background thread. The easiest way to do this is to start a new Task and then close the window once the task has completed:

Views.InstallingWindow installing = new Views.InstallingWindow();
installing.Show();
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
    timeConsumingMethod();
}).ContinueWith(task =>
{
    installing.Close();
}, System.Threading.CancellationToken.None, System.Threading.Tasks.TaskContinuationOptions.None, 

System.Threading.Tasks.TaskScheduler.FromCurrentSynchronizationContext());

Note that for this to work, you cannot access any UIElement in your timeConsumingMethod() method. A UIElement may only be accessed on the UI thread on which it was originally created.

Dispatcher.Invoke executes your timeConsumingMethod delegate on the UI thread so it will be blocked.

Try this instead in an async method:

installing.Show();
await Task.Run(() => timeConsumingMethod());
installing.Close();

If your timeConsumingMethod accesses any UI component (eg. sets control properties), then you should wrap these accesses into Dispatcher.Invoke only.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM