動的に画面上のコントロールを表示制御する

LightSwitchファーストタッチ3(コントロール制御)ではコントロールの表示制御をコードから行う方法を紹介しました。しかしこの方法ではデータの動的な変化に合わせて制御することは簡単ではありません。
ここではデータバインドを利用して簡単に動的に画面上のコントロールを表示制御する方法を紹介します。これは、LightSwitchがMVVMベースに作成されていてScreenがViewModelに相当し、LightSwitchにおいてもViewModelの実装テクニックが利用できる点を応用しています。具体的には、入出力用のデータ以外の表示制御用のプロパティを用意してコントロールのVisibilityやIsEnabledにバインドすることにより、画面上のコントロールの表示制御を行います。

データ(エンティティ)に表示制御用のプロパティを作成する

まずは表示制御用のプロパティを定義します。他のプロパティ値をベースに表示制御するような場合、計算されたプロパティを利用します。以下の例はShipPostalCodeの値の有無で変化するIsAvailableShipAddressを定義しました。

        partial void IsAvailableShipAddress_Compute(ref bool result)
        {
            result = !string.IsNullOrEmpty(ShipPostalCode);
        }

ScreenのCreatedイベントで表示制御プロパティをバインドする

作成した表示制御プロパティをバインドするためにはFindControlでScreen要素(IContentItemProxy型)を取得してSetBindingを実行します。SetBindingはSilverlightと同様に値コンバータやBindingModeも利用でいきます*1

        partial void OrdersListDetail_Created()
        {
            this.FindControl("ShipAddress1")
                .SetBinding(TextBox.VisibilityProperty,
                    "Screen.Orders.SelectedItem.IsAvailableShipAddress",
                    new BoolToVisibilityConverter(),
                    System.Windows.Data.BindingMode.OneWay);

            //this.FindControl("ShipAddress1")
            //    .SetBinding(TextBox.IsEnabledProperty,
            //    "Screen.Orders.SelectedItem.IsAvailableShipAddress");
        }

実行するとShipPostalCode項目のテキストを空文字にし他の項目に移動すると、ShipAddress1の項目が自動的に非表示になります。さらにテキストを入力して他の項目に移動すると表示されるようになります。

この方式は、各種イベントでコントロールを直接操作する方法に比べて、バインドの実装方式はシンプルな構造で見通しもよい実装になるのもメリットの1つです。ただし、FindControlInCollectionで取得したアイテムについてはSetBindingは利用できないようでエラー「SetBinding は、コレクション内にあるコントロールではサポートされていません...」が発生します。DataGridで利用できないのは残念です。

コンバーターを配置する

Silverlightは標準では値コンバータをほとんどもっていません。今回VisibilityとBoolの変換を行う値コンバータが必要になります。LightSwicthに共通的なライブラリを配置する方法はいくつかありますが、今回はソースコードをLightSwitchのソリューションに配置するようにします。やり方は、LightSwitchのソリューションの表示をファイルビューに変更してUserCodeフォルダにファイルを配置すればまとめてビルドしてくれます。

    public class BoolToVisibilityConverter: IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return ((bool)value == true) ? Visibility.Visible : Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

まとめ

LightSwicthで動的に表示制御するためには、表示制御用のプロパティを作成し、VisibilityやIsEnabledにバインドすることで実装できます。LightSwicthは決まった画面を簡単に作成でるだけで柔軟性にかけるようなイメージを持つかもしれませんが、MVVMをベースにしているのでこのようなMVVMのテクニックを活用することで思っているよりも柔軟な画面を作る事ができます。このテクニックは背景や文字色の動的な変化なども同じような仕組みで実装できるので応用範囲が広いものです。うまく利用することでLightSwitchの利用範囲をもっと大きくできるでしょう。

*1:いちいちSilverlightのコントロールを取得しないくてもIContentItemProxyにSetBindingメソッドが用意されているということは、バインドでの実装方式はLightSwitchでの実装シナリオとしてはじめから想定されているように感じます