如何对 Windows 窗体的单选按钮进行分组?

354

如何在Windows窗体应用程序中分组单选按钮(类似于ASP.NET的RadioButtonList!)?

这样我就可以在选项之间切换并选择每种情况。


2
你可以查看Windows Forms RadioButtonList - Reza Aghaei
请查看截图:https://dev59.com/unI95IYBdhLWcg3wvgh9#46424314 - Luis Perez
9个回答

474
将同一组的单选按钮放在一个容器对象(如PanelGroupBox)中。 在Windows窗体中,这将自动将它们分组。

15
这个问题是关于 Windows Forms 单选按钮(RadioButton)的,它没有暴露 GroupName 属性。 - UweB
3
如果由于任何问题,比如在表单上没有足够的空间,无法添加分组框和面板,那么怎么办呢? - Muhammad Saqib
3
@MuhammadSaqib,这是不可能的,因为面板可以是零大小。 我的意思是,没有可见边框和无边距的面板与纯窗体相同。 如果您需要以表格方式分组,请使用正确的面板-TableLayoutPanel。 - Alex Zhukovskiy

44

建议将单选按钮放置在一个GroupBox控件中。


2
GroupBox与单选按钮完全无关,任何容器都可以。 - usr

36

您应将组中所有单选按钮都放置在同一个容器内,例如GroupBoxPanel


1
当你有多层嵌套的面板时,例如当你试图做类似于这样的事情时,情况就变得复杂了。单选按钮与它们的父级产生冲突。 - Agi Hammerthief

27

我喜欢 WPF 中的 RadioButton 分组概念。有一个名为 GroupName 的属性用于指定哪些 RadioButton 控件是互斥的 (http://msdn.microsoft.com/de-de/library/system.windows.controls.radiobutton.aspx)。

因此,我编写了一个支持此功能的 Windows 窗体派生类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Windows.Forms.VisualStyles;
using System.Drawing;
using System.ComponentModel;

namespace Use.your.own
{
    public class AdvancedRadioButton : CheckBox
    {
        public enum Level { Parent, Form };

        [Category("AdvancedRadioButton"),
        Description("Gets or sets the level that specifies which RadioButton controls are affected."),
        DefaultValue(Level.Parent)]
        public Level GroupNameLevel { get; set; }

        [Category("AdvancedRadioButton"),
        Description("Gets or sets the name that specifies which RadioButton controls are mutually exclusive.")]
        public string GroupName { get; set; }

        protected override void OnCheckedChanged(EventArgs e)
        {
            base.OnCheckedChanged(e);

            if (Checked)
            {
                var arbControls = (dynamic)null;
                switch (GroupNameLevel)
                {
                    case Level.Parent:
                        if (this.Parent != null)
                            arbControls = GetAll(this.Parent, typeof(AdvancedRadioButton));
                        break;
                    case Level.Form:
                        Form form = this.FindForm();
                        if (form != null)
                            arbControls = GetAll(this.FindForm(), typeof(AdvancedRadioButton));
                        break;
                }
                if (arbControls != null)
                    foreach (Control control in arbControls)
                        if (control != this &&
                            (control as AdvancedRadioButton).GroupName == this.GroupName)
                            (control as AdvancedRadioButton).Checked = false;
            }
        }

        protected override void OnClick(EventArgs e)
        {
            if (!Checked)
                base.OnClick(e);
        }

        protected override void OnPaint(PaintEventArgs pevent)
        {
            CheckBoxRenderer.DrawParentBackground(pevent.Graphics, pevent.ClipRectangle, this);

            RadioButtonState radioButtonState;
            if (Checked)
            {
                radioButtonState = RadioButtonState.CheckedNormal;
                if (Focused)
                    radioButtonState = RadioButtonState.CheckedHot;
                if (!Enabled)
                    radioButtonState = RadioButtonState.CheckedDisabled;
            }
            else
            {
                radioButtonState = RadioButtonState.UncheckedNormal;
                if (Focused)
                    radioButtonState = RadioButtonState.UncheckedHot;
                if (!Enabled)
                    radioButtonState = RadioButtonState.UncheckedDisabled;
            }

            Size glyphSize = RadioButtonRenderer.GetGlyphSize(pevent.Graphics, radioButtonState);
            Rectangle rect = pevent.ClipRectangle;
            rect.Width -= glyphSize.Width;
            rect.Location = new Point(rect.Left + glyphSize.Width, rect.Top);

            RadioButtonRenderer.DrawRadioButton(pevent.Graphics, new System.Drawing.Point(0, rect.Height / 2 - glyphSize.Height / 2), rect, this.Text, this.Font, this.Focused, radioButtonState);
        }

        private IEnumerable<Control> GetAll(Control control, Type type)
        {
            var controls = control.Controls.Cast<Control>();

            return controls.SelectMany(ctrl => GetAll(ctrl, type))
                                      .Concat(controls)
                                      .Where(c => c.GetType() == type);
        }
    }
}

3
这对我来说非常有用,因为我需要在TableLayoutPanel中的一组RadioButton中使用它们-谢谢! - pelazem
我正在尝试在自己的表单中使用这个类,但是无法让控件显示在组框的顶部(就像它是组框的标题一样)。它应该作为顶级单选按钮(即,此单选按钮的组是表单根处的面板,而组框是同级)。是否有关于如何使用此类实现此目的的示例代码? - Agi Hammerthief
我会写 IEnumerable<Control> arbControls = null; 而不是使用 dynamic。var 会更加掩盖它,这就是为什么我通常在我的代码中只使用显式类型。否则,非常好的工作,非常感谢您分享!+1 - sɐunıɔןɐqɐp

14

没有面板的单选按钮

public class RadioButton2 : RadioButton
{
   public string GroupName { get; set; }
}

private void RadioButton2_Clicked(object sender, EventArgs e)
{
    RadioButton2 rb = (sender as RadioButton2);

    if (!rb.Checked)
    {
       foreach (var c in Controls)
       {
           if (c is RadioButton2 && (c as RadioButton2).GroupName == rb.GroupName)
           {
              (c as RadioButton2).Checked = false;
           }
       }

       rb.Checked = true;
    }
}

private void Form1_Load(object sender, EventArgs e)
{
    //a group
    RadioButton2 rb1 = new RadioButton2();
    rb1.Text = "radio1";
    rb1.AutoSize = true;
    rb1.AutoCheck = false;
    rb1.Top = 50;
    rb1.Left = 50;
    rb1.GroupName = "a";
    rb1.Click += RadioButton2_Clicked;
    Controls.Add(rb1);

    RadioButton2 rb2 = new RadioButton2();
    rb2.Text = "radio2";
    rb2.AutoSize = true;
    rb2.AutoCheck = false;
    rb2.Top = 50;
    rb2.Left = 100;
    rb2.GroupName = "a";
    rb2.Click += RadioButton2_Clicked;
    Controls.Add(rb2);

    //b group
    RadioButton2 rb3 = new RadioButton2();
    rb3.Text = "radio3";
    rb3.AutoSize = true;
    rb3.AutoCheck = false;
    rb3.Top = 80;
    rb3.Left = 50;
    rb3.GroupName = "b";
    rb3.Click += RadioButton2_Clicked;
    Controls.Add(rb3);

    RadioButton2 rb4 = new RadioButton2();
    rb4.Text = "radio4";
    rb4.AutoSize = true;
    rb4.AutoCheck = false;
    rb4.Top = 80;
    rb4.Left = 100;
    rb4.GroupName = "b";
    rb4.Click += RadioButton2_Clicked;
    Controls.Add(rb4);
}

11

将单选按钮放入GroupBox(或其他面板)中

这里输入图片描述


7

默认情况下,共享容器内的所有单选按钮属于同一组。 这意味着,如果您选中其中一个单选按钮,则其他单选按钮将取消选中。 如果您想创建独立的单选按钮组,则必须将它们放置在不同的容器中,例如Group Box,或通过代码后台控制其已选中状态。


5

GroupBox更好一些。但不仅限于GroupBox,您甚至可以使用Panels(System.Windows.Forms.Panel)。

  • 当您设计Internet Protocol版本4设置对话框时,这非常有用。(在Windows电脑上检查它,然后您就可以理解其行为)

3

如果您无法将它们放入一个容器中,则需要编写代码来更改每个 RadioButton checked 状态:

private void rbDataSourceFile_CheckedChanged(object sender, EventArgs e)
{
    rbDataSourceNet.Checked = !rbDataSourceFile.Checked;
}

private void rbDataSourceNet_CheckedChanged(object sender, EventArgs e)
{
  rbDataSourceFile.Checked = !rbDataSourceNet.Checked;
}

4
这会让你陷入一个无限循环中... - Michael Sandler

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