在 WinForms 中对一组单选按钮进行数据绑定的最佳方法

发布于 2024-07-15 19:39:38 字数 679 浏览 2 评论 0原文

我目前正在对现有的一些 Windows 窗体进行数据绑定,并且在确定在组框中对一组单选按钮控件进行数据绑定的正确方法时遇到了问题。

我的业务对象有一个整数属性,我想针对 4 个单选按钮(其中每个单选按钮代表值 0 - 3)进行数据绑定。

我目前正在绑定一个演示者对象,该对象充当表单和业务对象之间的绑定器,我现在所做的方法是拥有 4 个单独的属性,每个属性都与这些值中的每一个绑定(我确实使用 INotifyPropertyChanged ,但不包括在这里):

Private int _propValue;

Public bool PropIsValue0 
{ 
  get { return _propValue == 0; }
  set
  {
    if (value) 
      _propValue = 0;
  }
}

Public bool PropIsValue1 { // As above, but with value == 1 }
Public bool PropIsValue2 { // As above, but with value == 2 }
Public bool PropIsValue3 { // As above, but with value == 3 }

然后我将每个单选按钮绑定到它们各自的属性,如上所述。

这对我来说似乎不对,所以非常感谢任何建议。

I'm currently working on databinding some of my existing Windows Forms, and I've ran into an issue figuring out the proper way of databinding a group of radiobutton controls within a group box.

My business object has an integer property which I want to databind against 4 radiobuttons (where each of them represents the values 0 - 3).

I'm currently binding against a presenter object which works as the binder between the form and the business object, and the way I've done it now is to have 4 separate properties which each binds against each of these values (I do use INotifyPropertyChanged, but not including that here):

Private int _propValue;

Public bool PropIsValue0 
{ 
  get { return _propValue == 0; }
  set
  {
    if (value) 
      _propValue = 0;
  }
}

Public bool PropIsValue1 { // As above, but with value == 1 }
Public bool PropIsValue2 { // As above, but with value == 2 }
Public bool PropIsValue3 { // As above, but with value == 3 }

And I then bind each of the radiobuttons to their respective property as above.

This does not seem right to me, so any advice are highly appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

青瓷清茶倾城歌 2024-07-22 19:39:38

以下是本着 ArielBH 建议精神的通用 RadioGroupBox 实现(一些代码借自 Jay Andrew Allen 的 RadioPanel )。 只需向其中添加 RadioButtons,将其标签设置为不同的整数并绑定到“Selected”属性即可。

public class RadioGroupBox : GroupBox
{
    public event EventHandler SelectedChanged = delegate { };

    int _selected;
    public int Selected
    {
        get
        {
            return _selected;
        }
        set
        {
            int val = 0;
            var radioButton = this.Controls.OfType<RadioButton>()
                .FirstOrDefault(radio =>
                    radio.Tag != null 
                   && int.TryParse(radio.Tag.ToString(), out val) && val == value);

            if (radioButton != null)
            {
                radioButton.Checked = true;
                _selected = val;
            }
        }
    }

    protected override void OnControlAdded(ControlEventArgs e)
    {
        base.OnControlAdded(e);

        var radioButton = e.Control as RadioButton;
        if (radioButton != null)
            radioButton.CheckedChanged += radioButton_CheckedChanged;
    }

    void radioButton_CheckedChanged(object sender, EventArgs e)
    {
        var radio = (RadioButton)sender;
        int val = 0;
        if (radio.Checked && radio.Tag != null 
             && int.TryParse(radio.Tag.ToString(), out val))
        {
            _selected = val;
            SelectedChanged(this, new EventArgs());
        }
    }
}

请注意,由于 InitializeComponent 中的初始化顺序问题,您无法通过设计器绑定到“Selected”属性(绑定是在单选按钮初始化之前执行的,因此它们的标记在第一次分配中为 null)。 所以就像这样约束自己:

    public Form1()
    {
        InitializeComponent();
        //Assuming selected1 and selected2 are defined as integer application settings
        radioGroup1.DataBindings.Add("Selected", Properties.Settings.Default, "selected1");
        radioGroup2.DataBindings.Add("Selected", Properties.Settings.Default, "selected2");
    }

Following is a generic RadioGroupBox implementation in the spirit of ArielBH's suggestion (some code borrowed from Jay Andrew Allen's RadioPanel). Just add RadioButtons to it, set their tags to different integers and bind to the 'Selected' property.

public class RadioGroupBox : GroupBox
{
    public event EventHandler SelectedChanged = delegate { };

    int _selected;
    public int Selected
    {
        get
        {
            return _selected;
        }
        set
        {
            int val = 0;
            var radioButton = this.Controls.OfType<RadioButton>()
                .FirstOrDefault(radio =>
                    radio.Tag != null 
                   && int.TryParse(radio.Tag.ToString(), out val) && val == value);

            if (radioButton != null)
            {
                radioButton.Checked = true;
                _selected = val;
            }
        }
    }

    protected override void OnControlAdded(ControlEventArgs e)
    {
        base.OnControlAdded(e);

        var radioButton = e.Control as RadioButton;
        if (radioButton != null)
            radioButton.CheckedChanged += radioButton_CheckedChanged;
    }

    void radioButton_CheckedChanged(object sender, EventArgs e)
    {
        var radio = (RadioButton)sender;
        int val = 0;
        if (radio.Checked && radio.Tag != null 
             && int.TryParse(radio.Tag.ToString(), out val))
        {
            _selected = val;
            SelectedChanged(this, new EventArgs());
        }
    }
}

Note that you can't bind to the 'Selected' property via the designer due to initialization order problems in InitializeComponent (the binding is performed before the radio buttons are initialized, so their tag is null in the first assignment). So just bind yourself like so:

    public Form1()
    {
        InitializeComponent();
        //Assuming selected1 and selected2 are defined as integer application settings
        radioGroup1.DataBindings.Add("Selected", Properties.Settings.Default, "selected1");
        radioGroup2.DataBindings.Add("Selected", Properties.Settings.Default, "selected2");
    }
绳情 2024-07-22 19:39:38

我知道这篇文章很旧,但在寻找同一问题的答案时,我遇到了这篇文章,但它没有解决我的问题。 就在一分钟前,我的灯泡随机熄灭,我想分享我的解决方案。

我在组框中有三个单选按钮。 我正在使用 List<> 自定义类对象作为数据源。

类对象:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BAL
{
class ProductItem
{

    // Global Variable to store the value of which radio button should be checked
    private int glbTaxStatus;
    // Public variable to set initial value passed from 
    // database query and get value to save to database
    public int TaxStatus
    {
        get { return glbTaxStatus; }
        set { glbTaxStatus = value; }
    }

    // Get/Set for 1st Radio button
    public bool Resale
    {
        // If the Global Variable = 1 return true, else return false
        get
        {
            if (glbTaxStatus.Equals(1))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        // If the value being passed in = 1 set the Global Variable = 1, else do nothing
        set
        {
            if (value.Equals(true))
            {
                glbTaxStatus = 1;
            }
        }
    }

    // Get/Set for 2nd Radio button
    public bool NeverTax
    {
        // If the Global Variable = 2 return true, else return false
        get
        {
            if (glbTaxStatus.Equals(2))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        // If the value being passed in = 2 set the Global Variable = 2, else do nothing
        set
        {
            if (value.Equals(true))
            {
                glbTaxStatus = 2;
            }
        }
    }

    // Get/Set for 3rd Radio button
    public bool AlwaysTax
    {
        // If the Global Variable = 3 return true, else return false
        get
        {
            if (glbTaxStatus.Equals(3))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        // If the value being passed in = 3 set the Global Variable = 3, else do nothing
        set
        {
            if (value.Equals(true))
            {
                glbTaxStatus = 3;
            }
        }
    }

// More code ...

三个独立的公共变量,通过 get/set 访问同一个全局变量。

在后面的代码中,我在 Page_Load() 设置所有控件数据绑定期间调用了一个函数。 对于每个单选按钮,我添加其自己的数据绑定。

radResale.DataBindings.Add("Checked", glbProductList, "Resale", true, DataSourceUpdateMode.OnPropertyChanged, false);
radNeverTax.DataBindings.Add("Checked", glbProductList, "NeverTax", true, DataSourceUpdateMode.OnPropertyChanged, false);
radAlwaysTax.DataBindings.Add("Checked", glbProductList, "Always", true, DataSourceUpdateMode.OnPropertyChanged, false);

我希望这可以帮助别人!!

I know this post is old but in my search for an answer for this same problem I came across this post and it didn't solve my problem. I ended up having a lightbulb go off randomly just a minute ago and wanted to share my solution.

I have three radio buttons in a group box. I'm using a List<> of a custom class object as the data source.

Class Object:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BAL
{
class ProductItem
{

    // Global Variable to store the value of which radio button should be checked
    private int glbTaxStatus;
    // Public variable to set initial value passed from 
    // database query and get value to save to database
    public int TaxStatus
    {
        get { return glbTaxStatus; }
        set { glbTaxStatus = value; }
    }

    // Get/Set for 1st Radio button
    public bool Resale
    {
        // If the Global Variable = 1 return true, else return false
        get
        {
            if (glbTaxStatus.Equals(1))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        // If the value being passed in = 1 set the Global Variable = 1, else do nothing
        set
        {
            if (value.Equals(true))
            {
                glbTaxStatus = 1;
            }
        }
    }

    // Get/Set for 2nd Radio button
    public bool NeverTax
    {
        // If the Global Variable = 2 return true, else return false
        get
        {
            if (glbTaxStatus.Equals(2))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        // If the value being passed in = 2 set the Global Variable = 2, else do nothing
        set
        {
            if (value.Equals(true))
            {
                glbTaxStatus = 2;
            }
        }
    }

    // Get/Set for 3rd Radio button
    public bool AlwaysTax
    {
        // If the Global Variable = 3 return true, else return false
        get
        {
            if (glbTaxStatus.Equals(3))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        // If the value being passed in = 3 set the Global Variable = 3, else do nothing
        set
        {
            if (value.Equals(true))
            {
                glbTaxStatus = 3;
            }
        }
    }

// More code ...

Three seperate public variables with get/set accessing the same one global variable.

In the code behind, I have a function called during the Page_Load() setting all the controls databindings. For each radio button I add its own databinging.

radResale.DataBindings.Add("Checked", glbProductList, "Resale", true, DataSourceUpdateMode.OnPropertyChanged, false);
radNeverTax.DataBindings.Add("Checked", glbProductList, "NeverTax", true, DataSourceUpdateMode.OnPropertyChanged, false);
radAlwaysTax.DataBindings.Add("Checked", glbProductList, "Always", true, DataSourceUpdateMode.OnPropertyChanged, false);

I hope this helps someone!!

懵少女 2024-07-22 19:39:38

我想我会使用我自己的 GroupBox。 我会将 CustomGroupBox 绑定到您的模型,并从绑定值设置正确的 RadioButton (使用标签或名称属性)。

I think I would use my own GroupBox. I would bind the CustomGroupBox to your Model and set the correct RadioButton (using the tag or name properties) from the binded value.

南笙 2024-07-22 19:39:38

这是我将单选按钮列表绑定到枚举的方法。

使用枚举作为按钮的 Tag 属性中的字符串,我使用 Binding.FormatBinding.Parse 事件来决定应检查哪个按钮。

public enum OptionEnum
{
   Option1 = 0,
   Option2
}

OptionEnum _rbEnum = OptionEnum.Option1;
OptionEnum PropertyRBEnum
{
    get { return _rbEnum; }
    set
    {
        _rbEnum = value;
        RaisePropertyChanged("PropertyRBEnum");
    }
}

public static void FormatSelectedEnum<T>(object sender, ConvertEventArgs args) where T : struct
{
    Binding binding = (sender as Binding);
    if (binding == null) return;

    Control button = binding.Control;

    if (button == null || args.DesiredType != typeof(Boolean)) return;

    T value = (T)args.Value;
    T controlValue;

    if (Enum.TryParse(button.Tag.ToString(), out controlValue))
    {
        args.Value = value.Equals(controlValue);
    }
    else
    {
        Exception ex = new Exception("String not found in Enum");
        ex.Data.Add("Tag", button.Tag);

        throw ex;
    }
}

public static void ParseSelectedEnum<T>(object sender, ConvertEventArgs args) where T : struct
{
    Binding binding = (sender as Binding);
    if (binding == null) return;

    Control button = binding.Control;
    bool value = (bool)args.Value;

    if (button == null || value != true) return;

    T controlValue;

    if (Enum.TryParse(button.Tag.ToString(), out controlValue))
    {
        args.Value = controlValue;
    }
    else
    {
        Exception ex = new Exception("String not found in Enum");
        ex.Data.Add("Tag", button.Tag);

        throw ex;
    }
}

然后像这样设置数据绑定:

radioButton1.Tag = "Option1";
radioButton2.Tag = "Option2";

foreach (RadioButtonUx rb in new RadioButtonUx[] { radioButton1, radioButton2 })
{
    Binding b = new Binding("Checked", this, "PropertyRBEnum");
    b.Format += FormatSelectedRadioButton<OptionEnum>;
    b.Parse += ParseSelectedRadioButton<OptionEnum>;

    rb.DataBindings.Add(b);
}

This is my approach for binding a list of radio buttons to an enum.

Using the Enum as a string in the button's Tag property, I use the Binding.Format and Binding.Parse event to decide which button should be checked.

public enum OptionEnum
{
   Option1 = 0,
   Option2
}

OptionEnum _rbEnum = OptionEnum.Option1;
OptionEnum PropertyRBEnum
{
    get { return _rbEnum; }
    set
    {
        _rbEnum = value;
        RaisePropertyChanged("PropertyRBEnum");
    }
}

public static void FormatSelectedEnum<T>(object sender, ConvertEventArgs args) where T : struct
{
    Binding binding = (sender as Binding);
    if (binding == null) return;

    Control button = binding.Control;

    if (button == null || args.DesiredType != typeof(Boolean)) return;

    T value = (T)args.Value;
    T controlValue;

    if (Enum.TryParse(button.Tag.ToString(), out controlValue))
    {
        args.Value = value.Equals(controlValue);
    }
    else
    {
        Exception ex = new Exception("String not found in Enum");
        ex.Data.Add("Tag", button.Tag);

        throw ex;
    }
}

public static void ParseSelectedEnum<T>(object sender, ConvertEventArgs args) where T : struct
{
    Binding binding = (sender as Binding);
    if (binding == null) return;

    Control button = binding.Control;
    bool value = (bool)args.Value;

    if (button == null || value != true) return;

    T controlValue;

    if (Enum.TryParse(button.Tag.ToString(), out controlValue))
    {
        args.Value = controlValue;
    }
    else
    {
        Exception ex = new Exception("String not found in Enum");
        ex.Data.Add("Tag", button.Tag);

        throw ex;
    }
}

Then setup your data binding like this:

radioButton1.Tag = "Option1";
radioButton2.Tag = "Option2";

foreach (RadioButtonUx rb in new RadioButtonUx[] { radioButton1, radioButton2 })
{
    Binding b = new Binding("Checked", this, "PropertyRBEnum");
    b.Format += FormatSelectedRadioButton<OptionEnum>;
    b.Parse += ParseSelectedRadioButton<OptionEnum>;

    rb.DataBindings.Add(b);
}
豆芽 2024-07-22 19:39:38

我开始解决同样的问题。

我使用了 RadioButtonBinding 类,它封装了有关数据源中枚举的所有单选按钮。

下面的类将所有单选按钮保存在列表中并查找枚举:

class RadioButtonBinding : ILookup<System.Enum, System.Windows.Forms.RadioButton>
{
    private Type enumType;
    private List<System.Windows.Forms.RadioButton> radioButtons;
    private System.Windows.Forms.BindingSource bindingSource;
    private string propertyName;

    public RadioButtonBinding(Type myEnum, System.Windows.Forms.BindingSource bs, string propertyName)
    {
        this.enumType = myEnum;
        this.radioButtons = new List<System.Windows.Forms.RadioButton>();
        foreach (string name in System.Enum.GetNames(this.enumType))
        {
            System.Windows.Forms.RadioButton rb = new System.Windows.Forms.RadioButton();
            rb.Text = name;
            this.radioButtons.Add(rb);
            rb.CheckedChanged += new EventHandler(rb_CheckedChanged);
        }
        this.bindingSource = bs;
        this.propertyName = propertyName;
        this.bindingSource.DataSourceChanged += new EventHandler(bindingSource_DataSourceChanged);
    }

    void bindingSource_DataSourceChanged(object sender, EventArgs e)
    {
        object obj = this.bindingSource.Current;
        System.Enum item = obj.GetType().GetProperty(propertyName).GetValue(obj, new object[] { }) as System.Enum;
        foreach (System.Enum value in System.Enum.GetValues(this.enumType))
        {
            if (this.Contains(value))
            {
                System.Windows.Forms.RadioButton rb = this[value].First();
                if (value.Equals(item))
                {
                    rb.Checked = true;
                }
                else
                {
                    rb.Checked = false;
                }
            }
        }
    }

    void rb_CheckedChanged(object sender, EventArgs e)
    {
        System.Windows.Forms.RadioButton rb = sender as System.Windows.Forms.RadioButton;
        System.Enum val = null;
        try
        {
            val = System.Enum.Parse(this.enumType, rb.Text) as System.Enum;
        }
        catch(Exception ex)
        {
            // cannot occurred if code is safe
            System.Windows.Forms.MessageBox.Show("No enum value for this radio button : " + ex.ToString());
        }
        object obj = this.bindingSource.Current;
        obj.GetType().GetProperty(propertyName).SetValue(obj, val, new object[] { });
        this.bindingSource.CurrencyManager.Refresh();
    }

    public int Count
    {
        get
        {
            return System.Enum.GetNames(this.enumType).Count();
        }
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return this.radioButtons.GetEnumerator();
    }

    public bool Contains(Enum key)
    {
        return System.Enum.GetNames(this.enumType).Contains(key.ToString());
    }

    public IEnumerable<System.Windows.Forms.RadioButton> this[Enum key]
    {
        get
        {
            return this.radioButtons.FindAll(a => { return a.Text == key.ToString(); });
        }
    }

    IEnumerator<IGrouping<Enum, System.Windows.Forms.RadioButton>> IEnumerable<IGrouping<Enum, System.Windows.Forms.RadioButton>>.GetEnumerator()
    {
        throw new NotImplementedException();
    }

    public void AddControlsIntoGroupBox(System.Windows.Forms.GroupBox gb)
    {
        System.Windows.Forms.FlowLayoutPanel panel = new System.Windows.Forms.FlowLayoutPanel();
        panel.Dock = System.Windows.Forms.DockStyle.Fill;
        panel.FlowDirection = System.Windows.Forms.FlowDirection.RightToLeft;
        foreach (System.Windows.Forms.RadioButton rb in this.radioButtons)
        {
            panel.Controls.Add(rb);
        }
        gb.Controls.Add(panel);
    }
}

您可以通过在表单的构造函数中添加该代码来将该类使用到表单中:

    public PageView()
    {
        InitializeComponent();
        RadioButtonBinding rbWidth = new RadioButtonBinding(typeof(Library.EnumConstraint), this.pageBindingSource, "ConstraintWidth");
        rbWidth.AddControlsIntoGroupBox(this.groupBox1);
        RadioButtonBinding rbHeight = new RadioButtonBinding(typeof(Library.EnumConstraint), this.pageBindingSource, "ConstraintHeight");
        rbHeight.AddControlsIntoGroupBox(this.groupBox3);
        this.pageBindingSource.CurrentItemChanged += new EventHandler(pageBindingSource_CurrentItemChanged);
    }

I started to resolve the same problematic.

I used a RadioButtonBinding class which encapsulates all radiobuttons about an enum in the data source.

This following class keeps all radio buttons in a list and makes a lookup for the enum :

class RadioButtonBinding : ILookup<System.Enum, System.Windows.Forms.RadioButton>
{
    private Type enumType;
    private List<System.Windows.Forms.RadioButton> radioButtons;
    private System.Windows.Forms.BindingSource bindingSource;
    private string propertyName;

    public RadioButtonBinding(Type myEnum, System.Windows.Forms.BindingSource bs, string propertyName)
    {
        this.enumType = myEnum;
        this.radioButtons = new List<System.Windows.Forms.RadioButton>();
        foreach (string name in System.Enum.GetNames(this.enumType))
        {
            System.Windows.Forms.RadioButton rb = new System.Windows.Forms.RadioButton();
            rb.Text = name;
            this.radioButtons.Add(rb);
            rb.CheckedChanged += new EventHandler(rb_CheckedChanged);
        }
        this.bindingSource = bs;
        this.propertyName = propertyName;
        this.bindingSource.DataSourceChanged += new EventHandler(bindingSource_DataSourceChanged);
    }

    void bindingSource_DataSourceChanged(object sender, EventArgs e)
    {
        object obj = this.bindingSource.Current;
        System.Enum item = obj.GetType().GetProperty(propertyName).GetValue(obj, new object[] { }) as System.Enum;
        foreach (System.Enum value in System.Enum.GetValues(this.enumType))
        {
            if (this.Contains(value))
            {
                System.Windows.Forms.RadioButton rb = this[value].First();
                if (value.Equals(item))
                {
                    rb.Checked = true;
                }
                else
                {
                    rb.Checked = false;
                }
            }
        }
    }

    void rb_CheckedChanged(object sender, EventArgs e)
    {
        System.Windows.Forms.RadioButton rb = sender as System.Windows.Forms.RadioButton;
        System.Enum val = null;
        try
        {
            val = System.Enum.Parse(this.enumType, rb.Text) as System.Enum;
        }
        catch(Exception ex)
        {
            // cannot occurred if code is safe
            System.Windows.Forms.MessageBox.Show("No enum value for this radio button : " + ex.ToString());
        }
        object obj = this.bindingSource.Current;
        obj.GetType().GetProperty(propertyName).SetValue(obj, val, new object[] { });
        this.bindingSource.CurrencyManager.Refresh();
    }

    public int Count
    {
        get
        {
            return System.Enum.GetNames(this.enumType).Count();
        }
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return this.radioButtons.GetEnumerator();
    }

    public bool Contains(Enum key)
    {
        return System.Enum.GetNames(this.enumType).Contains(key.ToString());
    }

    public IEnumerable<System.Windows.Forms.RadioButton> this[Enum key]
    {
        get
        {
            return this.radioButtons.FindAll(a => { return a.Text == key.ToString(); });
        }
    }

    IEnumerator<IGrouping<Enum, System.Windows.Forms.RadioButton>> IEnumerable<IGrouping<Enum, System.Windows.Forms.RadioButton>>.GetEnumerator()
    {
        throw new NotImplementedException();
    }

    public void AddControlsIntoGroupBox(System.Windows.Forms.GroupBox gb)
    {
        System.Windows.Forms.FlowLayoutPanel panel = new System.Windows.Forms.FlowLayoutPanel();
        panel.Dock = System.Windows.Forms.DockStyle.Fill;
        panel.FlowDirection = System.Windows.Forms.FlowDirection.RightToLeft;
        foreach (System.Windows.Forms.RadioButton rb in this.radioButtons)
        {
            panel.Controls.Add(rb);
        }
        gb.Controls.Add(panel);
    }
}

You are using the class into a form by adding that code in the constructor of the form:

    public PageView()
    {
        InitializeComponent();
        RadioButtonBinding rbWidth = new RadioButtonBinding(typeof(Library.EnumConstraint), this.pageBindingSource, "ConstraintWidth");
        rbWidth.AddControlsIntoGroupBox(this.groupBox1);
        RadioButtonBinding rbHeight = new RadioButtonBinding(typeof(Library.EnumConstraint), this.pageBindingSource, "ConstraintHeight");
        rbHeight.AddControlsIntoGroupBox(this.groupBox3);
        this.pageBindingSource.CurrentItemChanged += new EventHandler(pageBindingSource_CurrentItemChanged);
    }
老旧海报 2024-07-22 19:39:38

将单选按钮的标签名称设置为代表该值的名称。

创建一个字符串设置,例如 OptionDuplicateFiles,并为其指定默认单选按钮的标记名称的默认值。

要保存您选中的单选按钮:

Settings.Default.OptionDuplicateFiles = gbxDuplicateFiles.Controls
   .OfType<RadioButton>()
   .Where(b => b.Checked)
   .Select(b => b.Tag)
   .First()
   .ToString();

要加载您选中的单选按钮:

(gbxDuplicateFiles.Controls
   .OfType<RadioButton>()
   .Where(b => b.Tag.ToString() == Settings.Default.OptionDuplicateFiles)
   .First())
   .Checked = true;

Tada!

Set the tag name of your radio buttons to something that represents the value.

Create a string setting, for example, OptionDuplicateFiles, and give it the default value of the tag name for your default radio button.

To save your checked radio button:

Settings.Default.OptionDuplicateFiles = gbxDuplicateFiles.Controls
   .OfType<RadioButton>()
   .Where(b => b.Checked)
   .Select(b => b.Tag)
   .First()
   .ToString();

To load your checked radio button:

(gbxDuplicateFiles.Controls
   .OfType<RadioButton>()
   .Where(b => b.Tag.ToString() == Settings.Default.OptionDuplicateFiles)
   .First())
   .Checked = true;

Tada!

昵称有卵用 2024-07-22 19:39:38

我喜欢 RadioButtonGroupBox 的想法,但我决定创建一个自支持的版本。
没有理由为 Tag 属性添加值或引入新的值属性。
任何分配的单选按钮仍然是 RadioButtonGroupBox 的成员,并且单选按钮的顺序是在开发期间定义的。
苏,我修改了代码。
现在我可以按索引位置、按控件名称和按文本获取和设置选定的单选按钮。
顺便说一句,仅当为每个单选按钮分配的文本不同时,文本才可用。

public class RadioButtonGroupBox : GroupBox
{
    public event EventHandler SelectedChanged = delegate { };

    int _nIndexPosCheckRadioButton = -1;
    int _selected;
    public int Selected
    {
        get
        {
            return _selected;
        }
    }


    public int CheckedRadioButtonIndexPos
    {
        set
        {
            int nPosInList = -1;
            foreach (RadioButton item in this.Controls.OfType<RadioButton>())
            {
                // There are RadioButtonItems in the list...
                nPosInList++;

                // Set the RB that should be checked
                if (nPosInList == value)
                {
                    item.Checked = true;
                    // We can stop with the loop
                    break;
                }
            }
            _nIndexPosCheckRadioButton = nPosInList;
        }
        get
        {
            int nPosInList = -1;
            int nPosCheckeItemInList = -1;

            foreach (RadioButton item in this.Controls.OfType<RadioButton>())
            {
                // There are RadioButtonItems in the list...
                nPosInList++;

                // Find the RB that is checked
                if (item.Checked)
                {
                    nPosCheckeItemInList = nPosInList;
                    // We can stop with the loop
                    break;
                }
            }
            _nIndexPosCheckRadioButton = nPosCheckeItemInList;
            return _nIndexPosCheckRadioButton;
        }
    }

    public string CheckedRadioButtonByText
    {
        set
        {
            int nPosInList = -1;
            foreach (RadioButton item in this.Controls.OfType<RadioButton>())
            {
                // There are RadioButtonItems in the list...
                nPosInList++;

                // Set the RB that should be checked
                if (item.Text == value)
                {
                    item.Checked = true;
                    // We can stop with the loop
                    break;
                }
            }
            _nIndexPosCheckRadioButton = nPosInList;
        }
        get
        {
            string cByTextValue = "__UNDEFINED__";
            int nPosInList = -1;
            int nPosCheckeItemInList = -1;

            foreach (RadioButton item in this.Controls.OfType<RadioButton>())
            {
                // There are RadioButtonItems in the list...
                nPosInList++;

                // Find the RB that is checked
                if (item.Checked)
                {
                    cByTextValue = item.Text;
                    nPosCheckeItemInList = nPosInList;
                    // We can stop with the loop
                    break;
                }
            }
            _nIndexPosCheckRadioButton = nPosCheckeItemInList;
            return cByTextValue;
        }
    }

    public string CheckedRadioButtonByName
    {
        set
        {
            int nPosInList = -1;
            foreach (RadioButton item in this.Controls.OfType<RadioButton>())
            {
                // There are RadioButtonItems in the list...
                nPosInList++;

                // Set the RB that should be checked
                if (item.Name == value)
                {
                    item.Checked = true;
                    // We can stop with the loop
                    break;
                }
            }
            _nIndexPosCheckRadioButton = nPosInList;
        }
        get
        {
            String cByNameValue = "__UNDEFINED__";
            int nPosInList = -1;
            int nPosCheckeItemInList = -1;

            foreach (RadioButton item in this.Controls.OfType<RadioButton>())
            {
                // There are RadioButtonItems in the list...
                nPosInList++;

                // Find the RB that is checked
                if (item.Checked)
                {
                    cByNameValue = item.Name;
                    nPosCheckeItemInList = nPosInList;
                    // We can stop with the loop
                    break;
                }
            }
            _nIndexPosCheckRadioButton = nPosCheckeItemInList;
            return cByNameValue;
        }
    }


    protected override void OnControlAdded(ControlEventArgs e)
    {
        base.OnControlAdded(e);

        var radioButton = e.Control as RadioButton;
        if (radioButton != null)
            radioButton.CheckedChanged += radioButton_CheckedChanged;
    }


    void radioButton_CheckedChanged(object sender, EventArgs e)
    {
        _selected = CheckedRadioButtonIndexPos;
        SelectedChanged(this, new EventArgs());
    }

}

I liked the idea of a RadioButtonGroupBox but I decided to create a version that is self supporting.
There is no reason to add value to Tag attribute or to introduce new value attributes.
Any assigned radio button is still a member of the RadioButtonGroupBox and the sequence of radiobuttons is defined during development.
Soo, I modified the code.
Now I can get and set the selected radiobutton by index position, By Control Name and by Text.
BTW Text is only useable if your asssigned Text is different for each radiobutton.

public class RadioButtonGroupBox : GroupBox
{
    public event EventHandler SelectedChanged = delegate { };

    int _nIndexPosCheckRadioButton = -1;
    int _selected;
    public int Selected
    {
        get
        {
            return _selected;
        }
    }


    public int CheckedRadioButtonIndexPos
    {
        set
        {
            int nPosInList = -1;
            foreach (RadioButton item in this.Controls.OfType<RadioButton>())
            {
                // There are RadioButtonItems in the list...
                nPosInList++;

                // Set the RB that should be checked
                if (nPosInList == value)
                {
                    item.Checked = true;
                    // We can stop with the loop
                    break;
                }
            }
            _nIndexPosCheckRadioButton = nPosInList;
        }
        get
        {
            int nPosInList = -1;
            int nPosCheckeItemInList = -1;

            foreach (RadioButton item in this.Controls.OfType<RadioButton>())
            {
                // There are RadioButtonItems in the list...
                nPosInList++;

                // Find the RB that is checked
                if (item.Checked)
                {
                    nPosCheckeItemInList = nPosInList;
                    // We can stop with the loop
                    break;
                }
            }
            _nIndexPosCheckRadioButton = nPosCheckeItemInList;
            return _nIndexPosCheckRadioButton;
        }
    }

    public string CheckedRadioButtonByText
    {
        set
        {
            int nPosInList = -1;
            foreach (RadioButton item in this.Controls.OfType<RadioButton>())
            {
                // There are RadioButtonItems in the list...
                nPosInList++;

                // Set the RB that should be checked
                if (item.Text == value)
                {
                    item.Checked = true;
                    // We can stop with the loop
                    break;
                }
            }
            _nIndexPosCheckRadioButton = nPosInList;
        }
        get
        {
            string cByTextValue = "__UNDEFINED__";
            int nPosInList = -1;
            int nPosCheckeItemInList = -1;

            foreach (RadioButton item in this.Controls.OfType<RadioButton>())
            {
                // There are RadioButtonItems in the list...
                nPosInList++;

                // Find the RB that is checked
                if (item.Checked)
                {
                    cByTextValue = item.Text;
                    nPosCheckeItemInList = nPosInList;
                    // We can stop with the loop
                    break;
                }
            }
            _nIndexPosCheckRadioButton = nPosCheckeItemInList;
            return cByTextValue;
        }
    }

    public string CheckedRadioButtonByName
    {
        set
        {
            int nPosInList = -1;
            foreach (RadioButton item in this.Controls.OfType<RadioButton>())
            {
                // There are RadioButtonItems in the list...
                nPosInList++;

                // Set the RB that should be checked
                if (item.Name == value)
                {
                    item.Checked = true;
                    // We can stop with the loop
                    break;
                }
            }
            _nIndexPosCheckRadioButton = nPosInList;
        }
        get
        {
            String cByNameValue = "__UNDEFINED__";
            int nPosInList = -1;
            int nPosCheckeItemInList = -1;

            foreach (RadioButton item in this.Controls.OfType<RadioButton>())
            {
                // There are RadioButtonItems in the list...
                nPosInList++;

                // Find the RB that is checked
                if (item.Checked)
                {
                    cByNameValue = item.Name;
                    nPosCheckeItemInList = nPosInList;
                    // We can stop with the loop
                    break;
                }
            }
            _nIndexPosCheckRadioButton = nPosCheckeItemInList;
            return cByNameValue;
        }
    }


    protected override void OnControlAdded(ControlEventArgs e)
    {
        base.OnControlAdded(e);

        var radioButton = e.Control as RadioButton;
        if (radioButton != null)
            radioButton.CheckedChanged += radioButton_CheckedChanged;
    }


    void radioButton_CheckedChanged(object sender, EventArgs e)
    {
        _selected = CheckedRadioButtonIndexPos;
        SelectedChanged(this, new EventArgs());
    }

}
陌生 2024-07-22 19:39:38

我的方法是将每个单选按钮放入其自己的面板中,然后将它们绑定到布尔属性:

    public static Binding Bind<TObject>(this RadioButton control, object dataSource, string dataMember)
    {
        // Put the radio button into its own panel
        Panel panel = new Panel();
        control.Parent.Controls.Add(panel);
        panel.Location = control.Location;
        panel.Size = control.Size;
        panel.Controls.Add(control);
        control.Location = new Point(0, 0);

        // Do the actual data binding
        return control.DataBindings.Add("Checked", dataSource, dataMember);
    }

My approach is to put each radio button into its own panel before binding them to a boolean property:

    public static Binding Bind<TObject>(this RadioButton control, object dataSource, string dataMember)
    {
        // Put the radio button into its own panel
        Panel panel = new Panel();
        control.Parent.Controls.Add(panel);
        panel.Location = control.Location;
        panel.Size = control.Size;
        panel.Controls.Add(control);
        control.Location = new Point(0, 0);

        // Do the actual data binding
        return control.DataBindings.Add("Checked", dataSource, dataMember);
    }
笑脸一如从前 2024-07-22 19:39:38

我想对代码块进行观察,这可能对阅读这些帖子的人有所帮助。 由于其结构,以下代码可能并不总是按预期工作。

try
    {
      val = System.Enum.Parse(this.enumType, rb.Text) as System.Enum;
    }
    catch(Exception ex)
    {
      // cannot occurred if code is safe
      System.Windows.Forms.MessageBox.Show("No enum value for this radio button : " + ex.ToString());
    }
    object obj = this.bindingSource.Current;
    obj.GetType().GetProperty(propertyName).SetValue(obj, val, new object[] {
    }
  );
  this.bindingSource.CurrencyManager.Refresh();

如果try块中发生错误,则catch块将被执行。 代码将在 catch 块之后继续执行。 由于没有对绑定源进行处理,因此 catch 后面的变量可能会处于不确定状态,并可能引发另一个可能会或可能不会被处理的异常。

更好的方法如下:

 try
        {
            val = System.Enum.Parse(this.enumType, rb.Text) as System.Enum;

        object obj = this.bindingSource.Current;
        obj.GetType().GetProperty(propertyName).SetValue(obj, val, new object[] { });
        this.bindingSource.CurrencyManager.Refresh();
        }
        catch(EntityException ex)
        {
            // handle error
        }
        catch(Exception ex)
        {
            // cannot occurred if code is safe
            System.Windows.Forms.MessageBox.Show("No enum value for this radio button : " + ex.ToString());
        }

这允许处理枚举值错误以及可能发生的其他错误。 但是,请在 Exception 块之前使用 EntityException 或其变体(Exception 的所有后代都必须首先出现)。 通过使用实体框架类而不是 Exception 基类,可以获取实体框架错误的特定实体状态信息。 这有助于调试或为用户提供更清晰的运行时消息。

当我设置 try-catch 块时,我喜欢将其视为代码顶部的“层”。 我决定程序中异常的流程、异常向用户的显示,以及需要进行哪些清理才能使程序继续正常工作,而不会导致对象处于不确定状态,从而导致其他错误。

I would like to make an observation about the code block that might be helpful to people reading these posts. The following code may not always work as expected due to it's structure.

try
    {
      val = System.Enum.Parse(this.enumType, rb.Text) as System.Enum;
    }
    catch(Exception ex)
    {
      // cannot occurred if code is safe
      System.Windows.Forms.MessageBox.Show("No enum value for this radio button : " + ex.ToString());
    }
    object obj = this.bindingSource.Current;
    obj.GetType().GetProperty(propertyName).SetValue(obj, val, new object[] {
    }
  );
  this.bindingSource.CurrencyManager.Refresh();

If an error occurs in the try block, the catch block will be executed. The code will continue to execute after the catch block. Since there was no handling of binding source, the variables following the catch could end up in a indeterminate state and may throw another exception that may or may not be handled.

A better approach is as follows

 try
        {
            val = System.Enum.Parse(this.enumType, rb.Text) as System.Enum;

        object obj = this.bindingSource.Current;
        obj.GetType().GetProperty(propertyName).SetValue(obj, val, new object[] { });
        this.bindingSource.CurrencyManager.Refresh();
        }
        catch(EntityException ex)
        {
            // handle error
        }
        catch(Exception ex)
        {
            // cannot occurred if code is safe
            System.Windows.Forms.MessageBox.Show("No enum value for this radio button : " + ex.ToString());
        }

This allows the enum value error to be handled as well as other errors that may occur. However use the EntityException or variations of it before the Exception block (all decendents of Exception have to come first). One can get specific entity state information for a entity framework error by using the entity framework classes instead of the Exception base class. This can be helpful for debugging or providing clearer run time messages for the user.

When I setup try-catch blocks I like to view it as a "layer" on top of the code. I make decisions about the flow of the exceptions through out the program, their display to the user, and what ever cleanup is required to allow the program to continue working properly without objects in a indeterminate state that can cascade to other errors.

狼亦尘 2024-07-22 19:39:38

我喜欢 Jan Hoogma GroupBox 绑定,但更喜欢通过创建 RadioButtonBIndable 来对可以绑定的值进行更多控制,RadioButtonBIndable 可以分配不同类型的强类型值。

public class RadioButtonBindable : RadioButton
{
    public Int32 ValueInt { get; set; }   
    public Decimal ValueDecimal { get; set; }
    public String ValueString { get; set; }
    public Boolean ValueBoolean { get; set; }
}

然后我可以处理 GroupBox 并创建 GroupBoxBindable,它可以绑定到 RadioButtonBindable 中的任何值(您可以绑定到多个值,例如 ValueInt = 23 和 ValueString = "Example Text"
您还可以设置默认值,以防出现未选择 RadioButton 的罕见事件。

public class RadioButtonGroupBoxBindable : GroupBox, INotifyPropertyChanged
{
    //public event EventHandler SelectedChanged = delegate { };
    public event EventHandler ValueIntChanged = delegate { };
    public event EventHandler ValueDecimalChanged = delegate { };
    public event EventHandler ValueStringChanged = delegate { };
    public event EventHandler ValueBooleanChanged = delegate { };
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
    public Int32 DefaultValueInt { get; set; }
    public Decimal DefaultValueDecimal { get; set; }
    public String DefaultValueString { get; set; }
    public Boolean DefaultValueBoolean { get; set; }
    public Boolean ValueBoolean
    {
        set
        {
            foreach (Control control in this.Controls)
            {
                if (control is RadioButtonBindable)
                {
                    RadioButtonBindable item = (RadioButtonBindable)control;
                    if (item.ValueBoolean == value)
                    {
                        item.Checked = true;
                        break;
                    }
                }
            }
        }
        get
        {
            Boolean retVal = DefaultValueBoolean;
            foreach (Control control in this.Controls)
            {
                if (control is RadioButtonBindable)
                {
                    RadioButtonBindable item = (RadioButtonBindable)control;
                    if (item.Checked)
                    {
                        retVal = item.ValueBoolean;
                        break;
                    }
                }
            }
            return retVal;
        }
    }
    public int ValueInt
    {
        set
        {
            foreach (Control control in this.Controls)
            {
                if (control is RadioButtonBindable)
                {
                    RadioButtonBindable item = (RadioButtonBindable)control;
                    if (item.ValueInt == value)
                    {
                        item.Checked = true;
                        break;
                    }
                }
            }
        }
        get
        {
            int retVal = DefaultValueInt;
            foreach (Control control in this.Controls)
            {
                if (control is RadioButtonBindable)
                {
                    RadioButtonBindable item = (RadioButtonBindable)control;
                    if (item.Checked)
                    {
                        retVal = item.ValueInt;
                        break;
                    }
                }
            }
            return retVal;
        }
    }
    public decimal ValueDecimal
    {
        set
        {
            foreach (Control control in this.Controls)
            {
                if (control is RadioButtonBindable)
                {
                    RadioButtonBindable item = (RadioButtonBindable)control;
                    if (item.ValueDecimal == value)
                    {
                        item.Checked = true;
                        break;
                    }
                }
            }
        }
        get
        {
            decimal retVal = DefaultValueDecimal;
            foreach (Control control in this.Controls)
            {
                if (control is RadioButtonBindable)
                {
                    RadioButtonBindable item = (RadioButtonBindable)control;
                    if (item.Checked)
                    {
                        retVal = item.ValueDecimal;
                        break;
                    }
                }
            }
            return retVal;
        }
    }
    public string ValueString
    {
        set
        {
            foreach (Control control in this.Controls)
            {
                if (control is RadioButtonBindable)
                {
                    RadioButtonBindable item = (RadioButtonBindable)control;
                    if (item.ValueString == value)
                    {
                        item.Checked = true;
                        break;
                    }
                }
            }
        }
        get
        {
            string retVal = DefaultValueString;
            foreach (Control control in this.Controls)
            {
                if (control is RadioButtonBindable)
                {
                    RadioButtonBindable item = (RadioButtonBindable)control;
                    if (item.Checked)
                    {
                        retVal = item.ValueString;
                        break;
                    }
                }
            }
            return retVal;
        }
    }
    protected override void OnControlAdded(ControlEventArgs e)
    {
        base.OnControlAdded(e);

        var radioButton = e.Control as RadioButtonBindable;
        if (radioButton != null)
            radioButton.CheckedChanged += radioButton_CheckedChanged;
    }
    void radioButton_CheckedChanged(object sender, EventArgs e)
    {
        if (((RadioButtonBindable)sender).Checked)
        {
            OnPropertyChanged("ValueInt");
            OnPropertyChanged("ValueDecimal");
            OnPropertyChanged("ValueString");
            OnPropertyChanged("ValueBoolean");
            ValueIntChanged(this, new EventArgs());
            ValueDecimalChanged(this, new EventArgs());
            ValueStringChanged(this, new EventArgs());
            ValueBooleanChanged(this, new EventArgs());
        }
    }
}

I liked Jan Hoogma GroupBox binding but preferred more control over values you could bind to started by creating RadioButtonBIndable which can have values of different types assigned to it which are strongly typed.

public class RadioButtonBindable : RadioButton
{
    public Int32 ValueInt { get; set; }   
    public Decimal ValueDecimal { get; set; }
    public String ValueString { get; set; }
    public Boolean ValueBoolean { get; set; }
}

Then I can work on the GroupBox and create GroupBoxBindable that can be bound to any of the values in the RadioButtonBindable (you could bind to multiple values e.g. ValueInt = 23 and ValueString = "Example Text"
You can also set a default value in case of teh unlikeley event where there is no RadioButton selected.

public class RadioButtonGroupBoxBindable : GroupBox, INotifyPropertyChanged
{
    //public event EventHandler SelectedChanged = delegate { };
    public event EventHandler ValueIntChanged = delegate { };
    public event EventHandler ValueDecimalChanged = delegate { };
    public event EventHandler ValueStringChanged = delegate { };
    public event EventHandler ValueBooleanChanged = delegate { };
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
    public Int32 DefaultValueInt { get; set; }
    public Decimal DefaultValueDecimal { get; set; }
    public String DefaultValueString { get; set; }
    public Boolean DefaultValueBoolean { get; set; }
    public Boolean ValueBoolean
    {
        set
        {
            foreach (Control control in this.Controls)
            {
                if (control is RadioButtonBindable)
                {
                    RadioButtonBindable item = (RadioButtonBindable)control;
                    if (item.ValueBoolean == value)
                    {
                        item.Checked = true;
                        break;
                    }
                }
            }
        }
        get
        {
            Boolean retVal = DefaultValueBoolean;
            foreach (Control control in this.Controls)
            {
                if (control is RadioButtonBindable)
                {
                    RadioButtonBindable item = (RadioButtonBindable)control;
                    if (item.Checked)
                    {
                        retVal = item.ValueBoolean;
                        break;
                    }
                }
            }
            return retVal;
        }
    }
    public int ValueInt
    {
        set
        {
            foreach (Control control in this.Controls)
            {
                if (control is RadioButtonBindable)
                {
                    RadioButtonBindable item = (RadioButtonBindable)control;
                    if (item.ValueInt == value)
                    {
                        item.Checked = true;
                        break;
                    }
                }
            }
        }
        get
        {
            int retVal = DefaultValueInt;
            foreach (Control control in this.Controls)
            {
                if (control is RadioButtonBindable)
                {
                    RadioButtonBindable item = (RadioButtonBindable)control;
                    if (item.Checked)
                    {
                        retVal = item.ValueInt;
                        break;
                    }
                }
            }
            return retVal;
        }
    }
    public decimal ValueDecimal
    {
        set
        {
            foreach (Control control in this.Controls)
            {
                if (control is RadioButtonBindable)
                {
                    RadioButtonBindable item = (RadioButtonBindable)control;
                    if (item.ValueDecimal == value)
                    {
                        item.Checked = true;
                        break;
                    }
                }
            }
        }
        get
        {
            decimal retVal = DefaultValueDecimal;
            foreach (Control control in this.Controls)
            {
                if (control is RadioButtonBindable)
                {
                    RadioButtonBindable item = (RadioButtonBindable)control;
                    if (item.Checked)
                    {
                        retVal = item.ValueDecimal;
                        break;
                    }
                }
            }
            return retVal;
        }
    }
    public string ValueString
    {
        set
        {
            foreach (Control control in this.Controls)
            {
                if (control is RadioButtonBindable)
                {
                    RadioButtonBindable item = (RadioButtonBindable)control;
                    if (item.ValueString == value)
                    {
                        item.Checked = true;
                        break;
                    }
                }
            }
        }
        get
        {
            string retVal = DefaultValueString;
            foreach (Control control in this.Controls)
            {
                if (control is RadioButtonBindable)
                {
                    RadioButtonBindable item = (RadioButtonBindable)control;
                    if (item.Checked)
                    {
                        retVal = item.ValueString;
                        break;
                    }
                }
            }
            return retVal;
        }
    }
    protected override void OnControlAdded(ControlEventArgs e)
    {
        base.OnControlAdded(e);

        var radioButton = e.Control as RadioButtonBindable;
        if (radioButton != null)
            radioButton.CheckedChanged += radioButton_CheckedChanged;
    }
    void radioButton_CheckedChanged(object sender, EventArgs e)
    {
        if (((RadioButtonBindable)sender).Checked)
        {
            OnPropertyChanged("ValueInt");
            OnPropertyChanged("ValueDecimal");
            OnPropertyChanged("ValueString");
            OnPropertyChanged("ValueBoolean");
            ValueIntChanged(this, new EventArgs());
            ValueDecimalChanged(this, new EventArgs());
            ValueStringChanged(this, new EventArgs());
            ValueBooleanChanged(this, new EventArgs());
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文