【问题标题】:Add System Default Context Menu to Borderless Windows Form将系统默认上下文菜单添加到无边框 Windows 窗体
【发布时间】:2016-08-10 07:40:09
【问题描述】:

我从我的 Windows 窗体中删除了默认边框并创建了我自己的标题,我想提供与默认窗体相同的功能。

其中之一是鼠标右键单击时显示的上下文菜单:

是否有可能将其分配给我的服装标题?

如果要贴代码我更喜欢vb,c#也可以。

【问题讨论】:

  • 除了 move 之外,您尝试了什么,其他选项的代码非常简单,那么您尝试了什么?
  • @BugFinder 我不想重新创建上下文菜单,我想以某种方式调用系统默认菜单
  • @VisualVincent 它被错误地标记为重复,因为我的问题是关于 Windows 窗体和另一个关于 WPF 的问题
  • @VisualVincent 以重复的形式关闭该问题似乎是我的错。虽然链接的帖子对于解决问题确实很有用,但默认情况下无边框表单没有系统菜单。您应该首先通过在 CreateParams 中添加 WS_SYSMENU 样式来启用表单的系统菜单。然后你可以发送 WM_POPUPSYSTEMMENU 到 OnMouseDown 中的窗口
  • 我尝试了解决方案是“重复问题”,但它对我不起作用,因为某些类在 Windows 窗体中不可用

标签: c# .net vb.net winforms contextmenu


【解决方案1】:

默认情况下,无边框表单没有系统菜单。您应该首先通过在CreateParams 中添加WS_SYSMENU 样式来启用表单的系统菜单。然后你可以发送WM_POPUPSYSTEMMENU到OnMouseDown中的窗口。

C#

然后设置this.FormBorderStyle = Windows.Forms.FormBorderStyle.None;:

private const int WS_SYSMENU = 0x80000;
private const int WS_MINIMIZEBOX = 0x20000;
private const int WS_MAXIMIZEBOX = 0x10000;
protected override CreateParams CreateParams
{
    get
    {
        CreateParams p = base.CreateParams;
        p.Style = WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
        return p;
    }
}

[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg,
    IntPtr wParam, IntPtr lParam);
private const int WM_POPUPSYSTEMMENU = 0x313;
protected override void OnMouseDown(MouseEventArgs e)
{
    base.OnMouseDown(e);
    if (e.Button == System.Windows.Forms.MouseButtons.Right)
    {
        var p = MousePosition.X + (MousePosition.Y * 0x10000);
        SendMessage(this.Handle, WM_POPUPSYSTEMMENU, (IntPtr)0, (IntPtr)p);
    }
}

VB.NET

然后设置Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None:

Private Const WS_SYSMENU As Integer = &H80000
Private Const WS_MINIMIZEBOX As Integer = &H20000
Private Const WS_MAXIMIZEBOX As Integer = &H10000
Protected Overrides ReadOnly Property CreateParams As System.Windows.Forms.CreateParams
    Get
        Dim p = MyBase.CreateParams
        p.Style = WS_SYSMENU + WS_MINIMIZEBOX + WS_MAXIMIZEBOX
        Return p
    End Get
End Property

<DllImport("user32.dll")>
Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal msg As Integer, _
    ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
End Function
Private Const WM_POPUPSYSTEMMENU As Integer = &H313
Protected Overrides Sub OnMouseDown(ByVal e As System.Windows.Forms.MouseEventArgs)
    MyBase.OnMouseDown(e)
    If e.Button = MouseButtons.Right Then
        Dim p = MousePosition.X + (MousePosition.Y * &H10000)
        SendMessage(Me.Handle, WM_POPUPSYSTEMMENU, 0, p)
    End If
End Sub

注意

WM_POPUPSYSTEMMENU 未记录但完全可以正常工作。如果您想使用文档化的方式,您可以使用GetSystemMenu 获取系统菜单,然后使用TrackPopupMenu 显示它并使用SendMessage 执行返回的命令。您可以声明:

Private Const TPM_LEFTBUTTON As Integer = &H0
Private Const TPM_RIGHTBUTTON As Integer = &H2
Private Const TPM_RETURNCMD As Integer = &H100
Private Const WM_SYSCOMMAND As Integer = &H112
<DllImport("user32.dll")> _
Private Shared Function GetSystemMenu(ByVal hWnd As IntPtr, _
    ByVal bRevert As Boolean) As IntPtr
End Function
<DllImport("user32.dll")>
Private Shared Function TrackPopupMenu(ByVal hMenu As IntPtr, ByVal uFlags As Integer, _
    ByVal x As Integer, ByVal y As Integer, ByVal nReserved As Integer, _
    ByVal hWnd As IntPtr, ByVal prcRect As IntPtr) As Integer
End Function
<DllImport("user32.dll")>
Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal msg As Integer, _
    ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
End Function

并以这种方式显示菜单:

Dim menu = GetSystemMenu(Me.Handle, False)
Dim command = TrackPopupMenu(menu, TPM_RETURNCMD + TPM_LEFTBUTTON + TPM_RIGHTBUTTON, _
                    MousePosition.X, MousePosition.Y, IntPtr.Zero, _
                    Me.Handle, IntPtr.Zero)
If (command > 0) Then
    SendMessage(Me.Handle, WM_SYSCOMMAND, command, IntPtr.Zero)
End If

【讨论】:

  • 几乎完美运行 - 移动选项和菜单定位不起作用
  • 这就是它的工作方式。移动需要标题栏。或者,您也可以使用可用于移动无边界表单的解决方案。
  • 我需要为定位部分更改什么以及如何使 Moce 选项工作(我得到了移动代码,但是如何实现它)
  • 看看this pot。将其转换为 VB.NET 非常简单。你在这个答案中有SendMessage,这里也是ReleaseCapture:&lt;DllImport("user32.dll")&gt; Private Shared Function ReleaseCapture() As Boolean
  • 我需要将 createparams 的 vb 示例修改为 p.Style = p.Style 或 WS_SYSMENU ...尽管该示例在运行时有效,但它破坏了我的表单设计器。
猜你喜欢
  • 1970-01-01
  • 2015-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-06
  • 2010-10-20
  • 2016-12-16
  • 2019-12-11
相关资源
最近更新 更多