Простая привязка радиокнопки WPF?

Как проще всего связать группу из 3 радиокнопок со свойством типа int для значений 1, 2 или 3?

 Alexander Zwitbaum06 нояб. 2009 г., 16:43
Пожалуйста, посмотрите на решениеПривязка IsChecked свойство RadioButton в WPF, Отлично работает. Первоначальная проблема была исправлена в WPF 4.0!
 Steve Streeting28 дек. 2012 г., 13:54
Лучшее и более общее решение можно найти в этом ответе:stackoverflow.com/a/406798/414306
 Nifle23 авг. 2009 г., 09:40
Посмотрите на эту запись в блоге:> WPF RadioButtons и привязка данных

Ответы на вопрос(7)

предположим, у вас есть 3 логических свойства OptionA, OptionB, OptionC.

XAML:

<radiobutton ischecked="{Binding OptionA}">
<radiobutton ischecked="{Binding OptionB}">
<radiobutton ischecked="{Binding OptionC}">
</radiobutton></radiobutton></radiobutton>

КОД:

private bool _optionA;
public bool OptionA
{
    get { return _optionA; }
    set
    {
        _optionA = value;
        if( _optionA )
        {
             this.OptionB= false;
             this.OptionC = false;
        }
    }
}

private bool _optionB;
public bool OptionB
{
    get { return _optionB; }
    set
    {
        _optionB = value;
        if( _optionB )
        {
            this.OptionA= false;
            this.OptionC = false;
        }
    }
}

private bool _optionC;
public bool OptionC
{
    get { return _optionC; }
    set
    {
        _optionC = value;
        if( _optionC )
        {
            this.OptionA= false;
            this.OptionB = false;
        }
    }
}

Вы поняли идею. Не самая чистая вещь, но простая.

что никто не придумал такое решение, чтобы связать его с массивом bool. Возможно, он не самый чистый, но его можно использовать очень легко:

private bool[] _modeArray = new bool[] { true, false, false};
public bool[] ModeArray
{
    get { return _modeArray ; }
}
public int SelectedMode
{
    get { return Array.IndexOf(_modeArray, true); }
}

в XAML:

<radiobutton groupname="Mode" ischecked="{Binding Path=ModeArray[0], Mode=TwoWay}">
<radiobutton groupname="Mode" ischecked="{Binding Path=ModeArray[1], Mode=TwoWay}">
<radiobutton groupname="Mode" ischecked="{Binding Path=ModeArray[2], Mode=TwoWay}">
</radiobutton></radiobutton></radiobutton>

ПРИМЕЧАНИЕ: вам не нужно двухстороннее связывание, если вы не хотите, чтобы один отмечен по умолчанию. Двухстороннее связывание является самым большим минусом этого решения.

Плюсы:

Нет необходимости в коде позадиНет необходимости в дополнительном классе (IValue Converter)Нет необходимости в дополнительных перечисленияхне требует связывания Bizzareпросто и легко понятьне нарушает MVVM (хе, по крайней мере, я на это надеюсь)
 mmangual8308 июл. 2018 г., 04:31
Во-первых, отличное загрязнение. У меня есть один вопрос, так как яЯ новичок в WPF: как мне это настроить, где я могу проверить, какой вариант выбран?
 wondra31 мая 2018 г., 18:29
@RayBrennan эта опция на самом деле не подходит для динамического набора данных (не думайте, что это возможно в .xaml). Если вам нужно более сложное использование, я бы предложил выбрать одно из более сложных решений, а именно: конвертер (... или генерировать ставки в заднем коде).
 oopbase12 мая 2016 г., 10:08
Небольшой совет: с C # 6 ты выигралТебе больше не нужно отступать. Просто используйте AutoProperty: public bool [] ModeArray {get; } = new bool [] {true, false, false};
 wondra09 июл. 2018 г., 10:25
@ mmangual83 Ваш вопрос довольно двусмысленный: если вы имеете в виду, как установить значение по умолчанию для радиогруппы, вы должны установить соответствующий элемент_modeArray буквальныйtrue(первый в примере). Если вы спрашиваете, как предварительно просмотреть значение по умолчанию в конструкторе, ответ будет таким же, как и любой другой привязки, через /.d:DataContextd:DesignInstance
 QuantumHive26 авг. 2014 г., 13:53
Я тоже удивлен этим. Это решение предназначено для тех, кто не знаком с WPF, знает только, как сделать привязку и хочет быструю привязку для переключателей. Это'очень просто и понятно. +1
 mmangual8310 июл. 2018 г., 02:35
@wondra Я хочу сказать следующее: скажем, я выбираю радиокнопку из вашей коллекции ModeArray, тогда как мне настроить обратный вызов или метод, который прослушивает, когда радиокнопка была отмечена?
 Ray Brennan31 мая 2018 г., 12:41
Как это может быть обусловлено данными? Если я загружаю значения из базы данных, как я могу установить опцию программно?
 Forest Kunecke07 янв. 2015 г., 20:59
Это хорошо, очень быстро добавить тест, прежде чем выписывать мой собственныйConverter, +1

У меня есть класс model.cs с:

private int _isSuccess;
public int IsSuccess { get { return _isSuccess; } set { _isSuccess = value; } }

У меня есть файл Window1.xaml.cs с DataContext, установленным в model.cs. XAML содержит радиокнопки:

<radiobutton ischecked="{Binding Path=IsSuccess, Converter={StaticResource radioBoolToIntConverter}, ConverterParameter=1}" content="one">
<radiobutton ischecked="{Binding Path=IsSuccess, Converter={StaticResource radioBoolToIntConverter}, ConverterParameter=2}" content="two">
<radiobutton ischecked="{Binding Path=IsSuccess, Converter={StaticResource radioBoolToIntConverter}, ConverterParameter=3}" content="three">
</radiobutton></radiobutton></radiobutton>

Вот мой конвертер:

public class RadioBoolToIntConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        int integer = (int)value;
        if (integer==int.Parse(parameter.ToString()))
            return true;
        else
            return false;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return parameter;
    }
}

И конечно же в Window1 'Ресурсы:

<window.resources>
    <local:radiobooltointconverter x:key="radioBoolToIntConverter">
</local:radiobooltointconverter></window.resources>
 Rob Hardy22 июл. 2013 г., 16:59
Гораздо чище, чем принятый ответ - именно то, что я искал.
 Ignacio Soler Garcia12 апр. 2012 г., 23:05
Вам просто нужно изменить ваш конвертер на Parse Enum
 MarqueIV14 июл. 2012 г., 02:38
Опять же, это не будет работать для двусторонней привязки. 'Конвертировать Назад Вызов будет пытаться, чтобы несколько вещей по-разному устанавливали значения привязки, и в этом случае вы сталкиваетесь с условием гонки, когда один пытается установить свойство IsSuccess на одно значение, а другой пытается установить его на другое. Тот'Проблема с этим подходом. Конечно, этоменьше кода, но у вас все еще есть отдельные элементы управления, которые пытаются изменить одно свойство. (Помните, что когда вы выбираете одну радиокнопку, она отменяет выбор другой, поэтому происходят два изменения.)
 MoonKnight31 июл. 2013 г., 22:22
Как установить значение по умолчанию. То есть выбрать первый переключатель при первом отображении окна?
 user115192302 янв. 2013 г., 16:11
@MarqueIV Эта проблема легко решается, как видно из первого комментария для принятого ответа на этот вопрос:stackoverflow.com/questions/397556/...
 MarqueIV02 янв. 2013 г., 18:05
Одна вещь @ user1151923 ... нетв этом случае нужно вернутьсяBinding.DoNothing» и не 'DependencyProperty.UnsetValue?
 MarqueIV07 нояб. 2010 г., 22:43
Проблема с этим конвертером, это неt работать с перечислениями в качестве параметра (ваш вызов ToString () умирает.) Смотрите мой ответ ниже.
 James McDuffie26 нояб. 2018 г., 06:10
Я действительно предпочитаю эту версию, проголосовал!
 Gábor02 мая 2014 г., 20:10
Но, пожалуйста, нетif (true) возвращает true; иначе вернуть ложь; " конструирует ... :-)
 MarqueIV02 янв. 2013 г., 17:32
Хорошо, этодовольно приятный трюк! Я'дам тебе это! Я'Я также дам вам голосование за ссылку. Тем не менее, способ выше, хотя и более многословный, позволяет вам делать другие вещи, как показано на рисунке, поэтому яоставлю это здесь.

мы придумали решение, используяBinding.DoNothing возвращается из конвертера, который нене нарушать двустороннюю привязку.

public class EnumToCheckedConverter : IValueConverter
{
    public Type Type { get; set; }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value != null && value.GetType() == Type)
        {
            try
            {
                var parameterFlag = Enum.Parse(Type, parameter as string);

                if (Equals(parameterFlag, value))
                {
                    return true;
                }
            }
            catch (ArgumentNullException)
            {
                return false;
            }
            catch (ArgumentException)
            {
                throw new NotSupportedException();
            }

            return false;
        }
        else if (value == null)
        {
            return false;
        }

        throw new NotSupportedException();
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value != null && value is bool check)
        {
            if (check)
            {
                try
                {
                    return Enum.Parse(Type, parameter as string);
                }
                catch(ArgumentNullException)
                {
                    return Binding.DoNothing;
                }
                catch(ArgumentException)
                {
                    return Binding.DoNothing;
                }
            }

            return Binding.DoNothing;
        }

        throw new NotSupportedException();
    }
}

Использование:

<converters:enumtocheckedconverter x:key="SourceConverter" type="{x:Type monitor:VariableValueSource}">
</converters:enumtocheckedconverter>

Привязки радиокнопок:

<radiobutton groupname="ValueSource" ischecked="{Binding Source, Converter={StaticResource SourceConverter}, ConverterParameter=Function}">Function</radiobutton>

но его намерение должно быть совершенно ясным.

Он использует 3 логических свойства в ViewModel под названием,FlagForValue1FlagForValue2 а такжеFlagForValue3, Каждое из этих 3 свойств поддерживается одним частным полем с именем._intValue

Каждая из трех радиокнопок вида (xaml) привязана к соответствующему свойству Flag в модели вида. Это означает, что радио-кнопка отображаетЗначение 1 " связан сFlagForValue1 свойство bool в представлении модели и двух других соответственно.

При установке одного из свойств в модели представления (например,FlagForValue1) важно также инициировать события изменения свойств для двух других свойств (например,FlagForValue2, а такжеFlagForValue3) поэтому пользовательский интерфейс (WPFINotifyPropertyChanged инфраструктура) можно выбрать / отменить выбор каждого переключателя правильно.

    private int _intValue;

    public bool FlagForValue1
    {
        get
        {
            return (_intValue == 1) ? true : false;
        }
        set
        {
            _intValue = 1;
            RaisePropertyChanged("FlagForValue1");
            RaisePropertyChanged("FlagForValue2");
            RaisePropertyChanged("FlagForValue3");
        }
    }

    public bool FlagForValue2
    {
        get
        {
            return (_intValue == 2) ? true : false;
        }
        set
        {
            _intValue = 2;
            RaisePropertyChanged("FlagForValue1");
            RaisePropertyChanged("FlagForValue2");
            RaisePropertyChanged("FlagForValue3");
        }
    }

    public bool FlagForValue3
    {
        get
        {
            return (_intValue == 3) ? true : false;
        }
        set
        {
            _intValue = 3;
            RaisePropertyChanged("FlagForValue1");
            RaisePropertyChanged("FlagForValue2");
            RaisePropertyChanged("FlagForValue3");
        }
    }

XAML выглядит так:

                <radiobutton groupname="Search" ischecked="{Binding Path=FlagForValue1, Mode=TwoWay}">Value 1</radiobutton>

                <radiobutton groupname="Search" ischecked="{Binding Path=FlagForValue2, Mode=TwoWay}">Value 2</radiobutton>

                <radiobutton groupname="Search" ischecked="{Binding Path=FlagForValue3, Mode=TwoWay}">Value 3</radiobutton>
 Mohit Jain23 июл. 2015 г., 09:45
Пожалуйста, добавьте некоторые объяснения
 Jonathan Allen02 окт. 2016 г., 07:49
Гадкий как грех, но этов основном то, что я делаю тоже.

Это, кстати, уже давно, но у меня есть альтернативное решение, которое легче и проще. Получите класс отSystem.Windows.Controls.RadioButton и объявить два свойства зависимостиRadioValue а такжеRadioBinding, Затем в коде класса переопределитеOnChecked и установитьRadioBinding значение свойства к тому изRadioValue стоимость имущества. В другом направлении ловушка меняется наRadioBinding свойство с помощью обратного вызова, и если новое значение равно значениюRadioValue свойство, установите егоIsChecked собственность на.true

Вот's код:

public class MyRadioButton : RadioButton
{
    public object RadioValue
    {
        get { return (object)GetValue(RadioValueProperty); }
        set { SetValue(RadioValueProperty, value); }
    }

    // Using a DependencyProperty as the backing store for RadioValue.
       This enables animation, styling, binding, etc...
    public static readonly DependencyProperty RadioValueProperty =
        DependencyProperty.Register(
            "RadioValue", 
            typeof(object), 
            typeof(MyRadioButton), 
            new UIPropertyMetadata(null));

    public object RadioBinding
    {
        get { return (object)GetValue(RadioBindingProperty); }
        set { SetValue(RadioBindingProperty, value); }
    }

    // Using a DependencyProperty as the backing store for RadioBinding.
       This enables animation, styling, binding, etc...
    public static readonly DependencyProperty RadioBindingProperty =
        DependencyProperty.Register(
            "RadioBinding", 
            typeof(object), 
            typeof(MyRadioButton), 
            new FrameworkPropertyMetadata(
                null, 
                FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, 
                OnRadioBindingChanged));

    private static void OnRadioBindingChanged(
        DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        MyRadioButton rb = (MyRadioButton)d;
        if (rb.RadioValue.Equals(e.NewValue))
            rb.SetCurrentValue(RadioButton.IsCheckedProperty, true);
    }

    protected override void OnChecked(RoutedEventArgs e)
    {
        base.OnChecked(e);
        SetCurrentValue(RadioBindingProperty, RadioValue);
    }
}

Использование XAML:

<my:myradiobutton groupname="grp1" content="Value 1" radiovalue="val1" radiobinding="{Binding SelectedValue}">
<my:myradiobutton groupname="grp1" content="Value 2" radiovalue="val2" radiobinding="{Binding SelectedValue}">
<my:myradiobutton groupname="grp1" content="Value 3" radiovalue="val3" radiobinding="{Binding SelectedValue}">
<my:myradiobutton groupname="grp1" content="Value 4" radiovalue="val4" radiobinding="{Binding SelectedValue}">
</my:myradiobutton></my:myradiobutton></my:myradiobutton></my:myradiobutton>

Надеюсь, кто-то найдет это полезным после всего этого времени :)

 DonBoitnott15 нояб. 2018 г., 17:17
Очень хорошее решение, спасибо за публикацию. Так намного чище и проще в реализации.
Решение Вопроса

использование такого конвертера нарушает двустороннее связывание, плюс, как я уже говорил выше, вы можетене используйте это и с перечислениями. Лучший способ сделать это - использовать простой стиль для ListBox, например так:

Примечание: вопреки тому, что DrWPF.com указал в своем примере, сделайтене Поместите ContentPresenter внутри RadioButton или, если вы добавите элемент с содержимым, таким как кнопка или что-то еще, вы не сможете установить фокус или взаимодействовать с ним. Эта техника решает это. Кроме того, вам нужно обрабатывать серую текст, а также удалять поля на ярлыках, иначе он будет отображаться неправильно. Этот стиль подходит и для вас.

<style x:key="RadioButtonListItem" targettype="{x:Type ListBoxItem}">

    <Setter Property="Template">
        <Setter.Value>

            <ControlTemplate TargetType="ListBoxItem">

                <DockPanel LastChildFill="True" Background="{TemplateBinding Background}" HorizontalAlignment="Stretch" VerticalAlignment="Center" >

                    <RadioButton IsChecked="{TemplateBinding IsSelected}" Focusable="False" IsHitTestVisible="False" VerticalAlignment="Center" Margin="0,0,4,0" />

                    <ContentPresenter
                        Content             = "{TemplateBinding ContentControl.Content}"
                        ContentTemplate     = "{TemplateBinding ContentControl.ContentTemplate}"
                        ContentStringFormat = "{TemplateBinding ContentControl.ContentStringFormat}"
                        HorizontalAlignment = "{TemplateBinding Control.HorizontalContentAlignment}"
                        VerticalAlignment   = "{TemplateBinding Control.VerticalContentAlignment}"
                        SnapsToDevicePixels = "{TemplateBinding UIElement.SnapsToDevicePixels}" />

                </DockPanel>

            </ControlTemplate>

        </Setter.Value>

    </Setter>

</style>

<style x:key="RadioButtonList" targettype="ListBox">

    <Style.Resources>
        <Style TargetType="Label">
            <Setter Property="Padding" Value="0" />
        </style>
    

    <setter property="BorderThickness" value="0">
    <setter property="Background" value="Transparent">

    <setter property="ItemContainerStyle" value="{StaticResource RadioButtonListItem}">

    <setter property="Control.Template">
        <setter.value>
            <controltemplate targettype="{x:Type ListBox}">
                <itemspresenter snapstodevicepixels="{TemplateBinding UIElement.SnapsToDevicePixels}">
            </itemspresenter></controltemplate>
        </setter.value>
    </setter>

    <style.triggers>
        <trigger property="IsEnabled" value="False">
            <setter property="TextBlock.Foreground" value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}">
        </setter></trigger>
    </style.triggers>



<style x:key="HorizontalRadioButtonList" basedon="{StaticResource RadioButtonList}" targettype="ListBox">
    <Setter Property="ItemsPanel">
        <Setter.Value>
            <ItemsPanelTemplate>
                <VirtualizingStackPanel Background="Transparent" Orientation="Horizontal" />
            </ItemsPanelTemplate>
        </Setter.Value>
    </Setter>
</style>
</setter></setter></setter>

Теперь у вас есть внешний вид переключателей, но вы можете выполнить двустороннее связывание и использовать перечисление. Вот'шоу...

<listbox style="{StaticResource RadioButtonList}" selectedvalue="{Binding SomeVal}" selectedvaluepath="Tag">

    <listboxitem tag="{x:Static l:MyEnum.SomeOption}">Some option</listboxitem>
    <listboxitem tag="{x:Static l:MyEnum.SomeOtherOption}">Some other option</listboxitem>
    <listboxitem tag="{x:Static l:MyEnum.YetAnother}">Yet another option</listboxitem>

</listbox>

Кроме того, поскольку мы явно отделили стиль, который отслеживает ListBoxItem, а не помещаем его в строку, опять же, как показали другие примеры, теперь вы можете создать новый стиль для него, чтобы настраивать элементы для каждого элемента, такие как интервал. (Это не будет работать, если вы просто попытаетесь настроить таргетинг на ListBoxItem, так как стиль ключа переопределяет общие цели управления.)

Вот'Пример размещения поля 6 выше и ниже каждого элемента. (Обратите внимание, как вы должны явно применять стиль через свойство ItemContainerStyle, а не просто нацеливать ListBoxItem в ListBox 'секция ресурса по вышеуказанной причине.)

<window.resources>
    <style x:key="SpacedRadioButtonListItem" targettype="ListBoxItem" basedon="{StaticResource RadioButtonListItem}">
        <Setter Property="Margin" Value="0,6" />
    </style>
</window.resources>

<listbox style="{StaticResource RadioButtonList}" itemcontainerstyle="{StaticResource SpacedRadioButtonListItem}" selectedvalue="{Binding SomeVal}" selectedvaluepath="Tag">

    <listboxitem tag="{x:Static l:MyEnum.SomeOption}">Some option</listboxitem>
    <listboxitem tag="{x:Static l:MyEnum.SomeOtherOption}">Some other option</listboxitem>
    <listboxitem tag="{x:Static l:MyEnum.YetAnother}">Ter another option</listboxitem>

</listbox>
 Konrad Morawski30 апр. 2012 г., 15:36
+1, но если этоthe simplest way to bind a group of 3 radiobuttons to a property of type int for values 1, 2, or 3на самом деле, это не очень хорошо для WPF. Это'действительно вне меня, почему они делают самые простые вещи такими головокружительно трудными и ненужно сложными
 MarqueIV19 мар. 2015 г., 05:17
Тот'На самом деле несправедливое утверждение. Взгляните на шаблон элемента управления для обычной кнопки, используя, например, ShowMeTheTemplate. этодалеко от простого, но все же его использования, добавление тега Button очень просто. Вы'подглядывать под одеялом с тем, что яЯ делаю здесь, но если вместо этого вы просто добавите это в свой раздел ресурсов, то забудьте об этом, это тоже будет просто.
 MarqueIV19 мар. 2015 г., 05:21
Плюс, подумай о том, что тыкомментируем ... разрозненные средства управления радио, действующие на одно значение. Несколько элементов управления означает несколько привязок. Этот стиль делает один элемент управления - и, следовательно, одно значение - похожим на несколько элементов управления. Тот'почему это здорово Кроме того, это также можно использовать для привязки к IEnumerable и динамического создания элементов. Можно'сделать это с помощью радиокнопки.
 Matt18 мар. 2015 г., 11:49
О боже, просто? При всем уважении к вашему ответу и усилиям, но призываю этопростой стиль " довольно надуманно, нет? Isn»Основная идея и предполагаемое преимущество WPF перед Winforms лучше связывание данных? То, как простая радиокнопка (и группировка радиокнопок) нарушает связывание после нескольких лет присутствия WPF на рынке, мне не совсем понятно. Позор MS.
 MarqueIV30 апр. 2012 г., 17:43
Это на самом деле немного больше, чем просто, поскольку он стилизует список, который является единым элементом управления, и это 'Вот почему привязка работает так просто (как только вы справитесь с ее сумасшедшей настройкой). Но да, я согласен, что класс RadioButton определенно имеет некоторые недостатки связывания. Конечно, вы могли бы сделать это намного проще с помощью code-behind, но в этом случае вам нужно будет сделать стили и тому подобное один раз, тогда использовать его позже будет намного проще.

Ваш ответ на вопрос