禁用和重新启用控件集合






4.48/5 (6投票s)
禁用一个控件集合,并在重新启用该集合时,将所有子控件恢复到各自的启用状态
引言
这不是一篇复杂的文章或主题,只是尝试解决我遇到的一个问题,并认为其他人可能也会遇到。 在大家最喜欢的搜索引擎上快速搜索了一下,没有找到任何结果,所以我在这里输入我自己的解决方案。
问题非常简单 - 假设您需要在对话框或窗体中禁用它,因为您正在等待另一个线程上发生的事情,并且不希望用户在此期间与任何内容进行交互。
一个很好的例子是登录对话框,它要求提供 SQL Server 数据库的凭据,并在单击“确定”后尝试登录。 例如,如果指定的服务器名称错误(并且您使用的是默认的 30 秒连接超时),则用户必须等待 30 秒才能显示错误消息。
在建立连接时,您需要确保用户不会继续与您的屏幕进行交互,并且在此期间所有控件都有效地禁用。 简单的方法是将窗体的Enabled
标志设置为false
,但这会很糟糕。
问题是 - 如果您的应用程序是正确的多线程,并且连接尝试在后台发生,则您的对话框将在此期间保持解锁状态,用户应该能够移动它。 如果您禁用整个屏幕,您将无法再移动窗体,这会导致用户认为事情已冻结。
解决方案
这个问题的解决方案非常简单。 只需逐个禁用屏幕上的所有控件,然后就完成了。 对吧? 嗯,差不多。 您还必须考虑到屏幕上某些控件可能已被禁用,并且在禁用并随后重新启用屏幕后,您希望这些控件保持禁用状态。 回到登录示例,如果您使用 NT 身份验证,则禁用的控件可能是用户名和密码字段。
然后还有一些控件可能包含其他控件(例如分组框、面板等)的问题,并且它们的子控件也必须考虑在内。
为了实现这一点,需要一组动态方法。 一种方法,用于编目屏幕上的所有控件(存储它们的名称和启用状态)并禁用它们,另一种方法,使用第一种方法构建的目录将所有内容恢复到原来的状态。
UIHelper
类具有这两个方法,它们非常简单。
GetControlStatesAndDisable()
方法将您要禁用的Controls
集合作为单个参数(例如Form.Controls
)。 它编目并返回其中所有控件的名称和Enabled
状态(并且递归调用自身,以便向下遍历任何子控件列表树,例如分组框或面板),然后禁用此列表中的所有控件。
您的工作完成后,将调用RestoreControlStates()
方法,并将之前使用的相同 Controls 集合以及第一种方法创建的目录作为参数。
例如,假设您当前位于Form
类中
SortedList<string, bool> controlStates =
UIHelper.GetControlStatesAndDisable(this.Controls);
// do your lengthy operations here
UIHelper.RestoreControlStates(mForm1.Controls, controlStates);
使用示例代码
附加的示例代码显示了此辅助类的工作方式。 它由两个窗体组成 - 一个包含几个测试控件和容器控件(带有它们自己的子控件),并且每个控件旁边都有一个按钮,允许您启用或禁用它。
第二个窗体用于使用辅助类和方法启用或禁用form1
的所有控件。 请注意,无论您如何启用或禁用form1
上的单个控件,通过form2
上的按钮(因此通过辅助类)启用或禁用它们始终会将它们恢复到其原始的启用状态。
这两个方法如下(可以在本文附件中的UIHelper.cs中找到)
/// <summary>
/// Get a list of all the controls in the ControlCollection
/// along with their Enabled state. Disables all those controls after generating
/// a list of their current Enabled state.
/// </summary>
/// <param name="controlCollection">The ControlCollection to scan for controls and
/// Enabled flags.</param>
/// <returns>List of control names and Enabled states.</returns>
public static SortedList<string, bool> GetControlStatesAndDisable
(Control.ControlCollection controlCollection)
{
SortedList<string, bool> controlStates = new SortedList<string, bool>();
// Loop through the controls under the current ControlCollection
for (int ctr = 0; ctr < controlCollection.Count; ctr++)
{
// Store the current control name and its Enabled state
controlStates.Add(controlCollection[ctr].Name, controlCollection[ctr].Enabled);
// If the current control also has its own ControlCollection
// (such as for a group box, panel, etc), loop through
// its own child controls and extract the same info.
foreach (KeyValuePair<string, bool> pair in GetControlStatesAndDisable
(controlCollection[ctr].Controls))
{
controlStates.Add(pair.Key, pair.Value);
}
// Set the current control's Enabled state to false
controlCollection[ctr].Enabled = false;
}
return controlStates;
}
/// <summary>
/// Restore each control in the ControlCollection to the original
/// Enabled state that existed before calling GetControlStatesAndDisable().
/// </summary>
/// <param name="controlCollection">The ControlCollection to scan for controls
/// and restore their Enabled states.</param>
/// <param name="controlStates">The original Enabled states as retrieved
/// from a call to GetControlStatesAndDisable().</param>
public static void RestoreControlStates
(Control.ControlCollection controlCollection, SortedList<string, bool> controlStates)
{
// Loop through the controls under the current ControlCollection
for (int ctr = 0; ctr < controlCollection.Count; ctr++)
{
if (controlStates.ContainsKey(controlCollection[ctr].Name))
{
// Set the current control's Enabled state to what it was
// before the call to GetControlStatesAndDisable().
controlCollection[ctr].Enabled = controlStates[controlCollection[ctr].Name];
}
// If the current control has its own ControlCollection
// (e.g. for a group box, panel, etc) perform the same job
// on its own child controls.
RestoreControlStates(controlCollection[ctr].Controls, controlStates);
}
}
关注点
但是,我确实注意到,禁用和重新启用容器控件实际上会保留其子控件的所有单独的 Enabled 状态,因此可能不需要遍历控件集合并存储(或恢复)它们各自的 Enabled 状态。 这在启用或禁用整个窗体时也有效,但这会冻结窗体并使其看起来像应用程序已冻结或崩溃。 我仍然将递归代码留在示例中,以防它在我想不到的另一种情况下派上用场。
我希望这个小技巧对其他人有所帮助,并且一如既往,欢迎提出意见和建议。
历史
- 2010 年 1 月 1 日 - 首次发布
- 2010 年 1 月 2 日 - 将
UIHelper
代码添加到文章中