![]() |
风度翩翩的消防车 · 让周琦转会便秘的CBA签字费,为什么只能说存 ...· 7 月前 · |
![]() |
含蓄的米饭 · 罗兰贝格:唯一一家来自欧洲的顶级咨询公司- 知乎· 1 年前 · |
![]() |
刚分手的鼠标 · 祁象:忆童年之六:“自制火柴手枪”_链条· 1 年前 · |
编辑: 问题已在.NET 4.0中修复。
我一直在尝试使用
IsChecked
按钮将一组单选按钮绑定到视图模型。在查看其他帖子后,
IsChecked
属性似乎根本不起作用。我已经做了一个简短的演示,重现了这个问题,我把它包含在下面。
我的问题是:有没有一种简单可靠的方法来使用MVVM绑定单选按钮?谢谢。
附加信息:
IsChecked
属性不起作用有两个原因:
演示项目: 这里是一个再现问题的简单演示的代码和标记。创建一个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中的代码替换为设置视图模型的以下代码( hack):
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; }
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; }
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
属性根本不会更新。
发布于 2010-02-18 09:28:10
如果你从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>
发布于 2010-03-15 09:50:29
看起来他们修复了对.NET 4中
IsChecked
属性的绑定。在VS2008中中断的项目在VS2010中工作。
发布于 2010-02-19 03:42:43
对于任何研究这个问题的人来说,这是我最终实现的解决方案。它建立在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 -->
<!-- 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
事件:
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; }
p_SelectedButton = value;
base.RaisePropertyChangedEvent("SelectedButton");
}
在我的生产应用程序中,
SelectedButton
设置器将调用一个服务类方法,该方法将在选择按钮时执行所需的操作。
为了完整,下面是基类:
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);