C#erを自称しているのに、WPFやったことないなって思い始めてみました。
まずはだいたいどのアプリでも使いそうなComboBoxと値のバインドの忘備録。
コードは現在開発中の Reseacher のコードから抜粋。
ViewModel
MVVMだしViewModel使いますね。
MVVMとは?って方は この記事など参考にしてください。
using System.Collections.ObjectModel;
namespace Reseacher
{
public class ComboBoxViewModel
{
public ObservableCollection<Server> ServerItems { get; set; }
public ComboBoxViewModel(ServerRack serverRack)
{
ServerItems = serverRack;
}
}
}
ServerItemsプロパティがComboBoxにバインドしたいクラスです。
内部には string Name { get; set; }
プロパティを保持しています。
上記コードで肝になるのが ObservableCollection<T>
。
こいつはListなどと同じでT型の配列を持てます。
違うところは コレクションに変更があった場合にイベントを発火する ところ。
何が嬉しいかは以下で説明します。まずは上記Boldのところだけ覚えておきましょう。
Xaml
<ComboBox x:Name="serverComboBox"
ItemsSource="{Binding ServerItems, Mode=OneWay}"
Grid.Column="1"
DisplayMemberPath="Name"/>
Name
オブジェクトの固有名称を表します。
ItemSource
今回バインドしたいプロパティ。ComboBoxViewModel.cs
のグローバル変数ですね。
Modeオプションについては一方向か双方向を選択できます。詳しくはMSDN参照。
方法: バインディングの方向を指定する
DisplayMemberPath
「ItemSourceで指定したプロパティの中のどのプロパティを表示するか」を設定します。
フォームアプリケーションと違ってタグでさっぱり書けるのがいいですね。
手動でInitializeComponent触らなくていいのが嬉しいです。
バインド
var model = new ComboBoxViewModel(Nucleus.ServerRack);
serverComboBox.DataContext = model;
ViewModelのインスタンスを生成します。
自分はStaticClassの値をバインドしたかったのでコンストラクタで渡して処理していますが、
ViewModelクラスのプロパティに値が設定できればなんでも構いません。
生成後、XAMLで作成したオブジェクトのDataContextにViewModelを渡します。
これで実行すれば、以下の通りバインド処理が走ってコンボボックスが表示できます。
- ViewModel内のプロパティ
ObservableCollection<T>
がコンボボックスにバインドされる - T内のNameプロパティがコンボボックスの描画欄に描画される
双方向バインディング
ここからがキモです。
上の方で話していた通り、ObservableCollectionの何が嬉しいかを解説します。
例えば、コード側でObservableCollectionのItemを一つ削除したとします。
Formアプリケーションの方なら、「同期のために画面のComboBox側のItemも削除しなきゃ・・」となるでしょう。
ObservableCollectionでは不要です。
ObservableCollectionに対し、追加・削除が行われた場合、変更通知イベントが着火します。
それがView側に通知され、View側のComboBoxの値が自動的に変更されます。
また、画面側から値が追加・削除された場合も同じです。双方向バインディングですね。
一点注意が必要なのが、
コレクションのアイテムのプロパティが変更された場合はObservableCollectionで拾えません。
その場合は INotifyPropertyChanged
を使用します。
詳しくは次回以降で。
C#はしくみは良いけどForm側がイマイチだなと思っていたので、WPFの仕組みは素晴らしいですね。
一方向の仕組みですが、Reactっぽいなと思うところがチラホラ。
双方向バインディング便利すぎて脳汁出た。