如何创建非模态表单但阻止?

听起来应该很奇怪,但这只是为了我的爱好。 我想要一个(自定义)消息框弹出一个YesNo按钮,理想情况下应该阻止代码。 但我应该能够点击父窗体,这样我就可以关闭消息框而无需专门点击消息框按钮(相当于在消息框中单击否)。

像这样的东西:

void Foo() { CustomMsgBox.Show("do you really wanna delete?", CustomMsgBox.Buttons.YesNo); //block the code here, but user should be able to click on form, so that its equivalent to have clicked No; //if clicked No, return; //delete. } 

所以我认为的解决方案是使自定义消息框非模态 – 以便用户可以单击表单,但我无法阻止代码..我怎么能这样做?

它看起来像这样:

  void Foo() { NonModalMsgBox.Show("do you really wanna delete?", CustomMsgBox.Buttons.YesNo); //block thread till user clicks on form or messagebox buttons. //unblock when user clicks. //if No, return; //delete. } 

编辑:我知道这不是一个标准的练习,我知道非模态forms不会阻止,而模态forms可以。 所以请不要建议对模态forms或非模态forms的行为感到满意。 我的问题是有没有办法用Windows窗体模拟ContextMenu的行为。

你可以这样做:

 public void ShowMe() { Show(); while (!_receivedDeactivateEvent) Application.DoEvents(); } 

不过我不确定我会推荐它 – 我不确定它会有多稳定,也不确定如果单击父窗体上的“删除”按钮,它是否会按照您想要的方式运行对话框’已启动(它会先关闭第一个对话框,还是将其保留?可能是后者,可能会变得混乱)。

你可以很容易地解决这个问题。 创建并使用模式对话框,但覆盖对话框的WndProc并处理WM_MOUSEDOWN事件。 检查鼠标向下的位置,如果它在父窗口上方但未在对话框本身上方,则只需关闭对话框。

基本上你不能轻易地在“拦截”电话中这样做。 您可以轻松完成的任务是将执行删除所需的信息或执行操作的委托传递给表单。 单击“确定”后,您只需执行操作即可。 如果他们激活父表单,则关闭子表单。

您希望用户能够单击背景窗口以取消对话框吗? 在后台窗口中添加一个处理程序,以便在用户单击它时检查是否显示非模态窗口,如果是这样,则关闭它。

听起来很简单,但您需要小心处理背景窗口和子窗口上的所有可能的点击。 这听起来像是一堆蠕虫,我不想失望。

也许您可以检测非modal dialog是否失去焦点并自动关闭它。 我可以看到这种行为对于简单的“确认删除”对话框是有意义的,但作为用户,我的第一反应是垃圾邮件ESC键以关闭对话框。

另一种处理方法是从此处调用ShowDialog时手动启用父窗体

 [DllImport("user32.dll")] private static extern bool EnableWindow(IntPtr hWnd, bool enable); internal static DialogResult ShowDialogSpecial(this Form formToBeShown, Form parent) { parent.BeginInvoke(new Action(() => EnableWindow(parent.Handle, true))); formToBeShown.ShowDialog(parent); return formToBeShown.DialogResult; } 

只需从任何父表单调用扩展方法,如下所示:

 var f = new Form(); f.ShowDialogSpecial(this); //blocks but parent window will be active. 

当然,您需要处理父表单上的点击以关闭子表单。

一种更简单的方法:将表单的“TopMost”属性设置为True。 然后它会像阻塞一样