Yaşım hakkında Menü maddesini uygulamaya eklemek istiyorum. Uygulamanın 'sistem menüsüne' eklemek istiyorum (sol üst köşedeki uygulama simgesini tıkladığımızda açılan ekran). Peki, nasıl .NET'te yapabilirim?Bir Windows Formunun sistem menüsünü nasıl özelleştirebilirim?
cevap
Windows, GetSystemMenu
function ile özelleştirme amacıyla formun sistem menüsünün bir kopyasının tanıtıcısını almayı oldukça kolaylaştırır. Zor olan kısım, geri döndüğünüz menüye uygun modifikasyonları gerçekleştirmenizdir, AppendMenu
, InsertMenu
ve DeleteMenu
gibi işlevleri kullanarak, doğrudan Win32 API'sine karşı programlama yapıyor olsaydınız.
Bununla birlikte, tek yapmanız gereken basit bir menü öğesi eklemekse, gerçekten bu kadar zor değil. Örneğin, yalnızca AppendMenu
işlevini kullanmanız gerekir, çünkü tek yapmanız gereken, menünün sonuna bir veya iki öğe eklemektir. Daha gelişmiş bir şey yapmak (menünün ortasına bir öğe eklemek, menü maddesinde bir bitmap görüntülemek, kontrol edilen menü öğelerini görüntülemek, varsayılan menü öğesini ayarlamak vb.), Biraz daha fazla çalışma gerektirir. Ama nasıl yapıldığını bildikten sonra, vahşi olabilirsin. documentation on menu-related functions, her şeyi anlatır.
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");
}
}
}
Ve burada neler bitmiş ürün var:
İşte bir ayırıcı çizgi ve onun sistem menüsünün altına öğesi "Hakkında" (diğer adıyla bir pencere menüsü) ekleyen bir form için tam bir kod var gibi görünüyor:
Gereksinim duyduğunuz pinvoke miktarı için katma değer küçüktür. Ama bu mümkün. Sistem menü tanıtıcısını almak için GetSystemMenu() öğesini kullanın. Sonra bir giriş eklemek için InsertMenuItem. Bunu, OnHandleCreated() öğesinin bir geçersiz kılmasında yapmanız gerekir, böylece pencere yeniden oluşturulduğunda menüyü yeniden oluşturun.
Kullanıcı tıklattığında oluşturulan WM_SYSCOMMAND iletisini tanımak için WndProc() öğesini geçersiz kılın. İhtiyacınız olan pinvoke bildirimleri için pinvoke.net adresini ziyaret edin.
ben daha Cody Gray'in çözüm bir adım atmış ve bunun dışında yeniden kullanılabilir sınıf yaptı. Sistem menüsündeki Hakkında bilgilerini gizlemesi gereken uygulama günlüğü gönderme aracımın bir parçası.
https://github.com/ygoe/FieldLog/blob/master/LogSubmit/Unclassified/UI/SystemMenu.cs
Kolayca bu gibi kullanılabilir:
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");
}
}
Tekniğini denemek istedim ama SystemMenu için bir referans bulamadım Nerede? – John
@John bağlı [GitHub depo] sınıfında (https://github.com/dg9ngf/FieldLog/blob P/Invoke ile belirtilen işlevleri ve anlaşmaları sağlayan /master/LogSubmit/Unclassified/UI/SystemMenu.cs) – Yoda
@John Oops, bu yorumu özledim… Daha da ileriye gitmek için bağlantıyı da güncelledim. – ygoe
Bu cevap eskidir ama gerçekten LonelyPixel cevabını sevdim biliyorum. Bununla birlikte, WPF ile düzgün çalışması için biraz çalışmaya gerek duydu. Aşağıda yazdığım bir WPF sürümü, bu yüzden :) zorunda değilsiniz. Kabul cevabın
/// <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 sürümü:
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. FreeTextBox menüsünü nasıl özelleştirebilirim?
- 2. Jenkins'in çıkışını nasıl özelleştirebilirim?
- 3. Django'da bir widget'ın html çıktısını nasıl özelleştirebilirim?
- 4. Sulu'da bir tarih seçicisini nasıl özelleştirebilirim?
- 5. Prestashop'ta kayıt formunun kişiselleştirilmesi
- 6. Doğrulama mesajlarını Laravel'de nasıl özelleştirebilirim?
- 7. Django dil seçim formunun
- 8. Windows sistem saatini değiştirmeden geçme süresi
- 9. VB6 formunun yeniden boyutlandırılamayacağını nasıl belirleyebilirim?
- 10. JqGrid Düzenleme formunun genişliği nasıl değiştirilir?
- 11. React Native ListView'ın RefreshControl'ü nasıl özelleştirebilirim? RefreshControl
- 12. Mailboxer e-postasını Konu Nasıl Özelleştirebilirim?
- 13. PyQt'deki QCompleter açılır penceresini nasıl özelleştirebilirim?
- 14. WCF istemci kodu nesli nasıl özelleştirebilirim?
- 15. Tek bir uygulama için sistem renklerini değiştirme (Windows, .NET)
- 16. Özel bileşenimi uygun şekilde nasıl özelleştirebilirim?
- 17. İyonik'teki yukarı kalkma yüksekliğini nasıl özelleştirebilirim?
- 18. Mailboxer e-postasının şablonunu nasıl özelleştirebilirim?
- 19. Windows 8'de sistem sesini nasıl tespit edebiliriz?
- 20. Bir sistem aygıtını nasıl devre dışı bırakırım?
- 21. Java'da pencere menüsünü değiştirin
- 22. Emacs'te sistem türü nasıl seçilir?
- 23. sistem() çıktısının nasıl saklanacağı
- 24. Minimum sistem gereksinimleri nasıl belirlenir
- 25. Android - NestedFragments seçenekler menüsünü
- 26. TinyMCE'de Bağlam Menüsünü Çıkarma
- 27. XAML'de Sistem Sesini nasıl yürütürüm?
- 28. Simgede içerik menüsünü göster?
- 29. OS X'teki Eclipse'deki "Tercihler" menüsünü nasıl bulabilirim?
- 30. CSS3 ile akordeon menüsünü nasıl yapabilirim?
Test ve çok iyi çalışıyor! Günümü kurtardın! Teşekkür ederim! :) – GiveEmTheBoot
Bu iyi çalışıyor. Ancak, Hakkında girişi için nasıl bir hızlandırıcı tuş gösterebilirim? (Yakın Yakın Alt + F4 var, Benim için Alt + A göstermek istiyorum.) – BoltBait
Nevermind, yorumumun cevabını buldum. Ayrı ayrı bir sekme karakteri (\ t) kullanarak "& Hakkında ... \ tAlt + A" gibi dizgeyi eklersiniz. – BoltBait