Winforms 将枚举绑定到单选按钮

发布于 2024-08-25 13:59:24 字数 171 浏览 3 评论 0原文

如果我有三个单选按钮,将它们绑定到具有相同选择的枚举的最佳方法是什么?例如

[] Choice 1
[] Choice 2
[] Choice 3

public enum MyChoices
{
    Choice1,
    Choice2,
    Choice3
}

If I have three radio buttons, what is the best way to bind them to an enum which has the same choices? e.g.

[] Choice 1
[] Choice 2
[] Choice 3

public enum MyChoices
{
    Choice1,
    Choice2,
    Choice3
}

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

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

发布评论

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

评论(4

醉南桥 2024-09-01 13:59:24

我知道这是一个老问题,但它是第一个出现在我的搜索结果中的问题。我找到了一种将单选按钮绑定到枚举,甚至是字符串或数字等的通用方法。

    private void AddRadioCheckedBinding<T>(RadioButton radio, object dataSource, string dataMember, T trueValue)
    {
        var binding = new Binding(nameof(RadioButton.Checked), dataSource, dataMember, true, DataSourceUpdateMode.OnPropertyChanged);
        binding.Parse += (s, a) => { if ((bool)a.Value) a.Value = trueValue; };
        binding.Format += (s, a) => a.Value = ((T)a.Value).Equals(trueValue);
        radio.DataBindings.Add(binding);
    }

然后在表单的构造函数或表单加载事件上,在每个 RadioButton 控制。
dataSource 是包含枚举属性的对象。我确保 dataSource 实现的 INotifyPropertyChanged 接口正在触发枚举属性设置器中的 OnPropertyChanged 事件。

AddRadioCheckedBinding(Choice1RadioButton, dataSource, "MyChoice", MyChoices.Choice1);
AddRadioCheckedBinding(Choice2RadioButton, dataSource, "MyChoice", MyChoices.Choice2);

I know this is an old question, but it was the first to show up in my search results. I figured out a generic way to bind radio buttons to an enum, or even a string or number, etc.

    private void AddRadioCheckedBinding<T>(RadioButton radio, object dataSource, string dataMember, T trueValue)
    {
        var binding = new Binding(nameof(RadioButton.Checked), dataSource, dataMember, true, DataSourceUpdateMode.OnPropertyChanged);
        binding.Parse += (s, a) => { if ((bool)a.Value) a.Value = trueValue; };
        binding.Format += (s, a) => a.Value = ((T)a.Value).Equals(trueValue);
        radio.DataBindings.Add(binding);
    }

And then either on your form's constructor or on the form load event, call it on each of your RadioButton controls.
The dataSource is the object containing your enum property. I made sure that dataSource implemented the INotifyPropertyChanged interface is firing the OnPropertyChanged event in the enum properties setter.

AddRadioCheckedBinding(Choice1RadioButton, dataSource, "MyChoice", MyChoices.Choice1);
AddRadioCheckedBinding(Choice2RadioButton, dataSource, "MyChoice", MyChoices.Choice2);
老娘不死你永远是小三 2024-09-01 13:59:24

您可以创建三个布尔属性:

private MyChoices myChoice;

public bool MyChoice_Choice1
{
    get { return myChoice == MyChoices.Choice1; }
    set { if (value) myChoice = MyChoices.Choice1; myChoiceChanged(); }
}

// and so on for the other two

private void myChoiceChanged()
{
    OnPropertyChanged(new PropertyChangedEventArgs("MyChoice_Choice1"));
    OnPropertyChanged(new PropertyChangedEventArgs("MyChoice_Choice2"));
    OnPropertyChanged(new PropertyChangedEventArgs("MyChoice_Choice3"));
}

然后绑定到 MyChoice_Choice1 和其他属性吗?

Could you create three boolean properties:

private MyChoices myChoice;

public bool MyChoice_Choice1
{
    get { return myChoice == MyChoices.Choice1; }
    set { if (value) myChoice = MyChoices.Choice1; myChoiceChanged(); }
}

// and so on for the other two

private void myChoiceChanged()
{
    OnPropertyChanged(new PropertyChangedEventArgs("MyChoice_Choice1"));
    OnPropertyChanged(new PropertyChangedEventArgs("MyChoice_Choice2"));
    OnPropertyChanged(new PropertyChangedEventArgs("MyChoice_Choice3"));
}

then bind to MyChoice_Choice1 and the others?

删除会话 2024-09-01 13:59:24

我只是想添加我目前正在做的方式。本身没有“约束力”,但希望它能起到同样的作用。

欢迎评论。

public enum MyChoices
{
    Choice1,
    Choice2,
    Choice3
}

public partial class Form1 : Form
{
    private Dictionary<int, RadioButton> radButtons;
    private MyChoices choices;

    public Form1()
    {
        this.InitializeComponent();
        this.radButtons = new Dictionary<int, RadioButton>();
        this.radButtons.Add(0, this.radioButton1);
        this.radButtons.Add(1, this.radioButton2);
        this.radButtons.Add(2, this.radioButton3);

        foreach (var item in this.radButtons)
        {
            item.Value.CheckedChanged += new EventHandler(RadioButton_CheckedChanged);
        }
    }

    private void RadioButton_CheckedChanged(object sender, EventArgs e)
    {
        RadioButton button = sender as RadioButton;
        foreach (var item in this.radButtons)
        {
            if (item.Value == button)
            {
                this.choices = (MyChoices)item.Key;
            }
        }
    }

    public MyChoices Choices
    {
        get { return this.choices; }
        set
        {
            this.choices = value;
            this.SelectRadioButton(value);
            this.OnPropertyChanged(new PropertyChangedEventArgs("Choices"));
        }
    }

    private void SelectRadioButton(MyChoices choiceID)
    {
        RadioButton button;
        this.radButtons.TryGetValue((int)choiceID, out button);
        button.Checked = true;
    }
}

I just thought I'd add the way that I'm currently doing it. There's no 'binding' as such but hopefully it does the same job.

Comments welcome.

public enum MyChoices
{
    Choice1,
    Choice2,
    Choice3
}

public partial class Form1 : Form
{
    private Dictionary<int, RadioButton> radButtons;
    private MyChoices choices;

    public Form1()
    {
        this.InitializeComponent();
        this.radButtons = new Dictionary<int, RadioButton>();
        this.radButtons.Add(0, this.radioButton1);
        this.radButtons.Add(1, this.radioButton2);
        this.radButtons.Add(2, this.radioButton3);

        foreach (var item in this.radButtons)
        {
            item.Value.CheckedChanged += new EventHandler(RadioButton_CheckedChanged);
        }
    }

    private void RadioButton_CheckedChanged(object sender, EventArgs e)
    {
        RadioButton button = sender as RadioButton;
        foreach (var item in this.radButtons)
        {
            if (item.Value == button)
            {
                this.choices = (MyChoices)item.Key;
            }
        }
    }

    public MyChoices Choices
    {
        get { return this.choices; }
        set
        {
            this.choices = value;
            this.SelectRadioButton(value);
            this.OnPropertyChanged(new PropertyChangedEventArgs("Choices"));
        }
    }

    private void SelectRadioButton(MyChoices choiceID)
    {
        RadioButton button;
        this.radButtons.TryGetValue((int)choiceID, out button);
        button.Checked = true;
    }
}
白首有我共你 2024-09-01 13:59:24

提问者没有提及他的约束力是什么。我想他绑定到 XXX.Properties.Settings 类。如果没有,此解决方案需要绑定类来实现 INotifyPropertyChanged 接口。

并有一个像这样的索引器:

public object this[string propertyName] { get; set; }

我尝试了 WeskerTyrant 提供的可接受的解决方案,但失败了。

我必须点击两次才能起作用。

于是我开始自己解决问题。我注意到我绑定的类实现了 INotifyPropertyChanged 接口。其中有一个名为 PropertyChangedPropertyChangedEventHandler

(顺便说一句,我正在使用.net 472)
所以我自己写了一个辅助类。

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Windows.Forms;
namespace Ezfx.Dui
{
    public static class RadioButtonGroupUI
    {
        public static void Apply(ApplicationSettingsBase settings, string key, Control parentControl)
        {
            List<RadioButton> radios = new List<RadioButton>();
            foreach(Control control in parentControl.Controls)
            {
                switch (control)
                {
                    case RadioButton e:
                        radios.Add(e);
                        break;
                }
            }

            Apply(settings, key, radios.ToArray());
        }

        public static void Apply(ApplicationSettingsBase settings, string key, params RadioButton[] radios)
        {

            foreach (RadioButton radioButton in radios)
            {
                if (radioButton.Text == (string)settings[key])
                {
                    radioButton.Checked = true;
                }

                radioButton.CheckedChanged += (sender, e) => {
                    if (radioButton.Checked)
                    {
                        settings[key] = radioButton.Text;
                    }
                    
                };
            }

            settings.PropertyChanged += (sender, e) =>
            {
                foreach (RadioButton radioButton in radios)
                {
                    if (radioButton.Text == (string)settings[key])
                    {
                        radioButton.Checked = true;
                    }
                    else
                    {
                        radioButton.Checked = false;
                    }
                }
            };
        }
    }
}

使用时。您只需在 form_load 事件中添加以下代码即可。

    private void MainForm_Load(object sender, EventArgs e)
    {
        RadioButtonGroupUI.Apply(settings, "category", categoryGroupBox);
        RadioButtonGroupUI.Apply(settings, "package", scikitLearnRadioButton, sparkRadioButton);
    }

我在 github 上分享了这个:

https://github.com/EricWebsmith/Ezfx.Dui

我我猜人们会投票否决我,因为这不能回答有关枚举的问题。我的解决方案是在使用时强制转换设置。就我而言,我使用 python 脚本中的设置,因此不需要强制转换。

Enum.TryParse(settings.category, out Category category);

The question poster did not mention what he is binding to. I suppose he is binding to the XXX.Properties.Settings class. If not, this solution need the binding class to implement INotifyPropertyChanged interface.

and has an indexer like this:

public object this[string propertyName] { get; set; }

I tried the accepted solution, provided by WeskerTyrant, but failed.

I had to click twice before it works.

So I started to solve the problem by myself. I noticed that the class I am binding to implements the INotifyPropertyChanged interface. whiche has a PropertyChangedEventHandler called PropertyChanged.

(I am using .net 472 by the way)
So I wrote a helper class myself.

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Windows.Forms;
namespace Ezfx.Dui
{
    public static class RadioButtonGroupUI
    {
        public static void Apply(ApplicationSettingsBase settings, string key, Control parentControl)
        {
            List<RadioButton> radios = new List<RadioButton>();
            foreach(Control control in parentControl.Controls)
            {
                switch (control)
                {
                    case RadioButton e:
                        radios.Add(e);
                        break;
                }
            }

            Apply(settings, key, radios.ToArray());
        }

        public static void Apply(ApplicationSettingsBase settings, string key, params RadioButton[] radios)
        {

            foreach (RadioButton radioButton in radios)
            {
                if (radioButton.Text == (string)settings[key])
                {
                    radioButton.Checked = true;
                }

                radioButton.CheckedChanged += (sender, e) => {
                    if (radioButton.Checked)
                    {
                        settings[key] = radioButton.Text;
                    }
                    
                };
            }

            settings.PropertyChanged += (sender, e) =>
            {
                foreach (RadioButton radioButton in radios)
                {
                    if (radioButton.Text == (string)settings[key])
                    {
                        radioButton.Checked = true;
                    }
                    else
                    {
                        radioButton.Checked = false;
                    }
                }
            };
        }
    }
}

When using it. You simply add the following code in the form_load event.

    private void MainForm_Load(object sender, EventArgs e)
    {
        RadioButtonGroupUI.Apply(settings, "category", categoryGroupBox);
        RadioButtonGroupUI.Apply(settings, "package", scikitLearnRadioButton, sparkRadioButton);
    }

I shared this in github:

https://github.com/EricWebsmith/Ezfx.Dui

I guess people will vote me down because this does not answer the question about enum. My solution is to cast the settings when use. In my case, I use the settings in a python script, so there is no need to cast.

Enum.TryParse(settings.category, out Category category);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文