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






4.20/5 (5投票s)
一个简单的.net Panel控件,允许一个CheckBox自动启用/禁用一组相关控件。
引言
CheckBoxPanel 是一个简单的用户控件,用于对一组相关控件进行分组。一个“主”复选框控件用于自动启用/禁用这组控件。如果用户单击任何禁用的控件,复选框将变为选中状态,并且所有控件都将启用,从而改进窗体的流程并显着改善应用程序用户体验的某个方面。
背景
我一直在努力改进我的用户界面。一种常见的用户界面方法是将一个选项(例如:“保存到备份文件”)显示为一个复选框,并带有一些附加的相关设置(例如:一个包含要写入的文件名的编辑框和一个“浏览”按钮)。大多数传统的用户界面要么
- 在主选项被禁用时保持设置可编辑(讨厌!),或者
- 禁用控件,只有在主选项首先被选中后才启用它们。
让我们做得更好……当控件被禁用时,用户为什么要点击复选框才能使它们可编辑?如果他们点击子 TextBox,我们可以推断他们希望编辑它,这需要主选项被启用;那么我们为什么不节省他们一些时间并为他们做呢?
Using the Code
集成代码
文章代码包含 CheckBoxPanel 用户控件,包含在一个简单的 VS2005 示例应用程序中,该应用程序演示了 Panel 的运行。要在您自己的应用程序中使用该面板,只需将 CheckBoxPanel.cs 和 CheckBoxPanelDesigner.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日 - 文章首次发布