WPF MVVM中的Radiobuttons Ischecked属性无法工作

3
我无法将两个具有相同分组名称的单选按钮与XAML表单和IsChecked属性绑定起来,我还使用了NullableToBoolConverters。但是,在我的代码中,单选按钮的IsChecked属性不会改变(一旦我们点击第一个单选按钮后,它就根本没有遇到断点),我需要分别绑定两个单选按钮的IsChecked属性,因为我需要基于单选按钮属性设置表单上其他面板的可见性。

以下是我的XAML代码,后面是用于RadioButton属性的ViewModel.cs代码:
   <RadiobuttonSelectedConverter x:Key="CheckedSelection"/>// declaring my converter class in my resource dictionary.

  <StackPanel Orientation="Horizontal" Grid.Column="0" Grid.Row="3" Margin="10,5,0,0">
        <RadioButton GroupName="RadiosGroup" IsChecked="{Binding IsRadioButton1,Mode=TwoWay,
             Converter={StaticResource CheckedSelection}, ConverterParameter=true}">
                    First</RadioButton>
        <RadioButton GroupName="RadiosGroup" 
                     Margin="40,0,0,0" IsChecked="{Binding IsRadioButton2,Mode=TwoWay, 
            Converter={StaticResource CheckedSelection}, ConverterParameter=true}">Second</RadioButton>
    </StackPanel>



    private bool _isRadioButton1;

    public bool IsRadioButton1
    {
        get
        {
            return _isRadioButton1;
        }
        set
        {
            if _isRadioButton1!= value)
            {
                _isRadioButton1= value;

                IsRadioButton2= false;
                OnPropertyChanged("IsRadioButton1");

            }
        }
    }


    private bool _isRadioButton2;

    public bool IsRadioButton2
    {
        get
        {
            return _isRadioButton2;
        }
        set
        {
            if (_isRadioButton2 != value)
            {
                _isRadioButton2 = value;

              IsRadioButton1= false;
              OnPropertyChanged("IsRadioButton2");

            }
        }
    }

以下是我的转换器代码:
  [ValueConversion(typeof(bool?), typeof(bool))]
public class RadiobuttonSelectedConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        bool param = bool.Parse(parameter.ToString());
        if (value == null)
        {
            return false;
        }
        else
        {
            return !((bool)value ^ param);
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        bool param = bool.Parse(parameter.ToString());
        return !((bool)value ^ param);
    }
}

有人能帮我解决问题吗?提前感谢。


1
你的转换器看起来很奇怪。为什么不直接返回 value == param - Daniel Hilgarth
哦,谢谢你提供的信息。我实际上正在使用这个链接中的代码 - “http://geekswithblogs.net/claraoscura/archive/2008/10/17/125901.aspx”,但是它好像出了问题。你能告诉我具体是哪里出了问题吗? - user1105705
@user1105705,由于您的属性是 bool 类型,它不能为 null,那么您为什么要首先使用 Converter 呢?如果没有转换器,您的代码是否能正常工作? - Rachel
是的,但它只会触发更改的属性一次...我的意思是在第一次选择单选按钮时...而不是每次。 - user1105705
2个回答

6
个人而言,我不会像这样编写关联的RadioButtons。由于您想要的选择行为与ListBox相同,因此我发现最简单的方法是使用一个被样式化为每个项目使用RadioButtonsListBox
代码后台通常包含:
  • ObservableCollection<string> Options
  • string SelectedOption
我将使用这种样式来呈现ListBox
<Style x:Key="RadioButtonListBoxStyle" TargetType="{x:Type ListBox}">
    <Setter Property="BorderBrush" Value="Transparent"/>
    <Setter Property="KeyboardNavigation.DirectionalNavigation" Value="Cycle" />
    <Setter Property="ItemContainerStyle">
        <Setter.Value>
            <Style TargetType="{x:Type ListBoxItem}" >
                <Setter Property="Margin" Value="2, 2, 2, 0" />
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate>
                            <Border Background="Transparent">
                                <RadioButton
                                    Content="{TemplateBinding ContentPresenter.Content}" VerticalAlignment="Center"
                                    IsChecked="{Binding Path=IsSelected,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}"/>

                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Setter.Value>
    </Setter>
</Style>

样式应用如下:

<ListBox ItemsSource="{Binding Options}"
         SelectedValue="{Binding SelectedOption}"
         Style="{StaticResource RadioButtonListBoxStyle}" />

您也可以使用ChildViewModel等其他东西替代String作为集合,然后根据当前项设置相关视图,这意味着您不必在ViewModel中烦恼关联面板的Visibility

<DockPanel>
    <ListBox ItemsSource="{Binding OptionViewModels}"
             SelectedValue="{Binding SelectedViewModel}"
             Style="{StaticResource RadioButtonListBoxStyle}"
             DockPanel.Dock="Left">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding DisplayName}" />
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

    <ContentControl Content="{Binding SelectedViewModel}" />
</DockPanel>

但是对于你实际的问题,我能想到3个可能导致其表现不正确的原因。
第一个原因,在Jay's answer中提到:你在IsChecked1的setter方法中将IsChecked2设置为false,并且IsChecked2也会在其setter方法中将IsChecked1设置为false,因此最终的结果是两个值都是false。
第二个原因是可能与你的转换器有关。你在评论中说它在没有转换器的情况下正常工作,因此我认为这可能是问题的一部分。
最后,我认为更改分组的RadioButtons将触发旧项目的IsOptionA.IsSelected = false和新选定项目的IsOptionB.IsSelected = true,而这两个可能在某个地方交叉了。

谢谢您再次的回复,这很有效。我已经创建了一个observablecollection<myclass>来生成radiobuttons,在myclass中,我创建了一些属性来检查所选radiobutton的Id和名称,以便我可以根据radiobutton Id继续处理我的条件。然而,为绑定仅两个radiobuttons创建集合对象似乎有点不寻常...无论如何,这已经暂时解决了我的问题...谢谢。 - user1105705
@user1105705 起初对我来说也很奇怪,但随着时间的推移,我习惯了这种方式,现在无法想象以其他方式处理这种情况。它使得后续添加非常容易,并且我发现逻辑比尝试操作多个布尔值更容易跟踪和维护。很高兴它对你有用 :) - Rachel

1
这里有几个问题。
  1. 您不需要转换器。将IsRadioButton1IsRadioButton2属性设置为bool?类型,然后使用TwoWay Binding即可,如果三态不适用于您,则可以将其保留为bool
  2. 您的setter中的逻辑似乎是不正确的。在两种情况下,您都将另一个RadioButton的值设置为false,因此,如果IsRadioButton1true,然后您将IsRadioButton2设置为true,则setter将调用IsRadioButton = false,然后该setter将调用IsRadioButton2 = false。它们最终都将变为false

您可能希望将其更改为if(value)IsRadioButton2 = false;


编辑

实际上,据我回忆,RadioButton并不像CheckBox那样旨在绑定到bool属性。我认为您需要将所有的RadioButton绑定到一个属性,并使用一个带有ConverterParameterConverter来设置该属性。我会找到一个例子并在一分钟内发布。


好的,这里有一个解决方案,使用一个派生的RadioButton类,它完全通过绑定来实现:http://blogs.msdn.com/b/mthalman/archive/2008/09/04/wpf-data-binding-with-radiobutton.aspx

这里有一个相关的SO问题和答案:MVVM: Binding radio buttons to a view model?


感谢您的回复...我已经尝试在不设置IsRadioButton1、IsRadioButton2为false的情况下执行...但结果仍然相同。当第一或第二个单选按钮被选择(第三次选择时)再次返回时,我无法设置它们的属性。您能否更清楚地解释一下解决方法...再次感谢。 - user1105705
太好了,但是我需要知道单选按钮的布尔值,以便更改同一表单中另一个控件的可见性。使用上述过程似乎不可能设置两个单选按钮的单个属性。如果有任何可能,请告诉我在我的给定代码中必须执行的过程...谢谢。 - user1105705
@Jay,你能看一下这个问题吗?http://stackoverflow.com/questions/38434625/odd-behavior-when-trying-to-change-a-bound-radiobutton-in-wpf - Vahid

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接