65.9K
CodeProject 正在变化。 阅读更多。
Home

CheckBoxPanel - 一个C# CheckBox,可自动启用/禁用相关控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.20/5 (5投票s)

2009 年 8 月 18 日

CPOL

4分钟阅读

viewsIcon

52591

downloadIcon

796

一个简单的.net Panel控件,允许一个CheckBox自动启用/禁用一组相关控件。

引言

CheckBoxPanel 是一个简单的用户控件,用于对一组相关控件进行分组。一个“主”复选框控件用于自动启用/禁用这组控件。如果用户单击任何禁用的控件,复选框将变为选中状态,并且所有控件都将启用,从而改进窗体的流程并显着改善应用程序用户体验的某个方面。

CheckBoxPanel.gif

背景

我一直在努力改进我的用户界面。一种常见的用户界面方法是将一个选项(例如:“保存到备份文件”)显示为一个复选框,并带有一些附加的相关设置(例如:一个包含要写入的文件名的编辑框和一个“浏览”按钮)。大多数传统的用户界面要么

  • 在主选项被禁用时保持设置可编辑(讨厌!),或者
  • 禁用控件,只有在主选项首先被选中后才启用它们。

让我们做得更好……当控件被禁用时,用户为什么要点击复选框才能使它们可编辑?如果他们点击子 TextBox,我们可以推断他们希望编辑它,这需要主选项被启用;那么我们为什么不节省他们一些时间并为他们做呢?

Using the Code

集成代码

文章代码包含 CheckBoxPanel 用户控件,包含在一个简单的 VS2005 示例应用程序中,该应用程序演示了 Panel 的运行。要在您自己的应用程序中使用该面板,只需将 CheckBoxPanel.csCheckBoxPanelDesigner.cs 复制到您的 C# 项目中并进行构建。

在您自己的窗体中使用该面板

现在打开您的窗体设计器,在工具箱中,您会在顶部找到 CheckBoxPanel 列为一个新型控件。只需将其拖到任何窗体上,就像使用 GroupBox 一样使用它。

为了使其运行,您必须至少添加一个复选框。这是将操作该面板的主控件。只需将一个复选框拖放到面板上 - 可以添加任意数量的复选框,但默认情况下,最靠近面板左上角的复选框将被用作主控件。

然后添加任何您希望在主控件未选中时禁用的其他控件。

就是这样!

工作原理

它真的很简单——该类派生自 Windows.Forms.Panel,它为我们完成了几乎所有工作。

在初始化时,BindEvents() 会查找主控件,并为其 CheckedChanged 事件添加一个事件处理程序。如果用户单击复选框,这将调用 mMasterControl_CheckedChanged 函数。发生这种情况时,我们会通过遍历 Controls 集合(Panel 基类提供的子控件列表)来启用/禁用除主控件以外的所有控件。我们只需要小心不要也禁用主控件!

    void mMasterControl_CheckedChanged(object sender, EventArgs e)
    {
        if (mMasterControl == null)
            return;
        
        // Checked state has changed for the master checkbox.
        // Enable/disable all child items
        foreach (Control ctrl in Controls)
        {
            if (!ctrl.Equals(mMasterControl))
                ctrl.Enabled = mMasterControl.Checked;
        }
    }

我们还希望在用户单击任何控件时启用它们。CheckBoxPanel_Click 会响应面板内的任何单击事件。我们使用当前 MousePosition 上的 GetChildAtPoint 来查看单击是否命中了任何子控件 - 如果是,我们将主控件设置为选中状态,并将输入焦点放在被单击的控件上。我们不必显式更新控件,因为设置 mMasterControl.Checked 会自动调用我们的 CheckedChanged 事件处理程序来重新启用所有控件。

    void CheckBoxPanel_Click(object sender, EventArgs e)
    {
        if (mMasterControl != null && !mMasterControl.Checked)
        {
            Point pos = PointToClient(System.Windows.Forms.Control.MousePosition);
            Control child = GetChildAtPoint(pos, GetChildAtPointSkip.None);
            if (child != null)
            {
                mMasterControl.Checked = true;
                child.Focus();
            }
        }
    }

剩余的逻辑与包含文本框的面板相关。如果输入焦点丢失,面板会检查它是否包含 TextBox 控件,以及其中是否有任何文本。如果用户已删除文本框中的所有文本,则会取消选中主控件以再次禁用控件。

首先,这应该只发生在当面板仅包含 TextBoxes 时。在 BindEvents() 中,我们遍历所有子控件以检查它们是否都是 TextBoxes

    if (mAutoDisableBlankFields)
    {
        // See if this contains only text fields - if it does, when they are
        // all empty we untick the master control
        bool containsOnlyTextFields = true;
        foreach(Control ctrl in Controls)
        {
            if (ctrl is TextBox || (ctrl is CheckBox && ctrl.Equals(mMasterControl)))
            {
                // Ignore TextBoxes and the master control
            }
            else
            {
                containsOnlyTextFields = false;
                break;
            }
        }

…如果为真,我们将我们的 LostFocus 事件处理程序添加到每个 TextBox 控件

        if (containsOnlyTextFields)
        {
            foreach(Control ctrl in Controls)
            {
                if (ctrl is TextBox)
                {
                    TextBox textCtrl = (TextBox) ctrl;
                    textCtrl.LostFocus += new EventHandler(TextCtrl_LostFocus);
                }
            }
        }
    }

最后,TextCtrl_LostFocus 检查焦点是否已移出面板。在这种情况下,它会检查所有文本框是否为空 - 如果是,则它将 mMasterControl.Checked = false 设置为再次禁用所有控件。

    void TextCtrl_LostFocus(object sender, EventArgs e)
    {
        if (mMasterControl == null)
            return;
    
        foreach(Control ctrl in Controls)
        {
            TextBox textCtrl = ctrl as TextBox;
            if (textCtrl != null)
            {
                if (textCtrl.Focused ||                    // If the focus moved to
                                                           // another textbox in our
                                                           // panel, remain checked
                    !string.IsNullOrEmpty(textCtrl.Text))  // If a text box is non-empty,
                                                           // leave the option checked
                {
                    return;
                }
            }
        }

        // All text fields in the panel are blank, so we untick our checkbox
        mMasterControl.Checked = false;
    }

选项

该面板提供以下属性(可从您的代码和窗体设计器访问)以进一步优化其行为

  • MasterControl - 如果默认主控件不符合您的要求,请将 MasterControl 设置为面板中的任何 CheckBox。
  • AutoDisableBlankFields - 如果此属性为 true,并且用户将面板内的所有文本字段编辑为空,则面板内容将自动禁用。

关注点

良好的用户界面就是关注细节,简化用户工作流程,使其易于快速使用应用程序,并遵循直观的标准以避免让用户感到困惑。即使是 CheckBoxPanel 提供的微小功能,也可以真正改善用户体验。

自动化这种 UI 增强还可以节省大量程序员时间 - 您需要承担开发通用解决方案的初始成本,但随着您在编写的每个应用程序中节省时间地重复使用相同的代码,这将在数月和数年中得到回报。

历史

2009年8月18日 - 文章首次发布

© . All rights reserved.