XamBusyIndicator を表示させ、データ生成は非同期で実行したものの、データを表示するレンダリングの処理(このとき UI スレッドで動く XamBusyIndicator は表示されません)が重くて結局待ち時間が長く感じてしまうことがあります。

たとえば、グリッドの階層データを開いた状態で表示する処理

階層データを持つ Grid を表示する際に、階層を開いた状態にしたい場合、データ生成・取得の処理が速くても、UI スレッドで実行される Expand 処理にとても時間がかかることがあります。

以下のような処理

// ボタンがクリックされたら、xamBusyIndicator を表示させ、データ生成処理を非同期で実行する。
private async void button1_Click(object sender, RoutedEventArgs e)
{
    //this.xamBusyIndicator1.DisplayAfter = new TimeSpan(0, 0, 0, 0); // 表示遅延を0秒に変更

    // XamBusyIndicator の IsBusy を true にして表示する
    this.xamBusyIndicator1.IsBusy = true;

    // xamDataGridのデータ初期化を行う
    this.xamDataGrid1.DataSource = new List<Item>();

    // データ生成処理を非同期で実行する
    var resultData = await Task.Run(() => this.CreateData());

    this.xamDataGrid1.DataSource = resultData;

    // 階層データを持つ xamDataGrid を全展開する処理
    this.xamDataGrid1.Records.ExpandAll(true); ?

    // XamBusyIndicator の IsBusy を false にして非表示にする
    this.xamBusyIndicator1.IsBusy = false;
}

この処理では展開するデータが多いほど時間がかかり、 UI スレッドをブロックし画面が止まったようになってしまいます。

今回は、この止まった待ち時間にも XamBusyIndicator を表示させる方法をご紹介します。

1レコードずつ展開をし、都度再描画を実行させる。

xamDataGrid の全レコードを一気に展開すると一度の処理に時間がかかってしまい、画面が再描画されずに止まったように見えてしまいます。それを回避するため、レコードを1つずつ展開し、且つ展開毎に再描画できるようにします。

以下のコードです。

// ボタンがクリックされたら、xamBusyIndicator を表示させ、データ生成処理を非同期で実行する。
private async void button1_Click(object sender, RoutedEventArgs e)
{
    //this.xamBusyIndicator1.DisplayAfter = new TimeSpan(0, 0, 0, 0); // 表示遅延を0秒に変更

    // XamBusyIndicator の IsBusy を true にして表示する
    this.xamBusyIndicator1.IsBusy = true;

    // xamDataGridのデータ初期化を行う
    this.xamDataGrid1.DataSource = new List<Item>();

    // データ生成処理を非同期で実行する
    var resultData = await Task.Run(() => this.CreateData());

    this.xamDataGrid1.DataSource = resultData;

    // 階層データを持つ xamDataGrid をレコード毎に展開し、都度 Task.Delay を実行する。
    foreach (var record in this.xamDataGrid1.Records.Cast<Record>())
    {
        record.IsExpanded = true;
        await Task.Delay(1); ?
    }

    // XamBusyIndicator の IsBusy を false にして非表示にする
    this.xamBusyIndicator1.IsBusy = false;
}

1レコードずつ展開し、都度 Task.Delay を実行することで、再描画のチャンスを作る方法です。

これにより、止まって見えていた展開時の処理中にも XamBusyIndicator が表示され待ち時間をつなぐことができます。

デメリットとしては、総合した展開時間は一括展開時よりも長くかかってしまう点です。使い分けが重要ですね。ぜひご活用ください。

製品について

Ultimate UI for WPF