【问题标题】:Bind group of 3 RadioButtons to custom class?将 3 个 RadioButtons 组绑定到自定义类?
【发布时间】:2020-12-02 23:25:26
【问题描述】:

我正在尝试将自定义类绑定到我的 WPF 应用程序中的一组 3 个单选按钮。返回的类应该有三种可能性,具体取决于选择了组中的哪个按钮。所以即

public class RadioButtonResult
{
public bool Istrue {get; set;}
public string WhichOne {get; set;}
}

在按钮 1 返回的意义上应该绑定到 3 个单选按钮

new RadioButtonResult { Istrue = false, WhichOne = "First"}

第二个返回一个 Istrue = true 等的实例...我需要这个,因为有 3 种可能的情况,并且元素必须绑定到布尔属性和字符串属性。

我尝试使用转换器

    public class RadioButtonConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            switch (parameter)
            {
                case "First":
                    return new RadioButtonResult(false, "First");
                case "Second":
                    return new RadioButtonResult(true, "Second");
                case "Third":
                    return new RadioButtonResult(true, "First");
                default:
                    return new RadioButtonResult(false, "None")
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        { return null; }
    }

单选按钮本身应该没有文本,所以我不太确定如何传递转换器参数来尝试这个。 (我还没有尝试 ConvertBack,因为我无法让 Convert 工作)

<RadioButton GroupName="Group1" IsChecked="{Binding TestStatus, Converter=RadioButtonConverter, ConverterParameter="First"}"/>

我尝试了类似的方法,但它不接受文本作为参数。我怎样才能使这个转换器工作?

【问题讨论】:

  • 为什么要转换器?您在这里不需要转换器。而是一个正确的视图模型,其属性返回RadioButtonResult 实例。 Here is an MVVM example 绑定到bool 单选按钮属性对。
  • 我需要大约 30 行相同的单选按钮,所以我想我需要一个。但是我使用转换器的主要原因是我不知道单选按钮在 WPF 中是如何工作的,而设计团队无论如何都想要它们。我的视图模型返回了实例,因为我之前使用复选框和组合框实现了它们,但现在它应该只是 3 个单选按钮。我不知道如何将字符串和布尔值绑定到一组 3 个单选按钮
  • “需要大约 30 行” - 然后你需要绑定到一个集合。见this answer
  • 嗯,是的,但在我解决这个问题之前,我仍然需要弄清楚如何将类绑定到单选按钮。如何将具有 3 种不同结果的 2 个属性绑定到一组单选按钮?
  • 所以你想要的是一个返回一些结果的类。有逻辑取决于哪个单选按钮为真。你应该有几个带有文本的单选按钮,它们的输入用于从父类返回的逻辑中。对吗?

标签: c# wpf binding radio-button


【解决方案1】:

我不知道如何将字符串和布尔值绑定到一组 3 个单选按钮

您可以在视图模型中拥有 6 个属性或重用 RadioButtonClass 类(如果您想动态更改值,请考虑实现 INotifyPropertyChanged

public class ViewModel
{
    public RadioButtonResult Button1 { get; } = new RadioButtonResult(false, "First");
    ... // more buttons
}

<RadioButton GroupName="Group1"
             IsChecked="{Binding Button1.Istrue}"
             Content="{Binding Button1.WhichOne}" />

public MainWindow()
{
    InitializeComponents();
    DataContext = new ViewModel();
}

【讨论】:

  • 嗯有没有办法反转 IsChecked 的绑定?检查第一个 Radiobutton 时,我需要为 Result 设置“false”。 IE。如果选中 Radiobutton 1,则该属性需要为 (false, "First")
  • 这是写InverseBooleanConverter的好案例。
【解决方案2】:

我认为您的视图模型结构应该更像:

  public class RadioButtonResult
  {
      public bool Istrue {get; set;}
      public string WhichOne {get; set;}
      public List<OptionVM> Options {get; set;}
  }

OptionVM 有两个属性:

      public bool Istrue {get; set;}
      public string Descriptor {get; set;}

IsTrue 的设置器应该启动一些逻辑。

因此:

     private bool isTrue = false;
     public bool Istrue 
     { get => isTrue;
       set { isTrue = value;
             SetTheParentValue();
           }
     }

SetTheParentValue 应该是您注入到视图模型的 Action。这需要对 RadioButtonResult 的引用,并使那里的 istrue 为真或假,并设置 WhichOne。因此,您还需要一个公共 Action SetTheParentValue。

你应该实现 inotifypropertychanged。

没有转换器。

并且您的逻辑在操作中进行,因此这些类可重用于其他单选按钮组。

我们对您的整体结构了解不够,无法就其他方面提供建议。

但是。

单选按钮集是一个重复组,在 wpf 中通过将 itemscontrol 的 itemssource 绑定到视图模型的列表或 observablecollection 来处理。这将是 OptionVM。然后将数据模板化为单选按钮。

单选按钮的 ischecked 属性将绑定到 IsTrue,内容绑定到 Descriptor。

【讨论】:

    【解决方案3】:

    我建议不要为每个单选按钮设置一个单独的布尔属性,而是为每个单选按钮组设置一个枚举值。

    要进行绑定,您需要在枚举值和单选按钮的布尔 IsChecked 属性之间进行转换器。

    public class perValueEqualsConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return parameter != null && parameter.Equals(value);
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return value != null && value.Equals(true) ? parameter : Binding.DoNothing;
        }
    }
    

    枚举属性在 ViewModel 中定义...

    public enum MyEnum
    {
        Value1,
        Value2,
        Value3
    }
    
    public class MainViewModel : ViewModelBase
    {
        private MyEnum _e = MyEnum.Value2;
    
        public MyEnum E
        {
            get => _e;
            set => Set(nameof(E), ref _e, value);
        }
    }
    

    ...然后通过转换器实例用作视图中的绑定源

    <Window 
    ...>
    
        <Window.DataContext>
            <local:MainViewModel />
        </Window.DataContext>
    
        <Window.Resources>
            <conv:perValueEqualsConverter x:Key="ValueEqualsConverter" />
        </Window.Resources>
    
        <Grid Margin="24">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="16" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
    
            <Grid Grid.Row="0"
                  Width=200>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="8" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="8" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>
    
                <RadioButton
                    Grid.Row="0"
                    Content="Value 1"
                    IsChecked="{Binding E, Converter={StaticResource ValueEqualsConverter}, ConverterParameter={x:Static local:MyEnum.Value1}}" />
                <RadioButton
                    Grid.Row="2"
                    Content="Value 2"
                    IsChecked="{Binding E, Converter={StaticResource ValueEqualsConverter}, ConverterParameter={x:Static local:MyEnum.Value2}}" />
                <RadioButton
                    Grid.Row="4"
                    Content="Value 3"
                    IsChecked="{Binding E, Converter={StaticResource ValueEqualsConverter}, ConverterParameter={x:Static local:MyEnum.Value3}}" />
            </Grid>
    
            <Border
                Grid.Row="0"
                Margin="-8"
                BorderBrush="Black"
                BorderThickness="2"
                CornerRadius="8" />
    
            <TextBlock
                Grid.Row="2"
                Text="{Binding E}" />
    
        </Grid>
    </Window>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-25
      • 2010-09-28
      • 1970-01-01
      • 2011-07-28
      • 2014-10-01
      • 2017-09-03
      • 2012-07-10
      相关资源
      最近更新 更多