読者です 読者をやめる 読者になる 読者になる

RunningCSharp

.net中心の開発話。記事は個人の見解であり、所属組織を代表するものてはありません。

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" });

下記のような画面が表示されます。

f:id:ys-soniclab:20160730230748p:plain

また、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オブジェクトも色々手を付けられ、イベントに対応したメソッドも簡単に取り付けられるのは便利だと思いました。