首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >MVVM:将单选按钮绑定到视图模型?

MVVM:将单选按钮绑定到视图模型?
EN

Stack Overflow用户
提问于 2010-02-18 06:05:54
回答 11查看 70.8K关注 0票数 67

编辑:问题已在.NET 4.0中修复。

我一直在尝试使用IsChecked按钮将一组单选按钮绑定到视图模型。在查看其他帖子后,IsChecked属性似乎根本不起作用。我已经做了一个简短的演示,重现了这个问题,我把它包含在下面。

我的问题是:有没有一种简单可靠的方法来使用MVVM绑定单选按钮?谢谢。

附加信息: IsChecked属性不起作用有两个原因:

  1. 选择按钮时,组中其他按钮的IsChecked属性不会设置为false。
  2. 选择按钮时,在第一次选择按钮后不会设置其自身的IsChecked属性。我猜这个绑定在第一次点击时就被WPF丢弃了。

演示项目:这里是一个再现问题的简单演示的代码和标记。创建一个WPF项目并将Window1.xaml中的标记替换为以下内容:

代码语言:javascript
运行
复制
<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中的代码替换为设置视图模型的以下代码( hack):

代码语言:javascript
运行
复制
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添加到项目中

代码语言:javascript
运行
复制
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。现在选择按钮B。此时将出现另一个消息框,说明按钮B的IsChecked属性已设置为true,但没有消息框指示按钮A的IsChecked属性已设置为false--该属性尚未更改。

现在再次单击按钮A。该按钮将在窗口中处于选中状态,但不会出现消息框-- IsChecked属性尚未更改。最后,再次单击Button B--结果相同。第一次单击这两个按钮后,该按钮的IsChecked属性根本不会更新。

EN

回答 11

Stack Overflow用户

回答已采纳

发布于 2010-02-18 09:28:10

如果你从Jason的建议开始,那么问题就变成了列表中的单个绑定选择,它可以很好地转换为ListBox。在这一点上,将样式应用于ListBox控件以使其显示为RadioButton列表是很容易的。

代码语言:javascript
运行
复制
<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>
票数 56
EN

Stack Overflow用户

发布于 2010-03-15 09:50:29

看起来他们修复了对.NET 4中IsChecked属性的绑定。在VS2008中中断的项目在VS2010中工作。

票数 21
EN

Stack Overflow用户

发布于 2010-02-19 03:42:43

对于任何研究这个问题的人来说,这是我最终实现的解决方案。它建立在John Bowen的答案的基础上,我选择该答案作为问题的最佳解决方案。

首先,我为一个包含单选按钮的透明列表框创建了一个样式。然后,我创建了列表框中的按钮--我的按钮是固定的,而不是作为数据读取到应用程序中,所以我将它们硬编码到标记中。

我在视图模型中使用一个名为ListButtons的枚举来表示列表框中的按钮,并使用每个按钮的Tag属性传递用于该按钮的枚举值的字符串值。ListBox.SelectedValuePath属性允许我将Tag属性指定为选定值的源,我使用SelectedValue属性将选定值绑定到视图模型。我认为我需要一个值转换器来在字符串和它的枚举值之间进行转换,但是WPF的内置转换器处理转换没有问题。

下面是Window1.xaml的完整标记

代码语言:javascript
运行
复制
<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>

视图模型只有一个属性SelectedButton,它使用ListButtons枚举来显示选择了哪个按钮。该属性调用我用于视图模型的基类中的事件,这将引发PropertyChanged事件:

代码语言:javascript
运行
复制
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");
            }
        }

    }
} 

在我的生产应用程序中,SelectedButton设置器将调用一个服务类方法,该方法将在选择按钮时执行所需的操作。

为了完整,下面是基类:

代码语言:javascript
运行
复制
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
    }
}

希望这能有所帮助!

票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2284752

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档