SilverlightアプリでWebサービスのコール時に通信中ダイアログを表示する

Silverlightの場合、Webサービスコールは非同期となります。そのため、普通にコーディングした場合、ユーザはWebサービス中にも画面を操作することができます。これはこれで便利なのですが、作り手側の視点で見ると「連続して同じWebサービスを呼ばれた時の挙動は?」「サービスコール中にそのページが閉じられたら?」などの懸念が出てきます。また、ユーザからみても、画面に動きがないのはボタンを押せなかったからなのかWebサービスコール中だからなのかわからない、などの問題が発生します。
そこで、サービスコール中に通信中ダイアログを表示して現在処理中であることをユーザに知らせるとともに、他の操作を行えないようにします。

アジェンダ

ChildWindow

通信中ダイアログには、ChildWindowを使います。ChildWindowを使用するときは、System.Windows.Controls.dllをプロジェクトに追加するのを忘れないようにしましょう。
今回は、ChildWindowの見た目をそのまま使います。実際にリリースするアプリケーションの場合は、デザインを変えると良いと思います。

匿名メソッドとクロージャWebサービスコール

Webサービスコール前にChildWindowを開いたら、そのChildWindowのインスタンスをCompletedイベントハンドラに渡す必要があります。クラスのフィールドにChildWindowのインスタンスを保持しても良いのですが、クロージャで渡すことでシンプルな記述にします。

// 通信中ダイアログを表示
ChildWindow dialog = new ChildWindow();
dialog.Title = "通信中";
dialog.HasCloseButton = false;
dialog.Content = "通信中です。" + Environment.NewLine + "しばらくお待ちください。";
dialog.Show();

// サービス参照の追加で生成したプロキシクラスのインスタンスを生成する。
HelloWorldServiceClient client = new HelloWorldServiceClient();

// WCFコール終了後に発生するイベントにイベントハンドラを匿名メソッドで登録する
client.GetMessageCompleted += (s1, e1) =>
{
    // ダイアログを閉じる。
    dialog.Close();

    // サービスの戻り値を処理する。
    string result = e1.Result;
    TblResult.Text = result;
};

// GetMessageを呼ぶ。
client.GetMessageAsync(name);

Modelに委譲

私の場合は、Webサービスコール部分をModelに移して、呼ぶ側はメソッド引数にコールバックメソッドを渡す方法を良くとります。

public class MainPageModel
{
    public void GetMessageAsync(
        string name,
        Action<GetMessageCompletedEventArgs> completed)
    {
        HelloWorldServiceClient client = new HelloWorldServiceClient();
        client.GetMessageCompleted += (object sender, GetMessageCompletedEventArgs e) =>
        {
            // サービスからの応答が来たら、引数で渡されたcompletedに結果を渡す。
            if (completed != null)
            {
                completed(e);
            }
        };

        client.GetMessageAsync(name);
    }
}
//// WCFサービス呼び出し側のコード

// 通信中ダイアログを表示
ChildWindow dialog = new ChildWindow();
dialog.Title = "通信中";
dialog.HasCloseButton = false;
dialog.Content = "通信中です。" + Environment.NewLine + "しばらくお待ちください。";
dialog.Show();

string name = TbxName.Text;
MainPageModel model = new MainPageModel();
model.GetMessageAsync(name, (GetMessageCompletedEventArgs e1) =>
{
    // ダイアログを閉じる。
    dialog.Close();

    // 通信結果を処理する。
    TblResult.Text = e1.Result;
});