如何防止使用ALT+F4关闭WinForm但允许其他所有方式关闭WinForm?

4

我在互联网和这个资源的各个部分搜索了一下这个问题,并注意到我得到了以下代码片段:

Protected Overrides ReadOnly Property CreateParams() As CreateParams
    Get
        Dim cp As CreateParams = MyBase.CreateParams
        Const CS_NOCLOSE As Integer = &H200
        cp.ClassStyle = cp.ClassStyle Or CS_NOCLOSE
        Return cp
    End Get
End Property

这段代码可以防止ALT+F4被使用,但是它的一个意外副作用是:关闭窗口的控制框也被禁用了。

Closing "X" is disabled

请问是否有一个版本的这段代码,能够禁用ALT+F4,但仍然允许通过控制框或其他UI选项(如关闭按钮和菜单中的关闭选项)关闭窗口。

我知道有人会建议检查窗体的e.CloseReason, 但是UserClosing是唯一类似于我想要的原因,然而......那仍然禁用了UI的使用。除非有我忘记的代码。


2
也许这个问题可以帮到你:https://dev59.com/JFbUa4cB1Zd3GeqPAJ7Z - muffi
4个回答

2

将KeyPreview设置为True并处理KeyDown事件:

Private Sub Form1_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
    If e.Alt AndAlso e.KeyCode = Keys.F4 Then
        e.Handled = True
    End If
End Sub

奇怪的问题,是否有一种方法可以在整个程序中全局执行此操作,还是我必须在每个单独的表单上使用它? - Paul Williams
1
@PaulWilliams:你可以在一个单独的类中创建一个共享方法,在每个窗体的 Form.Load 事件中调用它(将窗体作为参数传递)。然后该方法将为您设置正确的属性并订阅事件处理程序。 - Visual Vincent
你是否有相关的代码?因为我在一个普通类中尝试它时出现了错误。 - Paul Williams
1
你可以在一个基类MyNotF4ClosableForm中处理它,并从这个基类继承你应用程序中的每个其他窗体。 - Olaf
Olaf,原谅我,我正在尝试做这件事,但是我在尝试继承新的自定义类中的“Forms”类时遇到了错误...因为我无法在没有将其附加到任何东西的情况下执行“Me.KeyDown”。 - Paul Williams
@PaulWilliams:"给我错误" 不是一个很好的问题描述... 请看下面我的回答。 - Visual Vincent

1

回应您的评论,处理来自另一个类的 KeyDown 事件。

文档:

Public NotInheritable Class MainInterface
    Private Sub New() 'No constructor.
    End Sub

    Public Shared Sub DisableAltF4(ByVal TargetForm As Form)
        TargetForm.KeyPreview = True
        AddHandler TargetForm.KeyDown, AddressOf Form_KeyDown
    End Sub

    Private Shared Sub Form_KeyDown(sender As Object, e As KeyEventArgs)
        e.Handled = (e.Alt AndAlso e.KeyCode = Keys.F4)
    End Sub
End Class

现在,在每个窗体的Load事件处理程序中,您可以执行以下操作:
Private Sub yourForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    MainInterface.DisableAltF4(Me)
End Sub

作为Olaf所说,您也可以使所有表单从一个基类继承。然而,这可能会变得有点更加复杂,因为您必须告诉yourForm.vbyourForm.Designer.vb文件,您想要从基本表单继承。
Public Class BaseForm
    Inherits Form

    Protected Overrides Sub OnLoad(e As System.EventArgs)
        MyBase.OnLoad(e)
        Me.KeyPreview = True
    End Sub

    Protected Overrides Sub OnKeyDown(e As System.Windows.Forms.KeyEventArgs)
        MyBase.OnKeyDown(e)
        e.Handled = e.Handled OrElse (e.Alt AndAlso e.KeyCode = Keys.F4)
    End Sub
End Class

yourForm.vb中:

Public Class yourForm
    Inherits BaseForm

    ...code...
End Class

在你的Form.Designer.vb文件中:
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class yourForm
    Inherits yourNamespace.BaseForm

    ...code...
End Class

刚刚测试了响应的第一部分(即水平线之前编辑的部分)。这一切都没问题。(不过我得启用“键预览”才能让它工作。不确定那是否是说明书上的一部分。) - Paul Williams
1
@PaulWilliams:这不是我的指示的一部分,因为我假设在测试Olaf的答案时你已经这样做了。但是,确实需要这样做。 ;) - Visual Vincent
1
@PaulWilliams:我编辑了我的答案,将其包含在代码中。 - Visual Vincent
现在更好了。谢谢。 - Paul Williams

0

简单:

使用C#

protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    if (keyData == (Keys.Alt | Keys.F4))
    {
        return true;  // The key is manually processed
    }
    else
        return base.ProcessCmdKey(ref msg, keyData);
}

在VB.Net中

Protected Overrides Function ProcessCmdKey(ByRef msg As Message, ByVal keyData As Keys) As Boolean
    If keyData = (Keys.Alt Or Keys.F4) Then
        Return True
    Else
        Return MyBase.ProcessCmdKey(msg, keyData)
    End If
End Function

0

您还应该使用RemoveMenu()互操作调用从表单系统菜单中删除相应的CLOSE菜单项。这将禁用所有默认窗口关闭选项。

当然,您可以在代码中调用Form.Close()来关闭您的表单。这可以由自定义按钮、菜单项等的Click事件处理程序触发。此外,您还可以实现一个System.Windows.Forms.IMessageFilter来处理自定义键序列(而不是ALT+F4)来关闭您的表单,例如C+L+O+S+E。


等等等等……我觉得你没读对……我想保留菜单选项,保留控制框选项,但禁用ALT+F4方法。 - Paul Williams

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接