WPF:配列からRadioButtonを自動生成するItemsControlを作成
タイトルの通りItemsSourceにboolとstringを持ったオブジェクトの配列を渡すことでRadioButtonを生成するコントロールのサンプルです。
サンプルはGitHubにアップしてみました。 github.com
ItemsControlを継承したカスタムコントロールとなっております、利用時にはResourceDictionaryの読み込みが必要な感じになっています。ResourceDictionaryたいしたことは書いていませんが、改善で拡張する際にあったほうが便利かと思いつけました。
一応、使い方を。 ①RadioButtonList.csとRadioButtonList.xamlをプロジェクトに追加
②利用するView(ウィンドウなど)またはApp.xamlなど参照可能な場所に
<ResourceDictionary Source="/radiobuttonlist;component/RadioButtonList.xaml"/>
上記のリソースを読み込んだうえで、
<ctl:RadioButtonList xmlns:ctl="clr-namespace:radiobuttonlist" ItemsSource="{Binding Items}" CheckedItem="{Binding CheckedItem}" TitleMemberPath="Title" IsCheckedMemberPath="IsChecked"/>
上記のような感じのタグで配置します。
③ViewModel側ではItemsSourceに指定した配列クラスの「IsCheckプロパティにバインドしたいプロパティ名」を「IsCheckedMemberPath」に、 「キャプションとして表示したい文字列のプロパティ名」を「IsCheckedMemberPath」に指定します。
こんな感じで使えるかと。
例えば、上記のタグに下記のようなデータクラスをバインドした場合、
//ItemsはItemsSourceプロパティとバインドされたObservableCollection Items.Add(new RadioButtonItem() { IsChecked = true, Title = "test1" }); Items.Add(new RadioButtonItem() { IsChecked = false, Title = "test2" }); Items.Add(new RadioButtonItem() { IsChecked = false, Title = "test3" }); Items.Add(new RadioButtonItem() { IsChecked = false, Title = "test4" }); Items.Add(new RadioButtonItem() { IsChecked = false, Title = "test5" });
下記のような画面が表示されます。
また、IsCheckedプロパティがTrueになったオブジェクトはCheckedItemプロパティに格納されます。
作成時、ItemTempleteの動的生成部分はちょっと作るのが大変でした。
//ItemTemplateをプロパティ値から動的に作成 var elementFactory = new FrameworkElementFactory(typeof(RadioButton)); if (!string.IsNullOrEmpty(TitleMemberPath)) { elementFactory.SetValue(RadioButton.ContentProperty, new Binding(TitleMemberPath)); } if (!string.IsNullOrEmpty(IsCheckedMemberPath)) { elementFactory.SetValue(RadioButton.IsCheckedProperty, new Binding(IsCheckedMemberPath)); } elementFactory.SetValue(RadioButton.GroupNameProperty, string.IsNullOrEmpty(GroupName) ? Guid.NewGuid().ToString() : GroupName); elementFactory.AddHandler(RadioButton.CheckedEvent, new RoutedEventHandler(CheckedMethod)); this.ItemTemplate = new DataTemplate { VisualTree = elementFactory };
書きづらいし読みづらいとも思いますが、Bindingオブジェクトも色々手を付けられ、イベントに対応したメソッドも簡単に取り付けられるのは便利だと思いました。