Wie kann man die Schließen-Schaltfläche im WPF-Fenster ausblenden?

Ich schreibe einen modalen Dialog in WPF. Wie setze ich ein WPF-Fenster so, dass es keine Schaltfläche zum Schließen gibt? Ich möchte immer noch, dass WindowState eine normale Titelleiste hat.

Ich habe ResizeMode, WindowState und WindowStyle gefunden, aber keine dieser Eigenschaften erlaubt es mir, die Schließen-Schaltfläche zu verbergen, aber die Titelleiste anzuzeigen, wie in modalen Dialogen.

Solutions Collecting From Web of "Wie kann man die Schließen-Schaltfläche im WPF-Fenster ausblenden?"

WPF hat keine integrierte Eigenschaft, um die Schließen-Schaltfläche der Titelleiste zu verbergen, aber Sie können es mit ein paar Zeilen von P / Invoke tun.

Fügen Sie diese Deklarationen zunächst zu Ihrer Window-class hinzu:

private const int GWL_STYLE = -16; private const int WS_SYSMENU = 0x80000; [DllImport("user32.dll", SetLastError = true)] private static extern int GetWindowLong(IntPtr hWnd, int nIndex); [DllImport("user32.dll")] private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); 

Dann setze diesen Code in das Loaded-Event des Windows:

 var hwnd = new WindowInteropHelper(this).Handle; SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU); 

Und da gehst du: nicht mehr Schließen-Taste. Sie werden auch kein Fenstersymbol auf der linken Seite der Titelleiste haben, was bedeutet, dass kein Systemmenü angezeigt wird, selbst wenn Sie mit der rechten Maustaste auf die Titelleiste klicken – sie alle zusammen.

Beachten Sie, dass Alt + F4 das Fenster immer noch schließt. Wenn Sie nicht zulassen möchten, dass das Fenster geschlossen wird, bevor der Hintergrund-Thread fertig ist, können Sie OnClosing auch überschreiben und Cancel auf True setzen, wie von Gabe vorgeschlagen.

Ich habe ein ähnliches Problem, und Joe Whites Lösung scheint mir einfach und sauber zu sein. Ich habe es erneut verwendet und es als angehängte Eigenschaft von Windows definiert

 public class WindowBehavior { private static readonly Type OwnerType = typeof (WindowBehavior); #region HideCloseButton (attached property) public static readonly DependencyProperty HideCloseButtonProperty = DependencyProperty.RegisterAttached( "HideCloseButton", typeof (bool), OwnerType, new FrameworkPropertyMetadata(false, new PropertyChangedCallback(HideCloseButtonChangedCallback))); [AttachedPropertyBrowsableForType(typeof(Window))] public static bool GetHideCloseButton(Window obj) { return (bool)obj.GetValue(HideCloseButtonProperty); } [AttachedPropertyBrowsableForType(typeof(Window))] public static void SetHideCloseButton(Window obj, bool value) { obj.SetValue(HideCloseButtonProperty, value); } private static void HideCloseButtonChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) { var window = d as Window; if (window == null) return; var hideCloseButton = (bool)e.NewValue; if (hideCloseButton && !GetIsHiddenCloseButton(window)) { if (!window.IsLoaded) { window.Loaded += HideWhenLoadedDelegate; } else { HideCloseButton(window); } SetIsHiddenCloseButton(window, true); } else if (!hideCloseButton && GetIsHiddenCloseButton(window)) { if (!window.IsLoaded) { window.Loaded -= ShowWhenLoadedDelegate; } else { ShowCloseButton(window); } SetIsHiddenCloseButton(window, false); } } #region Win32 imports private const int GWL_STYLE = -16; private const int WS_SYSMENU = 0x80000; [DllImport("user32.dll", SetLastError = true)] private static extern int GetWindowLong(IntPtr hWnd, int nIndex); [DllImport("user32.dll")] private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); #endregion private static readonly RoutedEventHandler HideWhenLoadedDelegate = (sender, args) => { if (sender is Window == false) return; var w = (Window)sender; HideCloseButton(w); w.Loaded -= HideWhenLoadedDelegate; }; private static readonly RoutedEventHandler ShowWhenLoadedDelegate = (sender, args) => { if (sender is Window == false) return; var w = (Window)sender; ShowCloseButton(w); w.Loaded -= ShowWhenLoadedDelegate; }; private static void HideCloseButton(Window w) { var hwnd = new WindowInteropHelper(w).Handle; SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU); } private static void ShowCloseButton(Window w) { var hwnd = new WindowInteropHelper(w).Handle; SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | WS_SYSMENU); } #endregion #region IsHiddenCloseButton (readonly attached property) private static readonly DependencyPropertyKey IsHiddenCloseButtonKey = DependencyProperty.RegisterAttachedReadOnly( "IsHiddenCloseButton", typeof (bool), OwnerType, new FrameworkPropertyMetadata(false)); public static readonly DependencyProperty IsHiddenCloseButtonProperty = IsHiddenCloseButtonKey.DependencyProperty; [AttachedPropertyBrowsableForType(typeof(Window))] public static bool GetIsHiddenCloseButton(Window obj) { return (bool)obj.GetValue(IsHiddenCloseButtonProperty); } private static void SetIsHiddenCloseButton(Window obj, bool value) { obj.SetValue(IsHiddenCloseButtonKey, value); } #endregion } 

Dann in XAML setzen Sie es einfach so:

  ...  

Setzen Sie die WindowStyle Eigenschaft auf None, wodurch das Kontrollkästchen neben der Titelleiste WindowStyle wird. Keine Notwendigkeit für coreal Calls.

Dies wird den Schließen-Knopf nicht los, aber es wird jemanden anhalten, der das Fenster schließt.

Setzen Sie dies in Ihren Code hinter die Datei:

 protected override void OnClosing(CancelEventArgs e) { base.OnClosing(e); e.Cancel = true; } 

Um die Schließen-Schaltfläche zu deaktivieren, sollten Sie Ihrer Window-class den folgenden Code hinzufügen (der Code wurde von hier übernommen , ein wenig bearbeitet und neu formatiert):

 protected override void OnSourceInitialized(EventArgs e) { base.OnSourceInitialized(e); HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource; if (hwndSource != null) { hwndSource.AddHook(HwndSourceHook); } } private bool allowClosing = false; [DllImport("user32.dll")] private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert); [DllImport("user32.dll")] private static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable); private const uint MF_BYCOMMAND = 0x00000000; private const uint MF_GRAYED = 0x00000001; private const uint SC_CLOSE = 0xF060; private const int WM_SHOWWINDOW = 0x00000018; private const int WM_CLOSE = 0x10; private IntPtr HwndSourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { switch (msg) { case WM_SHOWWINDOW: { IntPtr hMenu = GetSystemMenu(hwnd, false); if (hMenu != IntPtr.Zero) { EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED); } } break; case WM_CLOSE: if (!allowClosing) { handled = true; } break; } return IntPtr.Zero; } 

Dieser Code deaktiviert auch das Schließen des Elements im Systemmenü und verbietet das Schließen des Dialogfelds mit Alt + F4.

Wahrscheinlich möchten Sie das Fenster programmgesteuert schließen. Ein Aufruf von Close() funktioniert nicht. Tun Sie etwas wie folgt:

 allowClosing = true; Close(); 

Ich habe Viachaslaus Antwort versucht, weil mir die Idee gefiel, den Button nicht zu entfernen, sondern zu deaktivieren, aber aus irgendeinem Grund funktionierte das nicht immer: Der Schließen-Button war immer noch aktiviert, aber keinerlei Fehler.

Dies hat aber immer funktioniert (Fehlerprüfung entfällt):

 [DllImport( "user32.dll" )] private static extern IntPtr GetSystemMenu( IntPtr hWnd, bool bRevert ); [DllImport( "user32.dll" )] private static extern bool EnableMenuItem( IntPtr hMenu, uint uIDEnableItem, uint uEnable ); private const uint MF_BYCOMMAND = 0x00000000; private const uint MF_GRAYED = 0x00000001; private const uint SC_CLOSE = 0xF060; private const int WM_SHOWWINDOW = 0x00000018; protected override void OnSourceInitialized( EventArgs e ) { base.OnSourceInitialized( e ); var hWnd = new WindowInteropHelper( this ); var sysMenu = GetSystemMenu( hWnd.Handle, false ); EnableMenuItem( sysMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED ); } 

Ich füge einfach meine Implementierung der Antwort von Joe White hinzu, indem ich Interaktivität-Verhalten verwende (Sie müssen auf System.Windows.Interactivity verweisen).

Code:

 public class HideCloseButtonOnWindow : Behavior { #region bunch of native methods private const int GWL_STYLE = -16; private const int WS_SYSMENU = 0x80000; [DllImport("user32.dll", SetLastError = true)] private static extern int GetWindowLong(IntPtr hWnd, int nIndex); [DllImport("user32.dll")] private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); #endregion protected override void OnAttached() { base.OnAttached(); AssociatedObject.Loaded += OnLoaded; } protected override void OnDetaching() { AssociatedObject.Loaded -= OnLoaded; base.OnDetaching(); } private void OnLoaded(object sender, RoutedEventArgs e) { var hwnd = new WindowInteropHelper(AssociatedObject).Handle; SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU); } } 

Verwendung:

      

Die zu WindowStyle="None" Eigenschaft ist => WindowStyle="None"

  

Also, ziemlich genau hier ist dein Problem. Die Schließen-Schaltfläche in der oberen rechten Ecke eines Fensterrahmens ist nicht Teil des WPF-Fensters, sondern gehört zu dem Teil des Fensterrahmens, der von Ihrem Betriebssystem gesteuert wird. Dies bedeutet, dass Sie Win32 Interop verwenden müssen, um es zu tun.

Alternativ können Sie den NoFrame verwenden und entweder Ihren eigenen “Frame” bereitstellen oder gar keinen Frame haben.

Lassen Sie den Benutzer das Fenster schließen, aber verstecken Sie es wirklich.

Verstecken Sie das Fenster im OnClosing-Ereignis des Fensters, wenn es bereits sichtbar ist:

  If Me.Visibility = Windows.Visibility.Visible Then Me.Visibility = Windows.Visibility.Hidden e.Cancel = True End If 

Jedes Mal, wenn der Hintergrund-Thread ausgeführt werden soll, das Hintergrund-UI-Fenster erneut anzeigen:

  w.Visibility = Windows.Visibility.Visible w.Show() 

Stellen Sie beim Beenden der Programmausführung sicher, dass alle Fenster geschlossen sind / können:

 Private Sub CloseAll() If w IsNot Nothing Then w.Visibility = Windows.Visibility.Collapsed ' Tell OnClosing to really close w.Close() End If End Sub 

Im Folgenden werden die Schaltflächen “Schließen” und “Maximieren / Minimieren” deaktiviert, aber die Schaltflächen werden nicht entfernt (die Menüelemente werden jedoch entfernt!). Die Schaltflächen in der Titelleiste sind in einem deaktivierten / abgeblendeten Zustand gezeichnet. (Ich bin noch nicht bereit, die ganze functionalität selbst zu übernehmen ^^)

Dies unterscheidet sich geringfügig von der Virgoss-Lösung, da es die Menüelemente (und gegebenenfalls das nachgestellte Trennzeichen) entfernt und nicht nur deaktiviert. Es unterscheidet sich von der Joe Whites-Lösung, da es nicht das gesamte Systemmenü deaktiviert, und so kann ich in meinem Fall die Schaltfläche “Minimieren” und das Symbol “Minimieren” beibehalten.

Der folgende Code unterstützt auch das Deaktivieren der Schaltflächen Maximieren / Minimieren, da das Entfernen der Einträge aus dem Menü im Gegensatz zur Schaltfläche Schließen nicht dazu führt, dass das System die Schaltflächen “deaktiviert” anzeigt, obwohl das Entfernen der Menüeinträge die functionalität der Schaltflächen deaktiviert.

Für mich geht das. YMMV.

  using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; using Window = System.Windows.Window; using WindowInteropHelper = System.Windows.Interop.WindowInteropHelper; using Win32Exception = System.ComponentModel.Win32Exception; namespace Channelmatter.Guppy { public class WindowUtil { const int MF_BYCOMMAND = 0x0000; const int MF_BYPOSITION = 0x0400; const uint MFT_SEPARATOR = 0x0800; const uint MIIM_FTYPE = 0x0100; [DllImport("user32", SetLastError=true)] private static extern uint RemoveMenu(IntPtr hMenu, uint nPosition, uint wFlags); [DllImport("user32", SetLastError=true)] private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert); [DllImport("user32", SetLastError=true)] private static extern int GetMenuItemCount(IntPtr hWnd); [StructLayout(LayoutKind.Sequential)] public struct MenuItemInfo { public uint cbSize; public uint fMask; public uint fType; public uint fState; public uint wID; public IntPtr hSubMenu; public IntPtr hbmpChecked; public IntPtr hbmpUnchecked; public IntPtr dwItemData; // ULONG_PTR public IntPtr dwTypeData; public uint cch; public IntPtr hbmpItem; }; [DllImport("user32", SetLastError=true)] private static extern int GetMenuItemInfo( IntPtr hMenu, uint uItem, bool fByPosition, ref MenuItemInfo itemInfo); public enum MenuCommand : uint { SC_CLOSE = 0xF060, SC_MAXIMIZE = 0xF030, } public static void WithSystemMenu (Window win, Action action) { var interop = new WindowInteropHelper(win); IntPtr hMenu = GetSystemMenu(interop.Handle, false); if (hMenu == IntPtr.Zero) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to get system menu"); } else { action(hMenu); } } // Removes the menu item for the specific command. // This will disable and gray the Close button and disable the // functionality behind the Maximize/Minimuze buttons, but it won't // gray out the Maximize/Minimize buttons. It will also not stop // the default Alt+F4 behavior. public static void RemoveMenuItem (Window win, MenuCommand command) { WithSystemMenu(win, (hMenu) => { if (RemoveMenu(hMenu, (uint)command, MF_BYCOMMAND) == 0) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to remove menu item"); } }); } public static bool RemoveTrailingSeparator (Window win) { bool result = false; // Func< ...> not in .NET3 :-/ WithSystemMenu(win, (hMenu) => { result = RemoveTrailingSeparator(hMenu); }); return result; } // Removes the final trailing separator of a menu if it exists. // Returns true if a separator is removed. public static bool RemoveTrailingSeparator (IntPtr hMenu) { int menuItemCount = GetMenuItemCount(hMenu); if (menuItemCount < 0) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to get menu item count"); } if (menuItemCount == 0) { return false; } else { uint index = (uint)(menuItemCount - 1); MenuItemInfo itemInfo = new MenuItemInfo { cbSize = (uint)Marshal.SizeOf(typeof(MenuItemInfo)), fMask = MIIM_FTYPE, }; if (GetMenuItemInfo(hMenu, index, true, ref itemInfo) == 0) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to get menu item info"); } if (itemInfo.fType == MFT_SEPARATOR) { if (RemoveMenu(hMenu, index, MF_BYPOSITION) == 0) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to remove menu item"); } return true; } else { return false; } } } private const int GWL_STYLE = -16; [Flags] public enum WindowStyle : int { WS_MINIMIZEBOX = 0x00020000, WS_MAXIMIZEBOX = 0x00010000, } // Don't use this version for dealing with pointers [DllImport("user32", SetLastError=true)] private static extern int SetWindowLong (IntPtr hWnd, int nIndex, int dwNewLong); // Don't use this version for dealing with pointers [DllImport("user32", SetLastError=true)] private static extern int GetWindowLong (IntPtr hWnd, int nIndex); public static int AlterWindowStyle (Window win, WindowStyle orFlags, WindowStyle andNotFlags) { var interop = new WindowInteropHelper(win); int prevStyle = GetWindowLong(interop.Handle, GWL_STYLE); if (prevStyle == 0) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to get window style"); } int newStyle = (prevStyle | (int)orFlags) & ~((int)andNotFlags); if (SetWindowLong(interop.Handle, GWL_STYLE, newStyle) == 0) { throw new Win32Exception(Marshal.GetLastWin32Error(), "Failed to set window style"); } return prevStyle; } public static int DisableMaximizeButton (Window win) { return AlterWindowStyle(win, 0, WindowStyle.WS_MAXIMIZEBOX); } } } 

Verwendung: Dies muss NACH der Initialisierung der Quelle erfolgen. Ein guter Platz ist das SourceInitialized-Ereignis des Fensters:

 Window win = ...; /* the Window :-) */ WindowUtil.DisableMaximizeButton(win); WindowUtil.RemoveMenuItem(win, WindowUtil.MenuCommand.SC_MAXIMIZE); WindowUtil.RemoveMenuItem(win, WindowUtil.MenuCommand.SC_CLOSE); while (WindowUtil.RemoveTrailingSeparator(win)) { //do it here } 

Um die Alt + F4-functionalität zu deaktivieren, besteht die einfache Methode darin, das Cancelling-Ereignis zu verkabeln und ein Flag zu setzen, wenn Sie das Fenster wirklich schließen wollen.

XAML-Code

   

sollte arbeiten

Bearbeiten – für diesen Augenblick zeigt dieser Thread , wie das gemacht werden kann, aber ich denke nicht, dass Windows eine Eigenschaft hat, um zu bekommen, was Sie wollen, ohne die normale Titelleiste zu verlieren.

Edit 2 Dieser Thread zeigt eine Möglichkeit dafür, aber Sie müssen Ihren eigenen Stil auf das Systemmenü anwenden und es zeigt eine Möglichkeit, wie Sie das tun können.

gehe zu den Fenstereigenschaften

 window style = none; 

Du wirst nicht in der Nähe Knöpfe …

Versuchen Sie, dem Fenster ein Closing-Ereignis hinzuzufügen. Fügen Sie diesen Code dem Ereignishandler hinzu.

 e.Cancel = true; 

Dies verhindert, dass das Fenster geschlossen wird. Dies hat den gleichen Effekt wie das Schließen der Schließen-Schaltfläche.

Benutze dies, modifiziert von https://stephenhaupts.com/2014/09/25/remove-the-close-button-from-a-wpf-window :

 using System; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Input; using System.Windows.Interop; using System.Windows.Media; namespace Whatever { public partial class MainMenu : Window { private const int GWL_STYLE = -16; private const int WS_SYSMENU = 0x00080000; [DllImport("user32.dll", SetLastError = true)] private static extern int GetWindowLongPtr(IntPtr hWnd, int nIndex); [DllImport("user32.dll")] private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); public MainMenu() { InitializeComponent(); this.Loaded += new RoutedEventHandler(Window_Loaded); } private void Window_Loaded(object sender, RoutedEventArgs e) { var hwnd = new WindowInteropHelper(this).Handle; SetWindowLongPtr(hwnd, GWL_STYLE, GetWindowLongPtr(hwnd, GWL_STYLE) & ~WS_SYSMENU); } } } 

Nachdem ich viel nach der Antwort gesucht habe, habe ich diese einfache Lösung ausgearbeitet, die ich hier teilen werde, in der Hoffnung, dass sie anderen hilft.

Ich setze WindowStyle=0x10000000 .

Dadurch werden die WS_VISIBLE (0x10000000) und WS_OVERLAPPED (0x0) für den Fensterstil festgelegt. “Overlapped” ist der notwendige Wert, um die Titelleiste und den Fensterrahmen anzuzeigen. Durch Entfernen der WS_MINIMIZEBOX (0x20000) , WS_MAXIMIZEBOX (0x10000) und WS_SYSMENU (0x80000) aus meinem WS_SYSMENU (0x80000) wurden alle Schaltflächen aus der Titelleiste einschließlich der Schaltfläche Schließen entfernt.

Wie in anderen Antworten angegeben, können Sie WindowStyle="None" , um die WindowStyle="None" zu entfernen.

Und wie in den Kommentaren zu diesen anderen Antworten angegeben, verhindert dies, dass das Fenster ziehbar wird, so dass es schwer ist, es aus seiner ursprünglichen Position zu bewegen.

Sie können dies jedoch umgehen, indem Sie dem Konstruktor in der Code-Behind-Datei des Fensters eine einzelne Codezeile hinzufügen:

 MouseDown += delegate { DragMove(); }; 

Oder, wenn Sie Lambda Syntax bevorzugen:

 MouseDown += (sender, args) => DragMove(); 

Dies macht das gesamte Fenster ziehbar. Alle interaktiven Steuerelemente im Fenster, z. B. Schaltflächen, funktionieren weiterhin wie gewohnt und dienen nicht als Ziehpunkte für das Fenster.

Verwenden Sie WindowStyle="SingleBorderWindow" , dies wird Max und Min Schaltfläche aus WPF-Fenster ausblenden.

Wenn es nur darum geht, dem Benutzer zu verbieten, das Fenster zu schließen, ist dies eine einfache Lösung.

XAML-Code: IsCloseButtonEnabled="False"