我有一个在 .NET Framework 4.0 上运行的 C# WinForms 应用程序。
当用户在一段时间内处于非事件状态时,我希望它隐藏所有显示的表单并在通知区域显示一个图标。当用户单击该图标时,会出现一个登录表单,如果凭据有效,它会打开之前打开的表单。
为此,我将打开的表单列表存储在 Form
对象的 List
中并隐藏它们,就像这样。此方法由 Timer 调用:
private void LogOut()
{
foreach (Form form in Application.OpenForms)
if (form.Visible)
{
GlobalVariables.formList.Add(form);
form.Hide();
}
}
验证凭据后,我尝试再次使表单可见,如下所示:
//Show the previous forms.
foreach (Form form in GlobalVariables.formList)
form.Visible = true;
//Clear the forms list.
GlobalVariables.formList.Clear();
如果我在隐藏表单时只打开 MainForm,它会在重新登录时正常显示。如果我打开任何其他表单(使用 ShowDialog()
从MainForm),程序将在 form.Visible = true;
上崩溃并给我以下错误消息:
ObjectDisposedException was unhandled
Cannot access a disposed object
我该如何解决这个问题?另一种实现我想要实现的目标的方法也很棒。
请注意,使用 try - catch block 来确定表单是否已被处理并重新启动表单不是一种选择,因为用户可能在隐藏的表单中有未保存的输入。
我在 3 个多小时的搜索中无法在网上找到任何相关内容,因此非常感谢任何帮助!
编辑: 在尝试了各种方法之后,我注意到问题只发生在我使用 ShowDialog()
打开表单的表单上。如果我只使用 Show()
打开表单,一切正常。
但是在我的例子中,使用 Show()
不是一个选项,因为我不能让用户点击父表单中的东西。隐藏父表单也不是一种选择,因为他需要查看父表单中的信息。
最佳答案
显然,隐藏表单比您预想的更有影响力。您的代码涉及 Microsoft 对 Winforms 进行的安全审查。非常彻底,在它的行为方式中通常不可见,但在源代码中非常明显。强加的一条规则是用户永远不应失去对应用程序的控制。
那样的对话框很麻烦。核心问题是 ShowDialog() 创建了一个禁用所有其他窗口的模态 窗口。这为恶意软件创造了机会,很容易被利用,它所要做的就是隐藏一个对话框,然后你就欺骗了用户。用户无法再次获得对应用程序的控制权。已启用的一个窗口被隐藏,用户无法再次重新激活它。所有其他窗口都被禁用,因此尝试单击它们或它们的任务栏按钮将不会有任何效果。剩下的就是让用户使用任务管理器来终止应用程序。如果用户帐户被锁定,那也不是一个选择。
我现在能听到你的声音:“但是,但是,隐藏对话框的是我的代码,而不是恶意软件!”这不是它在 Windows 中的工作方式,没有办法告诉它实际上是您的代码完成的。不仅因为它可以被注入(inject)代码,它甚至不必是在您的进程中运行的代码。 任何代码都可以做到,它是 winapi 的一部分。
所以Winforms内置了一个特定的反制措施,如果它在对话框模式下运行时隐藏,它会自动关闭窗体。这当然有很大的影响,在 ShowDialog() 调用之后编写的代码现在将运行。一切皆有可能,但在您的案例中肯定会发生的不幸事件是,这会处理另一个窗口,并且尝试恢复它将会失败。
这里的粗略指导是你做错了。您正在尝试在已经高度安全且经过严格测试的系统之上构建一个安全系统。而且它非常有风险,自己处理密码是降低整个系统安全性的好方法。普通用户当然会喜欢选择与登录 Windows 时使用的密码相同的密码。使攻击者更容易获取该密码。
调用LockWorkStation()相反。
关于c# - 表单在 Hide() 上处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21811670/