Dav*_*man 61 c# wpf binding mvvm radio-button
编辑:问题已在.NET 4.0中修复.
我一直在尝试使用IsChecked
按钮将一组单选按钮绑定到视图模型.在审查其他帖子后,该IsChecked
属性似乎根本不起作用.我已经整理了一个简短的演示,可以重现这个问题,我在下面列出了这个问题.
这是我的问题:使用MVVM绑定单选按钮是否有直接可靠的方法?谢谢.
附加信息:该IsChecked
物业不起作用有两个原因:
选择按钮后,组中其他按钮的IsChecked属性不会设置为false.
选择按钮后,第一次选择按钮后,其自身的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>
Run Code Online (Sandbox Code Playgroud)
使用以下代码(hack)替换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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在将以下代码添加到项目中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));
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
要重现该问题,请运行该应用程序并单击按钮A.将出现一个消息框,表示按钮A的IsChecked
属性已设置为true.现在选择Button B.将出现另一个消息框,表示Button B的IsChecked
属性已设置为true,但没有消息框指示Button A的IsChecked
属性已设置为false - 该属性尚未更改.
现在再次单击按钮A. 该按钮将在窗口中选中,但不会出现任何消息框 - 该IsChecked
属性尚未更改.最后,再次点击Button B - 结果相同.IsChecked
首次单击按钮后,任何按钮都不会更新该属性.
Joh*_*wen 53
如果你从Jason的建议开始,那么问题就会变成一个单一的绑定选择,从列表中可以很好地转换为a 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>
Run Code Online (Sandbox Code Playgroud)
Ran*_*ngy 19
看起来他们修复了绑定到IsChecked
.NET 4中的属性.在VS2008中破解的项目在VS2010中工作.
Dav*_*man 10
对于任何研究这个问题的人来说,这是我最终实施的解决方案.它以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>
Run Code Online (Sandbox Code Playgroud)
视图模型有一个属性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; }
set
{
p_SelectedButton = value;
base.RaisePropertyChangedEvent("SelectedButton");
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
在我的生产应用程序中,SelectedButton
setter将调用一个服务类方法,该方法将在选择按钮时执行所需的操作.
要完成,这里是基类:
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
}
}
Run Code Online (Sandbox Code Playgroud)
希望有所帮助!
归档时间: |
|
查看次数: |
63887 次 |
最近记录: |