Program Tip

MVVM : 라디오 버튼을 뷰 모델에 바인딩합니까?

programtip 2020. 12. 1. 19:40
반응형

MVVM : 라디오 버튼을 뷰 모델에 바인딩합니까?


편집 : 문제는 .NET 4.0에서 수정되었습니다.

버튼을 사용하여 라디오 버튼 그룹을 뷰 모델에 바인딩하려고했습니다 IsChecked. 다른 게시물을 검토 한 결과 해당 IsChecked속성이 작동하지 않는 것으로 보입니다 . 아래에 포함 된 문제를 재현하는 짧은 데모를 모았습니다.

내 질문은 다음과 같습니다. MVVM을 사용하여 라디오 버튼을 바인딩하는 간단하고 안정적인 방법이 있습니까? 감사.

추가 정보 :IsChecked속성은 다음 두 가지 이유로 작동하지 않습니다.

  1. 버튼을 선택하면 그룹에있는 다른 버튼의 IsChecked 속성이 false로 설정되지 않습니다 .

  2. 단추를 선택하면 단추를 처음 선택한 후 자체 IsChecked 속성이 설정되지 않습니다. 첫 번째 클릭에서 바인딩이 WPF에 의해 삭제되고 있다고 생각합니다.

데모 프로젝트 : 다음은 문제를 재현하는 간단한 데모의 코드와 마크 업입니다. WPF 프로젝트를 만들고 Window1.xaml의 태그를 다음으로 바꿉니다.

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300" Loaded="Window_Loaded">
    <StackPanel>
        <RadioButton Content="Button A" IsChecked="{Binding Path=ButtonAIsChecked, Mode=TwoWay}" />
        <RadioButton Content="Button B" IsChecked="{Binding Path=ButtonBIsChecked, Mode=TwoWay}" />
    </StackPanel>
</Window>

Window1.xaml.cs의 코드를보기 모델을 설정하는 다음 코드 (핵)로 바꿉니다.

using System.Windows;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            this.DataContext = new Window1ViewModel();
        }
    }
}

이제 프로젝트에 다음 코드를 다음과 같이 추가합니다 Window1ViewModel.cs.

using System.Windows;

namespace WpfApplication1
{
    public class Window1ViewModel
    {
        private bool p_ButtonAIsChecked;

        /// <summary>
        /// Summary
        /// </summary>
        public bool ButtonAIsChecked
        {
            get { return p_ButtonAIsChecked; }
            set
            {
                p_ButtonAIsChecked = value;
                MessageBox.Show(string.Format("Button A is checked: {0}", value));
            }
        }

        private bool p_ButtonBIsChecked;

        /// <summary>
        /// Summary
        /// </summary>
        public bool ButtonBIsChecked
        {
            get { return p_ButtonBIsChecked; }
            set
            {
                p_ButtonBIsChecked = value;
                MessageBox.Show(string.Format("Button B is checked: {0}", value));
            }
        }

    }
}

문제를 재현하려면 앱을 실행하고 버튼 A를 클릭합니다. 버튼 A의 IsChecked속성이 true 로 설정되었다는 메시지 상자가 나타납니다 . 이제 Button B를 선택합니다. Button B의 IsChecked속성이 true 로 설정되었다는 또 다른 메시지 상자가 표시 되지만 Button A의 IsChecked속성이 false 로 설정 되었음을 나타내는 메시지 상자 가 없습니다. 속성이 변경되지 않았습니다.

이제 버튼 A를 다시 클릭하십시오. 창에서 버튼이 선택되지만 메시지 상자는 나타나지 IsChecked않으며 속성이 변경되지 않았습니다. 마지막으로 버튼 B를 다시 클릭하면 같은 결과가 나타납니다. IsChecked버튼을 먼저 클릭 한 후 속성 중 버튼 전혀 업데이트되지 않습니다.


Jason의 제안으로 시작하면 문제는 목록에서 단일 바운드 선택이되어 ListBox. 이 시점에서 ListBox컨트롤에 스타일을 적용 하여 RadioButton목록 으로 표시되도록하는 것은 간단 합니다.

<ListBox ItemsSource="{Binding ...}" SelectedItem="{Binding ...}">
    <ListBox.ItemContainerStyle>
        <Style TargetType="{x:Type ListBoxItem}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListBoxItem}">
                        <RadioButton Content="{TemplateBinding Content}"
                                     IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsSelected}"/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

IsChecked.NET 4 속성에 대한 바인딩을 수정 한 것 같습니다 . VS2008에서 중단 된 프로젝트는 VS2010에서 작동합니다.


이 질문을 연구하는 모든 사람을 위해 궁극적으로 구현 한 솔루션은 다음과 같습니다. 문제에 대한 최상의 솔루션으로 선택한 John Bowen의 답변을 기반으로합니다.

먼저 라디오 버튼을 항목으로 포함하는 투명한 목록 상자의 스타일을 만들었습니다. 그런 다음 목록 상자에 들어갈 버튼을 만들었습니다. 내 버튼은 데이터로 앱으로 읽어 들이지 않고 고정되어 있으므로 마크 업에 하드 코딩했습니다.

ListButtons뷰 모델에서 호출 열거 형을 사용 하여 목록 상자의 단추를 나타내고 각 단추의 Tag속성을 사용하여 해당 단추에 사용할 열거 형 값의 문자열 값을 전달합니다. ListBox.SelectedValuePath속성을 사용 Tag하면 선택한 값의 소스로 속성 을 지정할 수 있으며, 속성을 사용하여 뷰 모델에 바인딩 SelectedValue합니다. 문자열과 열거 형 값 사이를 변환하려면 값 변환기가 필요하다고 생각했지만 WPF의 기본 제공 변환기는 문제없이 변환을 처리했습니다.

다음은 Window1.xaml에 대한 완전한 마크 업입니다 .

<Window x:Class="RadioButtonMvvmDemo.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">

    <!-- Resources -->
    <Window.Resources>
        <Style x:Key="RadioButtonList" TargetType="{x:Type ListBox}">
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="ItemContainerStyle">
                <Setter.Value>
                    <Style TargetType="{x:Type ListBoxItem}" >
                        <Setter Property="Margin" Value="5" />
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="{x:Type ListBoxItem}">
                                    <Border BorderThickness="0" Background="Transparent">
                                        <RadioButton 
                                            Focusable="False"
                                            IsHitTestVisible="False"
                                            IsChecked="{TemplateBinding IsSelected}">
                                            <ContentPresenter />
                                        </RadioButton>
                                    </Border>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </Setter.Value>
            </Setter>
            <Setter Property="Control.Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListBox}">
                        <Border BorderThickness="0" Padding="0" BorderBrush="Transparent" Background="Transparent" Name="Bd" SnapsToDevicePixels="True">
                            <ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>

    <!-- Layout -->
    <Grid>
        <!-- Note that we use SelectedValue, instead of SelectedItem. This allows us 
        to specify the property to take the value from, using SelectedValuePath. -->

        <ListBox Style="{StaticResource RadioButtonList}" SelectedValuePath="Tag" SelectedValue="{Binding Path=SelectedButton}">
            <ListBoxItem Tag="ButtonA">Button A</ListBoxItem>
            <ListBoxItem Tag="ButtonB">Button B</ListBoxItem>
        </ListBox>
    </Grid>
</Window>

뷰 모델에는 선택된 버튼을 표시하기 위해 ListButtons 열거 형을 사용하는 단일 속성 SelectedButton이 있습니다. 이 속성은 뷰 모델에 사용하는 기본 클래스의 이벤트를 호출하여 이벤트를 발생시킵니다 PropertyChanged.

namespace RadioButtonMvvmDemo
{
    public enum ListButtons {ButtonA, ButtonB}

    public class Window1ViewModel : ViewModelBase
    {
        private ListButtons p_SelectedButton;

        public Window1ViewModel()
        {
            SelectedButton = ListButtons.ButtonB;
        }

        /// <summary>
        /// The button selected by the user.
        /// </summary>
        public ListButtons SelectedButton
        {
            get { return p_SelectedButton; }

            set
            {
                p_SelectedButton = value;
                base.RaisePropertyChangedEvent("SelectedButton");
            }
        }

    }
} 

내 프로덕션 앱에서 SelectedButtonsetter는 버튼이 선택 될 때 필요한 작업을 수행 할 서비스 클래스 메서드를 호출합니다.

완료하려면 다음은 기본 클래스입니다.

using System.ComponentModel;

namespace RadioButtonMvvmDemo
{
    public abstract class ViewModelBase : INotifyPropertyChanged
    {
        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        #region Protected Methods

        /// <summary>
        /// Raises the PropertyChanged event.
        /// </summary>
        /// <param name="propertyName">The name of the changed property.</param>
        protected void RaisePropertyChangedEvent(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChangedEventArgs e = new PropertyChangedEventArgs(propertyName);
                PropertyChanged(this, e);
            }
        }

        #endregion
    }
}

도움이 되었기를 바랍니다.


한 가지 해결책은 속성 setter에서 라디오 버튼에 대한 ViewModel을 업데이트하는 것입니다. Button A가 True로 설정되면 Button B를 false로 설정합니다.

DataContext의 개체에 바인딩 할 때 또 다른 중요한 요소는 개체가 INotifyPropertyChanged를 구현해야한다는 것입니다. 바인딩 된 속성이 변경되면 이벤트가 시작되고 변경된 속성의 이름이 포함되어야합니다. (간결성을 위해 샘플에서 Null 검사가 생략되었습니다.)

public class ViewModel  : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected bool _ButtonAChecked = true;
    public bool ButtonAChecked
    {
        get { return _ButtonAChecked; }
        set 
        { 
            _ButtonAChecked = value;
            PropertyChanged(this, new PropertyChangedEventArgs("ButtonAChecked"));
            if (value) ButtonBChecked = false;
        }
    }

    protected bool _ButtonBChecked;
    public bool ButtonBChecked
    {
        get { return _ButtonBChecked; }
        set 
        { 
            _ButtonBChecked = value; 
            PropertyChanged(this, new PropertyChangedEventArgs("ButtonBChecked"));
            if (value) ButtonAChecked = false;
        }
    }
}

편집하다:

문제는 버튼 B를 처음 클릭 할 때 IsChecked 값이 변경되고 바인딩이 전달되지만 버튼 A는 확인되지 않은 상태를 통해 ButtonAChecked 속성으로 전달되지 않는다는 것입니다. 코드에서 수동으로 업데이트하면 다음에 Button A를 클릭 할 때 ButtonAChecked 속성 설정자가 호출됩니다.


IsChecked 버그에 대해 확실하지 않은 경우 뷰 모델에 만들 수있는 한 가지 가능한 리팩터링 : 뷰에는 일련의 RadioButton으로 표시되는 상호 배타적 인 상태가 여러 개 있으며 지정된 시간에 하나만 선택할 수 있습니다. 뷰 모델에는 가능한 상태를 나타내는 1 개의 속성 (예 : 열거 형)이 있습니다. stateA, stateB 등 모든 개별 ButtonAIsChecked 등이 필요하지 않습니다.


할 수있는 또 다른 방법이 있습니다.

전망:

<StackPanel Margin="90,328,965,389" Orientation="Horizontal">
        <RadioButton Content="Mr" Command="{Binding TitleCommand, Mode=TwoWay}" CommandParameter="{Binding Content, RelativeSource={RelativeSource Mode=Self}, Mode=TwoWay}" GroupName="Title"/>
        <RadioButton Content="Mrs" Command="{Binding TitleCommand, Mode=TwoWay}" CommandParameter="{Binding Content, RelativeSource={RelativeSource Mode=Self}, Mode=TwoWay}" GroupName="Title"/>
        <RadioButton Content="Ms" Command="{Binding TitleCommand, Mode=TwoWay}" CommandParameter="{Binding Content, RelativeSource={RelativeSource Mode=Self}, Mode=TwoWay}" GroupName="Title"/>
        <RadioButton Content="Other" Command="{Binding TitleCommand, Mode=TwoWay}" CommandParameter="{Binding Content, RelativeSource={RelativeSource Mode=Self}}" GroupName="Title"/>
        <TextBlock Text="{Binding SelectedTitle, Mode=TwoWay}"/>
    </StackPanel>

ViewModel :

 private string selectedTitle;
    public string SelectedTitle
    {
        get { return selectedTitle; }
        set
        {
            SetProperty(ref selectedTitle, value);
        }
    }

    public RelayCommand TitleCommand
    {
        get
        {
            return new RelayCommand((p) =>
            {
                selectedTitle = (string)p;
            });
        }
    }

John Bowen의 답변에 대한 작은 확장 : 값이 구현되지 않으면 작동하지 않습니다 ToString(). ContentRadioButton을 TemplateBinding 으로 설정하는 대신 필요한 것은 다음 ContentPresenter과 같이 입력하면됩니다.

<ListBox ItemsSource="{Binding ...}" SelectedItem="{Binding ...}">
    <ListBox.ItemContainerStyle>
        <Style TargetType="{x:Type ListBoxItem}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListBoxItem}">
                        <RadioButton IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsSelected}">
                            <ContentPresenter/>
                        </RadioButton>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

이것은 당신이 추가로 사용할 수있는 방법 DisplayMemberPath이나 ItemTemplate적절한. RadioButton은 항목을 "래핑"하여 선택을 제공합니다.


라디오 버튼에 그룹 이름을 추가해야합니다.

   <StackPanel>
        <RadioButton Content="Button A" IsChecked="{Binding Path=ButtonAIsChecked, Mode=TwoWay}" GroupName="groupName" />
        <RadioButton Content="Button B" IsChecked="{Binding Path=ButtonBIsChecked, Mode=TwoWay}" GroupName="groupName" />
    </StackPanel>

나는 이것이 오래된 질문이고 원래 문제는 .NET 4에서 해결되었음을 알고 있으며 솔직히 이것은 약간 주제에서 벗어났습니다.

MVVM에서 RadioButtons를 사용하려는 대부분의 경우 enum의 요소 중에서 선택하는 것입니다 .이를 위해서는 VM 공간 bool 속성을 각 버튼에 바인딩하고 이를 사용 하여 실제 선택을 반영 하는 전체 enum 속성 을 설정 해야합니다. 이것은 매우 지루해집니다. 그래서 재사용이 가능하고 구현하기 쉽고 ValueConverters가 필요없는 솔루션을 생각해 냈습니다.

보기는 거의 동일하지만 열거 형 이 있으면 단일 속성으로 VM 측을 수행 할 수 있습니다.

MainWindowVM

using System.ComponentModel;

namespace EnumSelectorTest
{
  public class MainWindowVM : INotifyPropertyChanged
  {
    public EnumSelectorVM Selector { get; set; }

    private string _colorName;
    public string ColorName
    {
      get { return _colorName; }
      set
      {
        if (_colorName == value) return;
        _colorName = value;
        RaisePropertyChanged("ColorName");
      }
    }

    public MainWindowVM()
    {
      Selector = new EnumSelectorVM
        (
          typeof(MyColors),
          MyColors.Red,
          false,
          val => ColorName = "The color is " + ((MyColors)val).ToString()
        );
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void RaisePropertyChanged(string propertyName)
    {
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
  }
}

모든 작업을 수행하는 클래스는 DynamicObject에서 상속됩니다. 외부 에서 보면 XAML에서 바인딩 할 수있는 'Is', 'IsRed', 'IsBlue'등의 접두사가 붙은 열거 형의 각 요소에 대한 bool 속성을 만듭니다 . 실제 열거 형을 보유하는 Value 속성과 함께 .

public enum MyColors
{
  Red,
  Magenta,
  Green,
  Cyan,
  Blue,
  Yellow
}

EnumSelectorVM

using System;
using System.ComponentModel;
using System.Dynamic;
using System.Linq;

namespace EnumSelectorTest
{
  public class EnumSelectorVM : DynamicObject, INotifyPropertyChanged
  {
    //------------------------------------------------------------------------------------------------------------------------------------------
    #region Fields

    private readonly Action<object> _action;
    private readonly Type _enumType;
    private readonly string[] _enumNames;
    private readonly bool _notifyAll;

    #endregion Fields

    //------------------------------------------------------------------------------------------------------------------------------------------
    #region Properties

    private object _value;
    public object Value
    {
      get { return _value; }
      set
      {
        if (_value == value) return;
        _value = value;
        RaisePropertyChanged("Value");
        _action?.Invoke(_value);
      }
    }

    #endregion Properties

    //------------------------------------------------------------------------------------------------------------------------------------------
    #region Constructor

    public EnumSelectorVM(Type enumType, object initialValue, bool notifyAll = false, Action<object> action = null)
    {
      if (!enumType.IsEnum)
        throw new ArgumentException("enumType must be of Type: Enum");
      _enumType = enumType;
      _enumNames = enumType.GetEnumNames();
      _notifyAll = notifyAll;
      _action = action;

      //do last so notification fires and action is executed
      Value = initialValue;
    }

    #endregion Constructor

    //------------------------------------------------------------------------------------------------------------------------------------------
    #region Methods

    //---------------------------------------------------------------------
    #region Public Methods

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
      string elementName;
      if (!TryGetEnumElemntName(binder.Name, out elementName))
      {
        result = null;
        return false;
      }
      try
      {
        result = Value.Equals(Enum.Parse(_enumType, elementName));
      }
      catch (Exception ex) when (ex is ArgumentNullException || ex is ArgumentException || ex is OverflowException)
      {
        result = null;
        return false;
      }
      return true;
    }

    public override bool TrySetMember(SetMemberBinder binder, object newValue)
    {
      if (!(newValue is bool))
        return false;
      string elementName;
      if (!TryGetEnumElemntName(binder.Name, out elementName))
        return false;
      try
      {
        if((bool) newValue)
          Value = Enum.Parse(_enumType, elementName);
      }
      catch (Exception ex) when (ex is ArgumentNullException || ex is ArgumentException || ex is OverflowException)
      {
        return false;
      }
      if (_notifyAll)
        foreach (var name in _enumNames)
          RaisePropertyChanged("Is" + name);
      else
        RaisePropertyChanged("Is" + elementName);
      return true;
    }

    #endregion Public Methods

    //---------------------------------------------------------------------
    #region Private Methods

    private bool TryGetEnumElemntName(string bindingName, out string elementName)
    {
      elementName = "";
      if (bindingName.IndexOf("Is", StringComparison.Ordinal) != 0)
        return false;
      var name = bindingName.Remove(0, 2); // remove first 2 chars "Is"
      if (!_enumNames.Contains(name))
        return false;
      elementName = name;
      return true;
    }

    #endregion Private Methods

    #endregion Methods

    //------------------------------------------------------------------------------------------------------------------------------------------
    #region Events

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void RaisePropertyChanged(string propertyName)
    {
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion Events
  }
}

변경 사항에 응답하려면 NotifyPropertyChanged 이벤트를 구독하거나 위에서 수행 한대로 생성자에 익명 메서드를 전달할 수 있습니다.

그리고 마지막으로 MainWindow.xaml

<Window x:Class="EnumSelectorTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">  
  <Grid>
    <StackPanel>
      <RadioButton IsChecked="{Binding Selector.IsRed}">Red</RadioButton>
      <RadioButton IsChecked="{Binding Selector.IsMagenta}">Magenta</RadioButton>
      <RadioButton IsChecked="{Binding Selector.IsBlue}">Blue</RadioButton>
      <RadioButton IsChecked="{Binding Selector.IsCyan}">Cyan</RadioButton>
      <RadioButton IsChecked="{Binding Selector.IsGreen}">Green</RadioButton>
      <RadioButton IsChecked="{Binding Selector.IsYellow}">Yellow</RadioButton>
      <TextBlock Text="{Binding ColorName}"/>
    </StackPanel>
  </Grid>
</Window>

다른 누군가가 유용하다고 생각하기를 바랍니다. 왜냐하면 나는 이것이 내 도구 상자에 있다고 생각하기 때문입니다.


I have a very similar problem in VS2015 and .NET 4.5.1

XAML:

                <ListView.ItemsPanel>
                    <ItemsPanelTemplate>
                        <UniformGrid Columns="6" Rows="1"/>
                    </ItemsPanelTemplate>
                </ListView.ItemsPanel>
                <ListView.ItemTemplate>
                    <DataTemplate >
                        <RadioButton  GroupName="callGroup" Style="{StaticResource itemListViewToggle}" Click="calls_ItemClick" Margin="1" IsChecked="{Binding Path=Selected,Mode=TwoWay}" Unchecked="callGroup_Checked"  Checked="callGroup_Checked">

....

As you can see in this code i have a listview, and items in template are radiobuttons that belongs to a groupname.

If I add a new item to the collection with the property Selected set to True it appears checked and the rest of buttons remain checked.

I solve it by getting the checkedbutton first and set it to false manually but this is not the way it's supposed to be done.

code behind:

`....
  lstInCallList.ItemsSource = ContactCallList
  AddHandler ContactCallList.CollectionChanged, AddressOf collectionInCall_change
.....
Public Sub collectionInCall_change(sender As Object, e As NotifyCollectionChangedEventArgs)
    'Whenever collection change we must test if there is no selection and autoselect first.   
    If e.Action = NotifyCollectionChangedAction.Add Then
        'The solution is this, but this shouldn't be necessary
        'Dim seleccionado As RadioButton = getCheckedRB(lstInCallList)
        'If seleccionado IsNot Nothing Then
        '    seleccionado.IsChecked = False
        'End If
        DirectCast(e.NewItems(0), PhoneCall).Selected = True
.....
End sub

`


<RadioButton  IsChecked="{Binding customer.isMaleFemale}">Male</RadioButton>
    <RadioButton IsChecked="{Binding customer.isMaleFemale,Converter=      {StaticResource GenderConvertor}}">Female</RadioButton>

Below is the code for IValueConverter

public class GenderConvertor : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return !(bool)value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return !(bool)value;
    }
}

this worked for me. Even value got binded on both view and viewmodel according to the radio button click. True--> Male and False-->Female

참고URL : https://stackoverflow.com/questions/2284752/mvvm-binding-radio-buttons-to-a-view-model

반응형