Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
197 views
in Technique[技术] by (71.8m points)

c# - MVVM: Binding radio buttons to a view model?

EDIT: Problem was fixed in .NET 4.0.

I have been trying to bind a group of radio buttons to a view model using the IsChecked button. After reviewing other posts, it appears that the IsChecked property simply doesn't work. I have put together a short demo that reproduces the problem, which I have included below.

Here is my question: Is there a straightforward and reliable way to bind radio buttons using MVVM? Thanks.

Additional information: The IsChecked property doesn't work for two reasons:

  1. When a button is selected, the IsChecked properties of other buttons in the group don't get set to false.

  2. When a button is selected, its own IsChecked property does not get set after the first time the button is selected. I am guessing that the binding is getting trashed by WPF on the first click.

Demo project: Here is the code and markup for a simple demo that reproduces the problem. Create a WPF project and replace the markup in Window1.xaml with the following:

<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>

Replace the code in Window1.xaml.cs with the following code (a hack), which sets the view model:

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

Now add the following code to the project as 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));
            }
        }

    }
}

To reproduce the problem, run the app and click Button A. A message box will appear, saying that Button A's IsChecked property has been set to true. Now select Button B. Another message box will appear, saying that Button B's IsChecked property has been set to true, but there is no message box indicating that Button A's IsChecked property has been set to false--the property hasn't been changed.

Now click Button A again. The button will be selected in the window, but no message box will appear--the IsChecked property has not been changed. Finally, click on Button B again--same result. The IsChecked property is not updated at all for either button after the button is first clicked.

Question&Answers:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If you start with Jason's suggestion then the problem becomes a single bound selection from a list which translates very nicely to a ListBox. At that point it's trivial to apply styling to a ListBox control so that it shows up as a RadioButton list.

<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>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...