在 MVVM 之后从 WPF 中的组框中确定选中的单选按钮

Posted

技术标签:

【中文标题】在 MVVM 之后从 WPF 中的组框中确定选中的单选按钮【英文标题】:Determining checked Radiobutton from groupbox in WPF following MVVM 【发布时间】:2013-09-08 03:08:05 【问题描述】:

我有一个带有一些单选按钮的组合框。我如何知道哪个被检查了?我正在使用 WPF 并关注 MVVM。

<GroupBox Name="grpbx_pagerange" Header="Print Range">
    <Grid >
        <RadioButton Name="radbtn_all" Content="All Pages" GroupName="radios_page_range" IsChecked="True"  />
        <RadioButton x:Name="radbtn_curr" Content="Current Page" GroupName="radios_page_range"  />
        <RadioButton Name="radbtn_pages" Content="Page Range" GroupName="radios_page_range" />

        ....

</GroupBox>

现在,我能想到的一种方法是将每个 RadioButton 的 IsChecked 属性绑定到 ViewModel 中的某个属性,然后在我的 ViewModel 中执行 if..else 类逻辑来找出选定的单选按钮。

但是还有其他优雅的方式吗?

【问题讨论】:

【参考方案1】:

您可以将 Radiobuttons 的 RadioButton.Command 绑定到您的 ViewModel 的命令,并发送一个唯一的 CommandParameter 来识别哪个按钮在命令处理程序中调用了该命令。

<RadioButton Command="Binding MyCommand" CommandParameter="Radio1"/>
<RadioButton Command="Binding MyCommand" CommandParameter="Radio2"/>
<RadioButton Command="Binding MyCommand" CommandParameter="Radio3"/>

在命令处理程序中检查参数以识别单选按钮。

谢谢

【讨论】:

嗨@nit:这是非常简单、快速、优雅且确实值得应用的解决方案。感谢您的回答。 :) 伙计,该解决方案工作正常,但我将如何将默认检查设置为我的任何 RadioButton。好吧,我们可以在 contructor 中设置它,但这会违反 MVVM 规则。任何想法都会有所帮助。 如果您的单选按钮的选中状态不是数据驱动的,即如果每次使用默认选项打开您的打印对话框,则在 xaml 中的第一个单选按钮上设置 IsChecked=true 不会刺痛。 :) 嘿@nit:我想你的回答指出我不是KISS-(thinking complx)。再次感谢,它有帮助。 :) 但是如果检查状态是数据驱动的呢?我怎样才能让一些按钮被检查?我在 xaml 中试过这个: IsChecked="Binding Button.Checked, Mode=TwoWay" 但它没有帮助。 /感谢您的帮助【参考方案2】:

您可以创建一个enum,其中包含RadioButton 对象的值作为名称(大致),然后使用EnumToBoolConverterIsChecked 属性绑定到此enum 类型的属性。

public enum Options

    All, Current, Range

然后在你的视图模型或代码后面:

private Options options = Options.All; // set your default value here

public Options Options
 
    get  return options; 
    set  options = value; NotifyPropertyChanged("Options"); 

添加Converter

[ValueConversion(typeof(Enum), typeof(bool))]
public class EnumToBoolConverter : IValueConverter

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    
        if (value == null || parameter == null) return false;
        string enumValue = value.ToString();
        string targetValue = parameter.ToString();
        bool outputValue = enumValue.Equals(targetValue, StringComparison.InvariantCultureIgnoreCase);
        return outputValue;
    

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    
        if (value == null || parameter == null) return null;
        bool useValue = (bool)value;
        string targetValue = parameter.ToString();
        if (useValue) return Enum.Parse(targetType, targetValue);
        return null;
    

最后,在 UI 中添加绑定,设置适当的ConverterParameter

<RadioButton Content="All Pages" IsChecked="Binding Options, Converter=
    StaticResource EnumToBoolConverter, ConverterParameter=All" />
<RadioButton Content="Current Page" IsChecked="Binding Options, Converter=
    StaticResource EnumToBoolConverter, ConverterParameter=Current" />
<RadioButton Content="Page Range" IsChecked="Binding Options, Converter=
    StaticResource EnumToBoolConverter, ConverterParameter=Range" />

现在您可以通过查看视图模型中的Options 变量或后面的代码来判断哪个是设置的。您还可以通过设置Options 属性来设置选中的RadioButton

【讨论】:

嘿@Sheridan:你的解决方案看起来很棒,尤其是Enum & Converterfeature。但我无法在 Window.Resource 中分配静态资源 - 它会可用 - 如果您可以请添加您定义静态资源的视图。谢谢。 :) @Bhramar 您可以像这样包含转换器:首先包含像 xmlns:local=="clr-namespace:WpfApplication1" 这样的 xml 命名空间,然后是声明转换器的命名空间。然后在 Window.Rsources 添加 我试过这个:&lt;Window x:Name="win_printDialog" x:Class="M.N.Core.Control.DocumentPrintDialog" ... xmlns:local="clr-namespace:M.N.Core.Control" Title="Print Dialog" &gt; &lt;Window.Resources&gt; &lt;local:EnumToBoolConverter x:Key="EnumToBoolConverter" /&gt; &lt;/Window.Resources&gt; 这实在是行不通。我提到了这个article 错误说-“EnumToBoolConverter”在命名空间“clr-namespace:M.N.Core.Control”中不存在 我对这种方法所做的一个小改动是返回 Binding.DoNothing 而不是 null - 否则我看到的是未选中的单选按钮周围的红色验证边框。似乎为我解决了问题。 是的,另一个流行的选择是返回DependencyProperty.UnsetValue...由你决定。【参考方案3】:

还有另一种 MVVM 方法可以使用 IsChecked 属性解决此问题

这是 XAML

<Page>
<Page.Resources>
<DataTemplate x:Key="ChoiceItemTemplate">
<RadioButton Content="Binding individualRadioButtonText"
     IsTabStop="True"
     GroupName="choice"
     IsChecked="Binding IsChecked, Mode=TwoWay"/>
 </DataTemplate>
</Page.Resources>


 <StackPanel>
  <TextBlock Text="Binding ChoiceQuestion" />
 <ItemsControl  ItemsSource="Binding ListOfAnswerOptions"
                ItemTemplate="StaticResource ChoiceItemTemplate" />
 </StackPanel>
</Page>

你的模型会是这样的

 public class RadioButtonQuestion
 
    public string ChoiceQuestion  get; set; 
    public string answer  get; set; 
    public List<AnswerOption> ListOfAnswerOptions  get; set; 
 

 public class AnswerOption
 
    public string individualRadioButtonText  get; set; 
    public bool IsChecked  get; set; 
 

ViewModel 看起来像这样(选择逻辑)

RadioButtonQuestion r = new RadioButtonQuestion();
var selectedElement = rbuttonQuestion.answerOptions.FirstOrDefault(c => c.IsChecked);
r.answer = selectedElement.individualRadioButtonText;

因此,如果您将视图的数据上下文设置为此视图模型。你必须能够让它工作。

希望对你有帮助。

【讨论】:

【参考方案4】:

如果你在选项按钮(布尔值、整数、字符串)上使用 Tag 属性,就像在他的 XAML 中一样

<StackPanel Orientation="Horizontal" Margin="10,10, 0, 0">
    <RadioButton Name="rP0" Content="Low  " Tag="0" />
    <RadioButton Name="rP1" Content="Normal" Tag="1" IsChecked="True" />
    <RadioButton Name="rP2" Content="Medium" Tag="2" />
    <RadioButton Name="rP3" Content="High" Tag="3" />
</StackPanel>

然后您可以使用以下函数来获取选定的值(按钮)

int priority = SelectedRadioValue<int>(0, rP0, rP1, rP2, rP3);

在哪里

public T SelectedRadioValue<T>(T defaultValue, params RadioButton[] buttons)

    foreach (RadioButton button in buttons)
    
        if (button.IsChecked == true)
        
            if (button.Tag is string && typeof(T) != typeof(string))
            
                string value = (string) button.Tag;
                return (T) Convert.ChangeType(value, typeof(T));
            

            return (T)button.Tag;
        
    

    return defaultValue;

【讨论】:

【参考方案5】:

我遇到了同样的问题,我通过从 Radiobutton 中删除“GroupName”属性解决了。

请从所有单选按钮中删除“GroupName”属性。 并检查

【讨论】:

以上是关于在 MVVM 之后从 WPF 中的组框中确定选中的单选按钮的主要内容,如果未能解决你的问题,请参考以下文章

制作一组单选按钮 [VB.NET]

在 WPF + MVVM +Binding + UserInput 中的 TextBox “预期格式为 DD/MM/YYYY”

WPF - 组框标题对齐

WPF 基于组合框选择使用 MVVM 改变窗口布局

文本框中的 WPF 命令参数

如何在单选按钮组框中获取用户的选择以进行进一步处理?