rksoftware

Visual Studio とか C# とかが好きです

WPF で ProgressBar が動かない

「ProgressBar IsIndeterminate 動かない」という検索ワードでこのブログへたどり着く方がいらっしゃるようで、こういうことなのかは分かりませんがちょっと書いておこうと思います。
まずは WPF で ProgressBar を使う方法の記事です。

■ IsIndeterminate = true にしても動かない

次のコードでは、「ProgressBar は動きません

<Window x:Class="WpfApp1.MainWindow"
        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:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="250" Width="300">
    <StackPanel VerticalAlignment="Center">
        <ProgressBar x:Name="progressBar" IsIndeterminate="False" Height="10"/>
        <Button Content="Button" Click="Button_Click"/>
    </StackPanel>
</Window>
using System.Windows;

namespace WpfApp1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            progressBar.IsIndeterminate = true;
            // 10 秒かかる処理
            System.Threading.Thread.Sleep(10 * 1000);
            progressBar.IsIndeterminate = false;
        }
    }
}

ボタンクリックのイベントハンドラで、progressBar.IsIndeterminate = true; とした後に時間のかかる処理をしていますが残念ながら動きません。原因はボタンのイベントハンドラが UI スレッドで動作しているためです。UI スレッドで重い処理をしているので UI がブロックされて、画面表示の更新もブロックされしまいます。いわゆる「応答していません」状態になっています。

■ 動くようにする

using System.Windows;

namespace WpfApp1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            progressBar.IsIndeterminate = true;
            // 10 秒かかる処理
            await System.Threading.Tasks.Task.Delay(10 * 1000);
            progressBar.IsIndeterminate = false;
        }
    }
}

イベントハンドラを async にし重い処理も async にします。こうすることで重い処理がバックグラウンドのスレッドで行われるようになり、UI が更新されるようになります。
※注意: UI がブロックされなくなったことで、重い処理中に画面の操作ができるようになってしまいます。例えばボタンを連打するなどが可能になってしまいます。重い処理中は画面のコントロールをすべて無効化するなどの対策も必要になります。