Ich möchte den alten Über Menüeintrag zu meiner Anwendung hinzufügen. Ich möchte es dem Systemmenü der Anwendung hinzufügen (das erscheint, wenn wir auf das Anwendungssymbol in der oberen linken Ecke klicken). Also, wie kann ich das in .NET machen?Wie kann ich das Systemmenü eines Windows Forms anpassen?
Antwort
Windows macht es relativ einfach, eine Handhabe für eine Kopie des Systemmenüs des Formulars zu Anpassungszwecken mit der GetSystemMenu
function zu bekommen. Der schwierige Teil ist, dass Sie auf eigene Faust sind, um die entsprechenden Änderungen an dem Menü durchzuführen, das zurückgegeben wird, mit Funktionen wie AppendMenu
, InsertMenu
und DeleteMenu
genau wie wenn Sie direkt mit der Win32-API programmieren würden.
Wenn Sie jedoch nur einen einfachen Menüeintrag hinzufügen möchten, ist das gar nicht so schwer. Beispielsweise müssten Sie nur die Funktion AppendMenu
verwenden, da Sie nur ein oder zwei Elemente am Ende des Menüs hinzufügen möchten. Etwas Höheres zu tun (wie das Einfügen eines Elements in der Mitte des Menüs, Anzeigen einer Bitmap auf dem Menüelement, Anzeigen von aktivierten Menüelementen, Festlegen eines Standardmenüelements usw.) erfordert etwas mehr Arbeit. Aber wenn Sie einmal wissen, wie es geht, können Sie wild werden. Die documentation on menu-related functions sagt alles.
Hier ist der vollständige Code für eine Form, die eine Trennlinie und ein „About“ Element an die Unterseite seines Systemmenüs ergänzt (auch ein Fenster-Menü aufgerufen):
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
public class CustomForm : Form
{
// P/Invoke constants
private const int WM_SYSCOMMAND = 0x112;
private const int MF_STRING = 0x0;
private const int MF_SEPARATOR = 0x800;
// P/Invoke declarations
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool AppendMenu(IntPtr hMenu, int uFlags, int uIDNewItem, string lpNewItem);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool InsertMenu(IntPtr hMenu, int uPosition, int uFlags, int uIDNewItem, string lpNewItem);
// ID for the About item on the system menu
private int SYSMENU_ABOUT_ID = 0x1;
public CustomForm()
{
}
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
// Get a handle to a copy of this form's system (window) menu
IntPtr hSysMenu = GetSystemMenu(this.Handle, false);
// Add a separator
AppendMenu(hSysMenu, MF_SEPARATOR, 0, string.Empty);
// Add the About menu item
AppendMenu(hSysMenu, MF_STRING, SYSMENU_ABOUT_ID, "&About…");
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
// Test if the About item was selected from the system menu
if ((m.Msg == WM_SYSCOMMAND) && ((int)m.WParam == SYSMENU_ABOUT_ID))
{
MessageBox.Show("Custom About Dialog");
}
}
}
Und hier ist es, was das fertige Produkt sieht aus wie:
Der Mehrwert ist ziemlich klein für die Menge an Pinvoke, die Sie benötigen. Aber es ist möglich. Verwenden Sie GetSystemMenu(), um das Systemmenühandle abzurufen. Fügen Sie dann mithilfe von InsertMenuItem einen Eintrag hinzu. Sie müssen dies in einer Überschreibung von OnHandleCreated() tun, damit Sie das Menü neu erstellen, wenn das Fenster neu erstellt wird.
Überschreiben Sie WndProc(), um die WM_SYSCOMMAND-Nachricht zu erkennen, die generiert wird, wenn der Benutzer darauf klickt. Besuchen Sie pinvoke.net für die Pinvoke-Deklarationen, die Sie benötigen.
habe ich Cody Grays Lösung einen Schritt weiter und machte eine wiederverwendbare Klasse aus ihm heraus. Es ist Teil meines Anwendungsprotokoll-Übergabetools, das seine Informationen im Systemmenü verbergen sollte.
class MainForm : Form
{
private SystemMenu systemMenu;
public MainForm()
{
InitializeComponent();
// Create instance and connect it with the Form
systemMenu = new SystemMenu(this);
// Define commands and handler methods
// (Deferred until HandleCreated if it's too early)
// IDs are counted internally, separator is optional
systemMenu.AddCommand("&About…", OnSysMenuAbout, true);
}
protected override void WndProc(ref Message msg)
{
base.WndProc(ref msg);
// Let it know all messages so it can handle WM_SYSCOMMAND
// (This method is inlined)
systemMenu.HandleMessage(ref msg);
}
// Handle menu command click
private void OnSysMenuAbout()
{
MessageBox.Show("My about message");
}
}
Ich wollte Ihre Technik versuchen, aber ich konnte keine Referenz für SystemMenu finden. Wo ist es? – John
@John es ist die Klasse im verknüpften [GitHub-Repository] (https://github.com/dg9ngf/FieldLog/blob /master/LogSubmit/Unclassified/UI/SystemMenu.cs), die die genannten Funktionen bereitstellt und mit dem P/Invoke arbeitet – Yoda
@John Oops, habe ich diesen Kommentar vermisst ... Ich habe den Link auch aktualisiert, um ihn zukunftsfähiger zu machen- Beweis: – ygoe
Ich weiß, diese Antwort ist alt, aber ich mochte LonelyPixel Antwort:
https://github.com/ygoe/FieldLog/blob/master/LogSubmit/Unclassified/UI/SystemMenu.cs
Es kann leicht wie folgt verwendet werden. Es brauchte jedoch etwas Arbeit, um mit WPF korrekt zu arbeiten. Unten ist eine WPF-Version, die ich geschrieben habe, also musst du nicht :).
/// <summary>
/// Extends the system menu of a window with additional commands.
/// Adapted from:
/// https://github.com/dg9ngf/FieldLog/blob/master/LogSubmit/Unclassified/UI/SystemMenu.cs
/// </summary>
public class SystemMenuExtension
{
#region Native methods
private const int WM_SYSCOMMAND = 0x112;
private const int MF_STRING = 0x0;
private const int MF_SEPARATOR = 0x800;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool AppendMenu(IntPtr hMenu, int uFlags, int uIDNewItem, string lpNewItem);
#endregion Native methods
#region Private data
private Window window;
private IntPtr hSysMenu;
private int lastId = 0;
private List<Action> actions = new List<Action>();
private List<CommandInfo> pendingCommands;
#endregion Private data
#region Constructors
/// <summary>
/// Initialises a new instance of the <see cref="SystemMenu"/> class for the specified
/// <see cref="Form"/>.
/// </summary>
/// <param name="window">The window for which the system menu is expanded.</param>
public SystemMenuExtension(Window window)
{
this.window = window;
if(this.window.IsLoaded)
{
WindowLoaded(null, null);
}
else
{
this.window.Loaded += WindowLoaded;
}
}
#endregion Constructors
#region Public methods
/// <summary>
/// Adds a command to the system menu.
/// </summary>
/// <param name="text">The displayed command text.</param>
/// <param name="action">The action that is executed when the user clicks on the command.</param>
/// <param name="separatorBeforeCommand">Indicates whether a separator is inserted before the command.</param>
public void AddCommand(string text, Action action, bool separatorBeforeCommand)
{
int id = ++this.lastId;
if (!this.window.IsLoaded)
{
// The window is not yet created, queue the command for later addition
if (this.pendingCommands == null)
{
this.pendingCommands = new List<CommandInfo>();
}
this.pendingCommands.Add(new CommandInfo
{
Id = id,
Text = text,
Action = action,
Separator = separatorBeforeCommand
});
}
else
{
// The form is created, add the command now
if (separatorBeforeCommand)
{
AppendMenu(this.hSysMenu, MF_SEPARATOR, 0, "");
}
AppendMenu(this.hSysMenu, MF_STRING, id, text);
}
this.actions.Add(action);
}
#endregion Public methods
#region Private methods
private void WindowLoaded(object sender, RoutedEventArgs e)
{
var interop = new WindowInteropHelper(this.window);
HwndSource source = PresentationSource.FromVisual(this.window) as HwndSource;
source.AddHook(WndProc);
this.hSysMenu = GetSystemMenu(interop.EnsureHandle(), false);
// Add all queued commands now
if (this.pendingCommands != null)
{
foreach (CommandInfo command in this.pendingCommands)
{
if (command.Separator)
{
AppendMenu(this.hSysMenu, MF_SEPARATOR, 0, "");
}
AppendMenu(this.hSysMenu, MF_STRING, command.Id, command.Text);
}
this.pendingCommands = null;
}
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == WM_SYSCOMMAND)
{
if ((long)wParam > 0 && (long)wParam <= lastId)
{
this.actions[(int)wParam - 1]();
}
}
return IntPtr.Zero;
}
#endregion Private methods
#region Classes
private class CommandInfo
{
public int Id { get; set; }
public string Text { get; set; }
public Action Action { get; set; }
public bool Separator { get; set; }
}
#endregion Classes
VB.NET-Version akzeptierte Antwort:
Imports System.Windows.Forms
Imports System.Runtime.InteropServices
Public Class CustomForm
Inherits Form
' P/Invoke constants
Private Const WM_SYSCOMMAND As Integer = &H112
Private Const MF_STRING As Integer = &H0
Private Const MF_SEPARATOR As Integer = &H800
' P/Invoke declarations
<DllImport("user32.dll", CharSet := CharSet.Auto, SetLastError := True)> _
Private Shared Function GetSystemMenu(hWnd As IntPtr, bRevert As Boolean) As IntPtr
End Function
<DllImport("user32.dll", CharSet := CharSet.Auto, SetLastError := True)> _
Private Shared Function AppendMenu(hMenu As IntPtr, uFlags As Integer, uIDNewItem As Integer, lpNewItem As String) As Boolean
End Function
<DllImport("user32.dll", CharSet := CharSet.Auto, SetLastError := True)> _
Private Shared Function InsertMenu(hMenu As IntPtr, uPosition As Integer, uFlags As Integer, uIDNewItem As Integer, lpNewItem As String) As Boolean
End Function
' ID for the About item on the system menu
Private SYSMENU_ABOUT_ID As Integer = &H1
Public Sub New()
End Sub
Protected Overrides Sub OnHandleCreated(e As EventArgs)
MyBase.OnHandleCreated(e)
' Get a handle to a copy of this form's system (window) menu
Dim hSysMenu As IntPtr = GetSystemMenu(Me.Handle, False)
' Add a separator
AppendMenu(hSysMenu, MF_SEPARATOR, 0, String.Empty)
' Add the About menu item
AppendMenu(hSysMenu, MF_STRING, SYSMENU_ABOUT_ID, "&About…")
End Sub
Protected Overrides Sub WndProc(ByRef m As Message)
MyBase.WndProc(m)
' Test if the About item was selected from the system menu
If (m.Msg = WM_SYSCOMMAND) AndAlso (CInt(m.WParam) = SYSMENU_ABOUT_ID) Then
MessageBox.Show("Custom About Dialog")
End If
End Sub
End Class
- 1. Wie kann ich auf einen Besitzer eines Windows Forms verweisen?
- 2. Wie kann ich das Aktualisieren eines Formulars in Windows Forms deaktivieren?
- 3. Wie bekomme ich alle Steuerelemente eines Formulars in Windows Forms?
- 4. Wie kann ich das FreeTextBox-Menü anpassen?
- 5. Wie öffne ich app.config in Windows Forms?
- 6. Wie verschiebe ich ein Windows-Menü in MDI Windows Forms?
- 7. Wie kann ich mit einem Windows Forms datetimepicker ArgumentOutOfRangeException umgehen?
- 8. Wie kann ich Rahmen zum Beschriften von Windows Forms hinzufügen?
- 9. Wie Grid in Django Admin Forms anpassen
- 10. Wie kann ich von Windows Forms zu MySQL verbinden?
- 11. Wie kann ich Tastenkombinationen für ein Windows Forms TabControl einrichten?
- 12. Wie kann ich den Anmeldebildschirm für Windows Vista & 7 anpassen?
- 13. Wie kann ich den Löschbestätigungsdialog in Windows überschreiben oder anpassen?
- 14. Windows Forms: Mehrere Standardschaltflächen?
- 15. Welche Kontrolle hat das? - C# - Windows Forms
- 16. windows forms
- 17. Wie kann ich den Namen eines Labels in Xamarin Forms
- 18. Wie kann ich die genaue Höhe eines listbox in Windows Forms (C#)?
- 19. Wie kann ich die Titelleiste eines QMdiSubWindow mit qss anpassen?
- 20. IPC Windows Service Windows Forms
- 21. Wie erhält man die Größe des Zeichnungsbereichs eines Windows Forms?
- 22. Windows Forms: Windows-Label nicht
- 23. Wie kann ich die Fensterauthentifizierung im Sharepoint 2013 anpassen?
- 24. Windows Forms MenuStrip Rahmenfarbe
- 25. Wie kann ich das Tag-Video für mobile Geräte anpassen?
- 26. Wie kann ich das Emacs-Compile-Ausgabe-Parsing anpassen?
- 27. Wie kann ich das Aussehen der Benachrichtigungen anpassen - toastr-rails
- 28. Wie kann ich das Verhalten der Google Places-Ortsmarken anpassen?
- 29. Windows Forms RichTextBox Cursorposition
- 30. Windows Forms: Textbox mit Geschichte
getestet und es funktioniert sehr gut! Du hast meinen Tag gerettet! Danke! :) – GiveEmTheBoot
Das funktioniert gut. Aber, wie kann ich einen Zugriffsschlüssel für den About-Eintrag anzeigen? (Wie Schließen hat Alt + F4, ich möchte Alt + A für Über anzeigen.) – BoltBait
Nevermind, fand ich die Antwort auf meinen Kommentar. Sie fügen einfach die Zeichenfolge "& About ... \ tAlt + A" hinzu, indem Sie ein Tab-Zeichen (\ t) zum Trennen verwenden. – BoltBait