RadioButtonのカスタムコントロールにenumのリストをバインドしたい

投稿者: Anonymous

WPFで、同じGroupNameを持つRadioButtonのリストを構成するカスタムコントロールを作ろうとしています。
このカスタムコントロールは、次のDependencyPropertyを持ちます。

ItemsSourceenumのコレクション(enumなら何でもOK)
SelectedValue:選択されているRadioButtonに対応するenumの値

enumの値からRadioButtonの表示テキスト(Content)への変換は、IValueConverterを実装して適当に処理しています。
ItemsSourceからRadioButtonを生成する処理には、ItemsControlを利用しました。

ここまでは問題なかったのですが、SelectedValueプロパティと、対応するRadioButtonIsCheckedを結びつける方法が分かりません。
ItemsControlを使わず、XAMLで静的に作られたものであれば、各RadioButtonCoverterParameterに対応するenumの値を記述し、Converterに渡すだけで良いことは分かるのですが、動的にラジオボタンを作ろうとして詰まってしまいました。
下記のコードの、ConvertParameter={Binding}の部分が問題です。

<ItemsControl Name="itemsControl" ItemsSource="{Binding ItemsSource, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}">

    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <RadioButton IsChecked="{
                             Binding SeletedValue,
                             Converter={StaticResource RadioButtonCheckedConverter},
                             ConverterParameter={Binding},
                             RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}
                         }"
                         GroupName="{Binding GroupName, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"
                         Content="{Binding Converter={StaticResource RadioButtonTextConverter}}"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>

</ItemsControl>

このままでは

型 'Binding' の 'ConverterParameter' プロパティで 'Binding' を設定することはできません。
'Binding' は、DependencyObject の DependencyProperty でのみ設定できます。

というエラーが出てしまい、動作しません。
何とかして、RadioButtonCheckedConverterに各RadioButtonにバインドされているenumの値をConverterParameterとして渡したいのですが・・・
どなたか何かご存知でしたら、教えてください。

解決

添付プロパティを使用してRadioButtonCheckedイベントを拾ってやる必要があると思います。

public class Radio
{
    public static object GetSelectedValue(RadioButton obj)
    {
        return (object)obj.GetValue(SelectedValueProperty);
    }

    public static void SetSelectedValue(RadioButton obj, object value)
    {
        obj.SetValue(SelectedValueProperty, value);
    }

    public static readonly DependencyProperty SelectedValueProperty =
       DependencyProperty.RegisterAttached("SelectedValue", typeof(object), typeof(Radio), new FrameworkPropertyMetadata(null, OnSelectedValueChanged) { BindsTwoWayByDefault = true });

    private static void OnSelectedValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var rb = (RadioButton)d;

        rb.Checked -= rb_Checked;
        rb.Checked += rb_Checked;
        rb_Checked(rb, null);
    }

    static void rb_Checked(object sender, RoutedEventArgs e)
    {
        var rb = (RadioButton)sender;
        if (rb.IsChecked == true)
        {
            SetSelectedValue(rb, rb.DataContext);
        }
    }
}

使用例

<RadioButton local:Radio.SelectedValue="{Binding SelectedValue, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}" />
回答者: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *