Wie verstecke ich die Schaltfläche zum Schließen im WPF-Fenster?


204

Ich schreibe einen modalen Dialog in WPF. Wie stelle ich ein WPF-Fenster so ein, dass es keine Schaltfläche zum Schließen gibt? Ich hätte immer noch gerne WindowStateeine normale Titelleiste.

Ich fand ResizeMode, WindowStateund WindowStyle, aber keine dieser Eigenschaften erlauben Sie mir , die Schließen - Schaltfläche zu verstecken , aber die Titelleiste zeigen, wie in modalen Dialogen.


9
Es ist ein Fortschrittsdialog, in dem ein Hintergrundthread ausgeführt wird, der das Abbrechen nicht unterstützt. Ich denke, ich versuche nur, es zu schaffen, damit ich das Abbrechen (noch) nicht unterstützen muss. Du hast aber wahrscheinlich recht.
Michael Hedgpeth

1
Ich hasse auch Apps, die versuchen, Windows Chrome zu entfernen. Wenn ich einen Fortschrittsdialog mache, lasse ich die Schaltfläche zum Schließen des Fensters immer dieselbe Logik ausführen wie das Klicken auf die eigentliche Schaltfläche Abbrechen.
Christian Hayter

13
Für Chris: Stellen wir uns vor, Ihre Software ist für die Videoüberwachung vorgesehen. Ein Sicherheitsagent während der Nacht MUSS (das ist seine Aufgabe), die Fenster geöffnet zu halten ... aber manchmal ist ihre Arbeit langweilig und sie möchten aus irgendeinem Grund im Internet surfen oder die Fenster der Videomatrizen schließen. Das Entfernen der Fenstertasten ist der richtige Weg es zu tun.
Jean-Marie

7
@ChrisUpchurch, "Warum möchten Sie das tun? Es scheint mir ein wirklich mieses UI-Design zu sein." - Ein wirklich "mieses UI-Design" ist, wenn ein Programm ein Dialogfeld mit OK anzeigt . Schaltflächen Abbrechen und Schließen . Für einen Benutzer ist es möglicherweise nicht offensichtlich, was Close tut. Ist es stornieren oder einreichen ? Konsens besteht darin, keine Schaltflächen zum Schließen in Dialoge aufzunehmen, also gibt es das
MickyD

1
@ Jean-Marie Aber das Ausblenden der Schaltfläche zum Schließen verhindert nicht, dass dies geschieht, sondern täuscht nur die Uninformierten und Faulen (gegenüber Google). Durch Ausblenden der Schaltfläche zum Schließen wird nur das Klicken auf diese Schaltfläche verhindert. Win-Key- und Alt-Key-Kombinationen funktionieren weiterhin wie gewohnt. Der "richtige" Weg, dies zu tun, besteht darin, ein Benutzerkonto für Mitarbeiter mit einer Gruppenrichtlinie zu erstellen, die verhindert, dass sie andere als die genehmigte Software öffnen / installieren Administratorkonto, auf das Supervisoren Zugriff haben, um Wartungsarbeiten durchzuführen.
Digital_Utopia

Antworten:


275

WPF verfügt nicht über eine integrierte Eigenschaft zum Ausblenden der Schaltfläche Schließen in der Titelleiste. Sie können dies jedoch mit ein paar Zeilen P / Invoke tun.

Fügen Sie zunächst Ihre Deklarationen zu Ihrer Window-Klasse 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);

Fügen Sie dann diesen Code in das LoadedEreignis des Fensters ein :

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

Und los geht's: keine Schaltfläche mehr schließen. Sie haben auch kein Fenstersymbol auf der linken Seite der Titelleiste, was bedeutet, dass kein Systemmenü angezeigt wird, selbst wenn Sie mit der rechten Maustaste auf die Titelleiste klicken - alle gehören zusammen.

Beachten Sie, dass Alt+ F4das Fenster weiterhin schließt. Wenn Sie nicht möchten, dass das Fenster geschlossen wird, bevor der Hintergrund-Thread fertig ist, können Sie es auch überschreiben OnClosingund Cancelauf true setzen, wie Gabe vorgeschlagen hat.


5
Laut den Dokumenten sollten wir SetWindowLongPtrstattdessen verwenden.
Jonathan Allen

15
Meistens ein Hinweis für sich selbst ... Namespace von DllImport -> System.Runtime.InteropServices.DllImport. Namespace von WindowInteropHelper -> System.Windows.Interop.WindowInteropHelper
Doobop

3
Tatsächlich verbirgt dieser Ansatz alle drei Schaltflächen (Min, Max und Close). Ist es möglich, die Schaltfläche Schließen einfach auszublenden?
Newman

4
@Miliu, nein. Sie können es deaktivieren , aber Sie können es nicht ausblenden, ohne auch Minimieren / Maximieren auszublenden. Ich vermute, die Windows-Entwickler dachten, es wäre verwirrend, wenn Maximize auf der rechten Seite wäre, wo Close normalerweise ist.
Joe White

3
Fügen Sie WindowStyle = "None" in Ihr Window-Tag in der XAML-Datei ein.
Diegodsp

88

Ich bin gerade zu einem ähnlichen Problem gekommen und Joe Whites Lösung scheint mir einfach und sauber zu sein. Ich habe es wiederverwendet und als angehängte Eigenschaft von Window 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 setzen Sie es in XAML einfach so:

<Window 
    x:Class="WafClient.Presentation.Views.SampleWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:u="clr-namespace:WafClient.Presentation.Behaviors"
    ResizeMode="NoResize"
    u:WindowBehavior.HideCloseButton="True">
    ...
</Window>

62

Setzen Sie die WindowStyleEigenschaft auf Keine, wodurch das Kontrollfeld zusammen mit der Titelleiste ausgeblendet wird. Keine Notwendigkeit für kernale Anrufe.


20
Dadurch wird die Titelleiste des Fensters vollständig ausgeblendet. Das bedeutet, dass Sie keinen Fenstertitel erhalten und der Benutzer das Fenster nicht verschieben kann.
Newman

6
Sie können das Fenster beweglich machen, indem Sie es this.DragMove();zum MouseDownEreignis des Fensters hinzufügen
Paul

1
Für einen modalen Dialog, der rein informativ und obligatorisch sein sollte, wie z. B. Fortschritte beim Aktualisieren einer Datenbank mit einem alten Schema, das geöffnet wurde, ist diese Lösung perfekt.
The Lonely Coder

1
Ich denke, einige Leute hätten gerne eine Grenze
pjdupreez

2
Auf jeden Fall die beste Lösung. Es ist kein Problem, dem Bedienfeld einen Rahmen hinzuzufügen oder das Verschieben zu implementieren.
buks

50

Dadurch wird die Schaltfläche zum Schließen nicht entfernt, aber es wird verhindert, dass jemand das Fenster schließt.

Fügen Sie dies in Ihren Code hinter der Datei ein:

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

7
Beachten Sie, dass dies in einem Windowals modaler Dialog eingerichteten Dialog die WindowEinstellung seiner DialogResultEigenschaft beeinträchtigt und möglicherweise unbrauchbar macht. stackoverflow.com/questions/898708/cant-set-dialogresult-in-wpf
Sheridan

4
Ich bekam einen Überlauf mit dieser Methode, ich nahm base.OnClosing (e) und dann funktionierte es
jacobsgriffith

8
Als Benutzer würde ich den Programmierer hassen, der dies in seine Anwendung aufgenommen hat
UrbanEsc

2
@UrbanEsc Ich würde eher zustimmen, dass es eine nervige Sache ist, aber als ich dies tat - und es war nur das eine Mal - war es eine obligatorische Anforderung, und es war ein notwendiges Übel, es gab einen sehr wichtigen Prozess das konnte nicht unterbrochen werden und die App konnte nicht fortgesetzt werden, bis es fertig war. Es gab andere Möglichkeiten, wie dies hätte geschehen können (ein Hintergrund-Thread, bei dem die Benutzeroberfläche deaktiviert war, bis sie fertig war), aber sowohl der Chef als auch der Kunde mochten es auf diese Weise, weil es die Schwere des Prozesses betonte.
Flurbius

15

Um die Schaltfläche zum Schließen zu deaktivieren, sollten Sie Ihrer Window-Klasse den folgenden Code hinzufügen (der Code wurde von hier übernommen , bearbeitet und ein wenig 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 das Schließen des Dialogfelds mit Alt + F4.

Möglicherweise möchten Sie das Fenster programmgesteuert schließen. Nur anrufen Close()wird nicht funktionieren. Mach so etwas:

allowClosing = true;
Close();

In Windows 7: Durch das oben Gesagte wird auch das Element Schließen im Dropdown-Menü System deaktiviert (aber nicht entfernt). Die Schaltfläche Schließen selbst ist deaktiviert (sieht grau aus), wird jedoch nicht entfernt. Dieser Trick funktioniert nicht für das Element / die Schaltfläche "Minimieren / Maximieren". Ich vermute, dass WPF sie wieder aktiviert.

3
Das Deaktivieren der Schaltfläche ist besser als nur das Entfernen. Sie behält ein einheitliches Gefühl bei und informiert den Benutzer darüber, dass ein wichtiger Vorgang ausgeführt wird.
Robert Baker

10

Ich habe Viachaslaus Antwort versucht, da mir die Idee gefällt, die Schaltfläche nicht zu entfernen, sondern zu deaktivieren, aber aus irgendeinem Grund hat es nicht immer funktioniert: Die Schaltfläche zum Schließen war immer noch aktiviert, aber es gab keinerlei Fehler.

Dies hat andererseits immer funktioniert (Fehlerprüfung weggelassen):

[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 );
}

1
Perfekt! Als WindowErweiterungsmethode in meinem Projekt hinzugefügt .
Matt Davis

8

Die festzulegende Eigenschaft ist => WindowStyle="None"

<Window x:Class="mdaframework.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Start" Height="350" Width="525" ResizeMode="NoResize"  WindowStartupLocation="CenterScreen" WindowStyle="None">

4
Dies verbirgt auch die Max / Min-Tasten
VoteCoffee

3
Es entfernt die gesamte Titelleiste und macht das Feld hässlich und ohne Beschreibung. Schrotflinten-Ansatz und eine doppelte Antwort. Downvote.
Vapcguy

Dies ist die beste Lösung für Kiosk-Anwendungen, bei denen die Anwendung immer maximiert werden muss und Kunden das Schließen von Apps nicht zulassen sollten. Also UpVote
Rajon Tanducar

8

Ich füge nur meine Implementierung der Antwort von Joe White mithilfe des Interaktivitätsverhaltens hinzu (Sie müssen auf System.Windows.Interactivity verweisen).

Code:

public class HideCloseButtonOnWindow : Behavior<Window>
{
    #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:

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:w="clr-namespace:WpfApplication2">

    <i:Interaction.Behaviors>
        <w:HideCloseButtonOnWindow />
    </i:Interaction.Behaviors>

</Window>

2

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

Blenden Sie im OnClosing-Ereignis des Fensters das Fenster aus, falls es bereits sichtbar ist:

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

Zeigen Sie jedes Mal, wenn der Hintergrund-Thread ausgeführt werden soll, das Hintergrund-UI-Fenster erneut an:

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

Stellen Sie beim Beenden der Programmausführung sicher, dass alle Fenster geschlossen sind / geschlossen werden 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

1

Also, so ziemlich hier ist dein Problem. Die Schaltfläche zum Schließen oben rechts in einem Fensterrahmen ist nicht Teil des WPF-Fensters, gehört jedoch zu dem Teil des Fensterrahmens, der von Ihrem Betriebssystem gesteuert wird. Dies bedeutet, dass Sie Win32 Interop verwenden müssen, um dies zu tun.

Alternativ können Sie den Noframe verwenden und entweder Ihren eigenen "Frame" bereitstellen oder überhaupt keinen Frame haben.


1

Im Folgenden werden die Schaltflächen zum Schließen und Maximieren / Minimieren deaktiviert. Die Schaltflächen werden jedoch nicht entfernt (die Menüelemente werden jedoch entfernt!). Die Schaltflächen in der Titelleiste sind deaktiviert / grau gezeichnet. (Ich bin nicht ganz bereit, alle Funktionen selbst zu übernehmen ^^)

Dies unterscheidet sich geringfügig von der Virgoss-Lösung darin, dass die Menüelemente (und ggf. das nachfolgende Trennzeichen) entfernt werden, anstatt sie nur zu deaktivieren. Es unterscheidet sich von der Joe Whites-Lösung, da es nicht das gesamte Systemmenü deaktiviert und ich in meinem Fall die Schaltfläche und das Symbol "Minimieren" beibehalten kann.

Der Nachfolger Code unterstützt auch die Maximize deaktivieren / Minimieren Tasten wie, anders als die Schaltfläche Schließen aus dem Menü die Einträge entfernt das System nicht dazu führt , die Tasten „disabled“ selbst zu machen , wenn die Menüeinträge zu entfernen tut deaktivieren die Funktionalität der Tasten.

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<IntPtr> 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 erfolgen, nachdem die Quelle initialisiert wurde. Ein guter Ort ist die Verwendung des SourceInitialized-Ereignisses 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-Funktionalität zu deaktivieren, besteht die einfache Methode darin, das Ereignis "Abbrechen" zu verkabeln und ein Flag zu setzen, wenn Sie das Fenster wirklich schließen möchten.


0

XAML-Code

<Button Command="Open" Content="_Open">
    <Button.Style>
        <Style TargetType="Button">
            <Style.Triggers>
                <Trigger Property="IsEnabled" Value="False">
                    <Setter Property="Visibility" Value="Collapsed" />
                </Trigger>
            </Style.Triggers>
        </Style>
     </Button.Style>
</Button>

sollte arbeiten

Bearbeiten - für Ihren Moment zeigt dieser Thread , wie das gemacht werden kann, aber ich glaube nicht, dass Window eine Eigenschaft hat, um das zu bekommen, was Sie wollen, ohne die normale Titelleiste zu verlieren.

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


Aus irgendeinem Grund wurde "sollte funktionieren" nur angezeigt, aber jetzt aktualisiert
TStamper

3
Ich spreche jedoch über den Fensterstatus, der sich in der Titelleiste befindet. Dies sieht aus wie das Bearbeiten einer einfachen Schaltfläche.
Michael Hedgpeth

@TStamper, wie verwende ich dein Snippet? Ich verwende einen globalen Fensterstil (und eine Vorlage).
Shimmy Weitzhandler

@ Shimmy- auf welches beziehst du dich?
TStamper

0

Versuchen Sie, dem Fenster ein Abschlussereignis hinzuzufügen. Fügen Sie diesen Code dem Ereignishandler hinzu.

e.Cancel = true;

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


1
"Dies hat den gleichen Effekt wie das Ausblenden der Schaltfläche zum Schließen." mit der Ausnahme, dass die Schaltfläche weiterhin sichtbar und anklickbar ist, dh animiert ist und beim Klicken visuell gedrückt wird - was POLA trotzt .
rory.ap

0

Verwenden Sie diese Option, geändert von https://stephenhaunts.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);
        }  

    }
}

0

Dies verbirgt die Schaltfläche nicht, verhindert jedoch, dass sich der Benutzer vorwärts bewegt, indem das Fenster geschlossen wird.

protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{            
    if (e.Cancel == false)
    {
        Application.Current.Shutdown();
    }
}

-1

gehe zu Fenstereigenschaften eingestellt

window style = none;

Du wirst keine engen Knöpfe bekommen ...


Downvote. Es ist eigentlich WindowStyle = "None"- achten Sie auf Ihre Syntax. Zum anderen handelt es sich um einen Shotgun-Ansatz, bei dem auch die Titelleiste entfernt wird, wodurch die Box hässlich wird und kein Titel mehr vorhanden ist, wenn es so viele bessere Möglichkeiten gibt, damit umzugehen (wie aus den anderen Antworten hervorgeht), und es handelt sich um eine doppelte Antwort.
Vapcguy

-1

Wie in anderen Antworten angegeben, können Sie WindowStyle="None"die Titelleiste vollständig entfernen.

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

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

MouseDown += delegate { DragMove(); };

Oder wenn Sie die Lambda-Syntax bevorzugen:

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

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


Immer noch eine schlechte Idee. Es entfernt die gesamte Titelleiste, was dies zu einem Schrotflintenansatz macht, und lässt die Box hässlich aussehen und bedeutet, dass es keinen Titel / keine Beschreibung dafür gibt. Es gibt viel bessere Alternativen.
Vapcguy

@vapcguy Entfernt die gesamte Titelleiste. Es ist ein Schrotflintenansatz. Lässt die Box hässlich aussehen? Deine Meinung. Viel bessere Alternativen? Für dich vielleicht. Nicht für jeden. :-)
Holf

-1

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

Ich setze WindowStyle=0x10000000.

Hiermit werden die Werte WS_VISIBLE (0x10000000)und WS_OVERLAPPED (0x0)für den Fensterstil festgelegt. "Überlappt" ist der erforderliche Wert, um die Titelleiste und den Fensterrand anzuzeigen. Durch das Entfernen WS_MINIMIZEBOX (0x20000), WS_MAXIMIZEBOX (0x10000)und WS_SYSMENU (0x80000)Werte von meinem Stil Wert, sind alle Tasten aus der Titelleiste entfernt wurden, einschließlich der Schaltfläche Schließen.


In WPF WindowStylebefindet sich eine Aufzählung, deren Werte nicht mit den Windows-API-Konstanten übereinstimmen. Das Erzwingen des Werts zur WindowStyleAufzählung funktioniert nicht. Natürlich habe ich den .NET-Quellcode in ILSpy überprüft. Der Enum-Wert wird in der privaten Funktion in die Windows-API übersetzt. CreateWindowStyleWenn die Funktion auf einen unbekannten WindowStyleWert stößt , gilt er einfach WindowStyle.None. (Der einzige Weg wäre, die internen Eigenschaften _Styleund _StyleExdie Reflexion zu verwenden, von denen ich dringend empfehle.)
Mike Rosoft

-2

Verwenden Sie WindowStyle="SingleBorderWindow"diese Option, um die Max- und Min-Schaltflächen im WPF-Fenster auszublenden.


1
löst nicht das Problem, den closeKnopf zu verstecken
Erinnerung an einen Traum

-2

Wenn der Benutzer nur daran gehindert werden soll, das Fenster zu schließen, ist dies eine einfache Lösung.

XAML-Code: IsCloseButtonEnabled="False"

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.