Jak ukryć przycisk zamykania w oknie WPF?


204

Piszę modalne okno dialogowe w WPF. Jak ustawić okno WPF, aby nie miało przycisku zamykania? Nadal chciałbym, WindowStateżeby miał normalny pasek tytułu.

Znalazłem ResizeMode, WindowStatei WindowStyle, ale żadna z tych właściwości pozwala mi ukryć zamykacz ale pokazać pasek tytułu, jak w modalnych okien dialogowych.


9
To okno dialogowe postępu uruchamiające wątek w tle, który nie obsługuje anulowania; Chyba po prostu próbuję to zrobić, aby nie musiałem (jeszcze) obsługiwać anulowania. Prawdopodobnie masz rację.
Michael Hedgpeth

1
Nienawidzę także aplikacji próbujących usunąć okno chrome. Jeśli utworzę okno dialogowe postępu, zawsze zamykam okno Zamknij przycisk tak samo jak kliknięcie przycisku Anuluj.
Christian Hayter,

13
Dla Chrisa: wyobraźmy sobie, że twoje oprogramowanie służy do nadzoru wideo. Agent bezpieczeństwa w nocy MA (to jego praca), aby utrzymać otwarte okna ... ale czasami ich praca jest nudna i chcą surfować po Internecie lub zamknąć okna Matryce wideo z dowolnego powodu, usunięcie przycisków okien jest właściwym sposobem zrobić to.
Jean-Marie,

7
@ChrisUpchurch, „Dlaczego chcesz to zrobić? Uderza mnie to naprawdę kiepski projekt interfejsu użytkownika.” - naprawdę „kiepski projekt interfejsu użytkownika” ma miejsce, gdy program wyświetla okno dialogowe z OK ; Przyciski Anuluj i Zamknij . Dla użytkownika może nie być oczywiste, co robi Close . Czy to anuluje czy prześle ? Konsensus nie polega na włączaniu przycisków zamykających w oknach dialogowych, więc istnieje
MickyD,

1
@ Jean-Marie Ale ukrywanie przycisku zamykania nie przeszkadza, że ​​to się dzieje, tylko oszuka niedoinformowanych i leniwych (do Google). Ukrywanie przycisku zamykania zapobiega tylko kliknięciu tego przycisku. Kombinacje klawiszy Win i Alt Alt będą nadal działać normalnie „Właściwym” sposobem na to jest utworzenie konta użytkownika dla pracowników z zasadami grupy, które uniemożliwiają im otwieranie / instalowanie oprogramowania innego niż zatwierdzone. konto administratora, do którego mają dostęp przełożeni, do obsługi wszelkich czynności konserwacyjnych.
Digital_Utopia,

Odpowiedzi:


275

WPF nie ma wbudowanej właściwości do ukrywania przycisku Zamknij pasek tytułu, ale możesz to zrobić za pomocą kilku linii P / Invoke.

Najpierw dodaj te deklaracje do swojej klasy Window:

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

Następnie wstaw ten kod do Loadedzdarzenia okna :

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

I proszę bardzo: nie ma już przycisku Zamknij. Po lewej stronie paska tytułu nie będzie też ikony okna, co oznacza brak menu systemowego, nawet po kliknięciu paska tytułu prawym przyciskiem myszy - wszystkie one pasują do siebie.

Zauważ, że Alt+ F4nadal zamyka okno. Jeśli nie chcesz zezwalać na zamknięcie okna przed zakończeniem wątku w tle, możesz również zastąpić OnClosingi ustawić wartość Canceltrue, zgodnie z sugestią Gabe.


5
Według dokumentów powinniśmy używać SetWindowLongPtrzamiast tego.
Jonathan Allen

15
Głównie uwaga do siebie ... Przestrzeń nazw DllImport -> System.Runtime.InteropServices.DllImport. Przestrzeń nazw WindowInteropHelper -> System.Windows.Interop.WindowInteropHelper
doobop

3
W rzeczywistości to podejście ukrywa wszystkie trzy przyciski (Min, Max i Close). Czy można po prostu ukryć przycisk Zamknij?
newman

4
@miliu, nie. Możesz go wyłączyć , ale nie możesz go ukryć bez ukrycia Minimalizuj / Maksymalizuj również. Podejrzewam, że twórcy systemu Windows myśleli, że byłoby mylące, gdyby Maximize znajdował się po prawej stronie, gdzie zwykle jest Close.
Joe White

3
Umieść WindowStyle = "None" na znaczniku Window w pliku XAML.
diegodsp

88

Właśnie miałem podobny problem i rozwiązanie Joe White'a wydaje mi się proste i czyste. Użyłem go ponownie i zdefiniowałem jako załączoną właściwość Window

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

}

Następnie w XAML po prostu ustaw to w następujący sposób:

<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

Ustaw WindowStylewłaściwość na None, która ukryje pole kontrolne wraz z paskiem tytułowym. Nie ma potrzeby wywoływania jądra.


20
To całkowicie ukryje pasek tytułu okna. Oznacza to, że nie otrzymujesz tytułu okna, a użytkownik nie będzie mógł przenieść okna.
Newman

6
Możesz sprawić, by okno było ruchome, dodając this.DragMove();do MouseDownzdarzenia okna
Paweł

1
W przypadku modalnego okna dialogowego, które powinno mieć charakter wyłącznie informacyjny i obowiązkowy, jak na przykład postęp w aktualizacji bazy danych przy użyciu starego schematu, który został otwarty, to rozwiązanie jest idealne.
The Lonely Coder,

1
Myślę, że niektórzy ludzie chcieliby mieć granicę
pjdupreez

2
Zdecydowanie najlepsze rozwiązanie. Nie ma problemu z dodawaniem ramki do panelu lub wdrażaniem przenoszenia.
buks,

50

To nie pozbędzie się przycisku zamykania, ale powstrzyma kogoś przed zamknięciem okna.

Umieść to w swoim kodzie za plikiem:

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

7
Należy pamiętać, że wykonanie tego w Windowoknie dialogowym modalnym zakłóci Windowustawienie jego DialogResultwłaściwości i może spowodować, że nie będzie można jej użyć. stackoverflow.com/questions/898708/cant-set-dialogresult-in-wpf
Sheridan

4
Otrzymałem przepełnienie za pomocą tej metody, wyjąłem base.OnClosing (e), a potem zadziałało
jacobsgriffith,

8
Jako użytkownik nienawidzę programisty, który umieścił to w swojej aplikacji
UrbanEsc

2
@ UrbanEsc Zgadzam się, że jest to irytujące, ale kiedy to zrobiłem - i to był tylko jeden raz - było to obowiązkowe wymaganie i było to zło konieczne, toczył się bardzo ważny proces nie można tego przerwać, a aplikacja nie może kontynuować, dopóki nie zostanie wykonana. Były inne sposoby, aby to zrobić (wątek w tle, z wyłączonym interfejsem użytkownika do czasu gotowości), ale szefowi i klientowi podobało się to w ten sposób, ponieważ podkreślało wagę procesu.
flurbius

15

Aby wyłączyć przycisk zamykania, należy dodać następujący kod do klasy Window (kod został pobrany stąd , nieco zmodyfikowany i ponownie sformatowany):

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

Ten kod wyłącza również zamknięcie elementu w menu System i uniemożliwia zamknięcie okna dialogowego za pomocą Alt + F4.

Prawdopodobnie będziesz chciał programowo zamknąć okno. Samo dzwonienie Close()nie zadziała. Zrób coś takiego:

allowClosing = true;
Close();

W systemie Windows 7: powyższe wyłącza również (ale nie usuwa) element Zamknij w rozwijanym menu System. Sam przycisk Zamknij jest wyłączony (wygląda na szary), ale nie został usunięty. Ta sztuczka nie działa w przypadku przycisku / przycisku Minimalizuj / Maksymalizuj - podejrzewam, że WPF ponownie je włącza.

3
Wyłączenie przycisku jest lepsze niż zwykłe usunięcie go, pozwala zachować spójność, informując użytkownika o wykonywaniu ważnej operacji.
Robert Baker

10

Próbowałem odpowiedzi Viachaslau, ponieważ podoba mi się pomysł, aby nie usuwać przycisku, ale go wyłączać, ale z jakiegoś powodu nie zawsze działało: przycisk zamykania był nadal włączony, ale bez żadnych błędów.

To z drugiej strony zawsze działało (pominięto sprawdzanie błędów):

[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
Idealny! Dodano jako Windowmetodę rozszerzenia w moim projekcie.
Matt Davis,

8

Właściwość do ustawienia to => 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
Ukrywa to również przyciski maks / min
VoteCoffee

3
Usuwa cały pasek tytułu, czyniąc pole brzydkim i bez opisu. Podejście do strzelby i podwójna odpowiedź. Głosuj
vapcguy

Jest to najlepsze rozwiązanie dla aplikacji kiosku, które zawsze wymagają zmaksymalizowania aplikacji i nie powinny pozwalać klientom na zamykanie aplikacji. Więc UpVote
Rajon Tanducar

8

Właśnie dodałem swoją implementację odpowiedzi Joe White'a przy użyciu zachowania interaktywnego (musisz odwołać się do System.Windows.Interactivity).

kod:

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

stosowanie:

<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

Pozwól użytkownikowi „zamknąć” okno, ale tak naprawdę po prostu je ukryć.

W zdarzeniu OnClosing okna ukryj okno, jeśli jest już widoczne:

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

Za każdym razem, gdy wątek w tle ma zostać wykonany, ponownie wyświetl okno interfejsu użytkownika tła:

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

Po zakończeniu wykonywania programu upewnij się, że wszystkie okna są / mogą być zamknięte:

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

Tak więc w zasadzie jest twój problem. Przycisk zamykania w prawym górnym rogu ramki okna nie jest częścią okna WPF, ale należy do części ramy okna kontrolowanej przez system operacyjny. Oznacza to, że będziesz musiał to zrobić przy pomocy Win32 Interop.

alternatywnie możesz użyć ramki noframe i albo podać własną „ramkę”, albo nie mieć żadnej ramki.


1

Poniższe informacje dotyczą wyłączania przycisków zamykania i maksymalizacji / minimalizacji, a nie rzeczywistości usuwają przycisków (ale usuwają elementy menu!). Przyciski na pasku tytułu są rysowane w stanie wyłączonym / szarym. (Nie jestem do końca gotowy do przejęcia całej funkcjonalności ^ ^)

Różni się to nieco od rozwiązania Virgoss, ponieważ usuwa elementy menu (i separator końcowy, jeśli to konieczne), a nie tylko je wyłącza. Różni się od rozwiązania Joe Whitesa, ponieważ nie wyłącza całego menu systemowego, więc w moim przypadku mogę trzymać się przycisku i ikony Minimalizuj.

Poniższy kod obsługuje również wyłączanie przycisków Maksymalizuj / Minimalizuj, ponieważ w przeciwieństwie do przycisku Zamknij, usuwanie wpisów z menu nie powoduje, że system renderuje przyciski jako „wyłączone”, nawet jeśli usunięcie pozycji menu powoduje wyłączenie funkcji przycisków.

Mi to pasuje. 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);
            }
        }
    }

Sposób użycia: Należy to zrobić PO zainicjowaniu źródła. Dobrym miejscem jest użycie zdarzenia SourceInitialized okna:

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
}

Aby wyłączyć funkcjonalność Alt + F4, łatwą metodą jest po prostu załączyć zdarzenie Anulowanie i użyć ustawienia flagi, gdy naprawdę chcesz zamknąć okno.


0

Kod XAML

<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>

powinno działać

Edytuj - na twoją chwilę ten Wątek pokazuje, jak to zrobić, ale nie sądzę, że Window ma właściwość, aby uzyskać to, czego chcesz, bez utraty normalnego paska tytułu.

Edit 2 Ten wątek pokazuje sposób na to, aby to zrobić, ale trzeba zastosować własny styl do menu systemowego i pokazuje sposób, jak można to zrobić.


z jakiegoś powodu po prostu wyświetliło się „powinno działać”, ale teraz nastąpiła aktualizacja
TStamper 13.04.2009

3
Mówię jednak o stanie okna, który znajduje się na pasku tytułu. Wygląda to jak edycja prostego przycisku.
Michael Hedgpeth

@TStamper, jak korzystać z Twojego fragmentu kodu? Używam globalnego stylu okna (i szablonu).
Shimmy Weitzhandler,

@ Shimmy- o którym mówisz?
TStamper

0

Spróbuj dodać zdarzenie Zamykanie do okna. Dodaj ten kod do procedury obsługi zdarzeń.

e.Cancel = true;

Zapobiegnie to zamknięciu okna. Ma to taki sam efekt, jak ukrywanie przycisku zamykania.


1
„Ma to taki sam efekt, jak ukrywanie przycisku zamykania”. z wyjątkiem tego, że przycisk jest nadal widoczny i klikalny, tj. jest animowany i przygnębia po kliknięciu - co jest sprzeczne z POLA .
rory.ap

0

Użyj tego, zmodyfikowanego z 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

Nie ukrywa to przycisku, ale uniemożliwi użytkownikowi przejście do przodu przez zamknięcie okna.

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

-1

zestaw właściwości okna goto

window style = none;

nie dostaniesz blisko przycisków ...


Głosuj Tak naprawdę WindowStyle = "None"- uważaj na swoją składnię. Po drugie, jest to podejście strzelbowe, które usuwa pasek tytułowy, czyniąc pudełko brzydkim i pozbawionym tytułu, gdy istnieje o wiele wiele lepszych sposobów radzenia sobie z tym (o czym świadczą inne odpowiedzi), i jest duplikatem odpowiedzi.
vapcguy

-1

Jak stwierdzono w innych odpowiedziach, możesz WindowStyle="None"całkowicie usunąć pasek tytułu.

I, jak stwierdzono w komentarzach do tych innych odpowiedzi, uniemożliwia to przeciąganie okna, więc trudno jest go przenieść z początkowej pozycji.

Można jednak temu zaradzić, dodając jeden wiersz kodu do Konstruktora w pliku Code Behind w oknie:

MouseDown += delegate { DragMove(); };

Lub, jeśli wolisz składnię Lambda:

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

Dzięki temu całe okno można przeciągać. Wszelkie interaktywne elementy sterujące obecne w oknie, takie jak Przyciski, będą nadal działać normalnie i nie będą działać jako uchwyty przeciągania dla okna.


Wciąż zły pomysł. Usuwa cały pasek tytułu, dzięki czemu jest to strzelba, i sprawia, że ​​pudełko wygląda brzydko i oznacza, że ​​nie ma dla niego tytułu / opisu. Istnieją znacznie lepsze alternatywy.
vapcguy

@vapcguy Usuwa cały pasek tytułu. To podejście do strzelby. Sprawia, że ​​pudełko wygląda brzydko? Twoja opinia. O wiele lepsze alternatywy? Być może dla ciebie. Nie dla każdego. :-)
Holf

-1

Po wielu poszukiwaniach odpowiedzi na to pytanie opracowałem to proste rozwiązanie, które podzielę się tutaj w nadziei, że pomoże innym.

Ustawiłem WindowStyle=0x10000000.

Ustawia to wartości WS_VISIBLE (0x10000000)i WS_OVERLAPPED (0x0)Styl okna. „Nakładające się” to wartość niezbędna do wyświetlenia paska tytułu i obramowania okna. Przez usunięcie WS_MINIMIZEBOX (0x20000), WS_MAXIMIZEBOX (0x10000), oraz WS_SYSMENU (0x80000)wartości z wartością mojego stylu, wszystkie przyciski z paska tytułowego zostały usunięte, w tym przycisk Zamknij.


W WPF WindowStylejest wyliczenie, którego wartości nie są zgodne ze stałymi interfejsami API systemu Windows; wymuszanie wartości do WindowStylewyliczenia nie będzie działać. Dla pewności sprawdziłem kod źródłowy .NET w ILSpy; wartość wyliczana jest tłumaczona na Windows API w funkcji prywatnej CreateWindowStyle, a jeśli funkcja napotka nieznaną WindowStylewartość, po prostu ma zastosowanie WindowStyle.None. (Jedynym sposobem byłoby użycie właściwości wewnętrznych _Stylei _StyleExodbicia, których zdecydowanie odradzam.)
Mike Rosoft,


-2

Jeśli jest to tylko po to, aby zabronić użytkownikowi zamknięcia okna, jest to proste rozwiązanie.

Kod XAML: IsCloseButtonEnabled="False"

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.