听起来很奇怪,但这只是我的爱好。我想要一个(自定义)消息框弹出一个YesNo按钮,理想情况下应该阻止代码。但是我应该能够单击父窗体,这样我就可以取消消息框,而不必特别单击消息框按钮(相当于在消息框上单击No).
像这样:
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.
}
编辑:我知道这不是一个标准的做法,我知道非模态形式不会阻塞,而模态形式。所以请不要建议满足于情态动词或非情态动词的行为。我的问题是,是否有任何方法来模拟上下文菜单的行为与windows窗体。
您可以很容易地解决这个问题。创建并使用一个模态对话框,但是覆盖对话框的WndProc并处理WM_MOUSEDOWN事件。检查鼠标的位置,如果它在父窗口上,但不在对话框本身上,则直接关闭对话框。
基本上你不能在一个'阻塞'调用中轻松做到这一点。您可以轻松地将执行删除所需的信息或执行操作的委托传递给表单。当它们单击Ok时,您只需执行操作即可。如果它们激活了父窗体,那么只需关闭子窗体。
您希望用户能够单击背景窗口来取消对话框?为背景窗口添加一个处理程序,这样当用户单击它时,您就可以检查是否显示非模态窗口,如果显示,则关闭它。
听起来很简单,但是您需要小心处理背景窗口和子窗口上的每一个可能的点击。这听起来像一个棘手的问题,我不想下去。
也许你可以检测非模态对话框是否失去焦点并自动关闭它。我可以看到这种行为对于一个简单的"确认删除"对话框来说是有意义的,但是作为用户,我的第一反应是按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.
当然你需要处理父窗体上的点击来关闭子窗体。
你可以这样做:
public void ShowMe() {
Show();
while (!_receivedDeactivateEvent)
Application.DoEvents();
}
我不确定我会推荐它,虽然——我不确定它会有多稳定,我也不确定它是否会按照你想要的方式行事,如果你点击父窗体上的删除按钮,而"对话框"是向上的(它会先关闭第一个对话框,还是离开它?
一个更简单的方法:设置表单的"TopMost"属性为True。然后它就像阻塞了