Como esconder o botão fechar na janela do WPF?

Eu estou escrevendo um modal dialog no WPF. Como faço para definir uma janela do WPF para não ter um botão de fechamento? Eu ainda gostaria que seu WindowState tivesse uma barra de título normal.

Eu encontrei ResizeMode, WindowState e WindowStyle, mas nenhuma dessas propriedades me permite ocultar o botão Fechar, mas mostra a barra de título, como em checkboxs de diálogo modais.

O WPF não possui uma propriedade interna para ocultar o botão Fechar da barra de título, mas você pode fazê-lo com algumas linhas de P / Invoke.

Primeiro, adicione estas declarações à sua class 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); 

Então coloque este código no evento Window’s Loaded:

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

E lá vai você: não mais botão Fechar. Você também não terá um ícone de janela no lado esquerdo da barra de título, o que significa que não há menu Sistema, mesmo quando você clica com o botão direito do mouse na barra de título – todos eles vão juntos.

Observe que Alt + F4 ainda fechará a janela. Se você não quiser permitir que a janela seja fechada antes que o thread de segundo plano seja concluído, você também poderá replace OnClosing e definir Cancel como true, como Gabe sugeriu.

Acabei de chegar a um problema semelhante e a solução de Joe White parece-me simples e limpa. Eu reutilizei e defini como uma propriedade anexada de 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 } 

Então, em XAML você acabou de definir assim:

  ...  

Defina a propriedade WindowStyle como None, que ocultará a checkbox de controle junto com a barra de título. Não há necessidade de chamadas kernal.

Isso não eliminará o botão fechar, mas impedirá que alguém feche a janela.

Coloque isso no seu código por trás do arquivo:

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

Para desabilitar o botão fechar, você deve adicionar o seguinte código à sua class Window (o código foi tirado daqui , editado e reformatado um pouco):

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

Esse código também desabilita o item fechar no menu Sistema e não permite fechar a checkbox de diálogo usando Alt + F4.

Você provavelmente desejará fechar a janela programaticamente. Apenas chamar Close() não funcionará. Faça algo assim:

 allowClosing = true; Close(); 

Eu estava tentando a resposta do Viachaslau desde que eu gostei da ideia de não remover o botão, mas desabilitá-lo, mas por alguma razão nem sempre funcionava: o botão fechar ainda estava habilitado, mas sem nenhum erro.

Isso, por outro lado, sempre funcionou (verificação de erros omitidos):

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

Acabei de adicionar minha implementação da resposta de Joe White usando Interactivity Behavior (você precisa referenciar System.Windows.Interactivity).

código:

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

uso:

      

A propriedade para definir é => WindowStyle="None"

  

Então, praticamente aqui é o seu problema. O botão fechar no canto superior direito de um quadro de janela não faz parte da janela do WPF, mas pertence à parte do quadro de janela que é controlado pelo seu sistema operacional. Isso significa que você terá que usar o Win32 interoperar para fazer isso.

Alternativamente, você pode usar o noframe e fornecer seu próprio “frame” ou não ter nenhum frame.

O seguinte é sobre como desabilitar os botões Fechar e Maximizar / Minimizar, ele não remove os botões (mas remove os itens de menu!). Os botões na barra de título são desenhados em um estado desativado / cinza. (Eu não estou totalmente pronto para assumir todas as funcionalidades sozinho ^^)

Isso é um pouco diferente da solução Virgoss, pois remove os itens de menu (e o separador à direita, se necessário), em vez de apenas desabilitá-los. Ele difere da solução Joe Whites, já que ele não desativa todo o menu do sistema e, no meu caso, eu posso manter o botão Minimizar e o ícone.

O código a seguir também suporta a desativação dos botões Maximizar / Minimizar, pois, ao contrário do botão Fechar, a remoção das inputs do menu não faz com que o sistema seja “desativado”, embora a remoção das inputs do menu desative a funcionalidade dos botões.

Funciona para mim. 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); } } } 

Uso: Isso deve ser feito APÓS a fonte ser inicializada. Um bom lugar é usar o evento SourceInitialized da janela:

 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 } 

Para desativar a funcionalidade Alt + F4, o método fácil é apenas conectar o evento Canceling e usar um sinalizador para quando você realmente deseja fechar a janela.

Código XAML

   

Deveria trabalhar

Edit – para o seu instante este Thread mostra como isso pode ser feito, mas eu não acho que o Window tenha uma propriedade para obter o que você quer sem perder a barra de título normal.

Editar 2 Este segmento mostra uma maneira de fazê-lo, mas você deve aplicar seu próprio estilo ao menu do sistema e mostra como você pode fazer isso.

Deixe o usuário “fechar” a janela, mas apenas esconda-a.

No evento OnClosing da janela, oculte a janela se já estiver visível:

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

Sempre que o encadeamento em segundo plano for executado, mostre novamente a janela da interface de usuário em segundo plano:

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

Ao terminar a execução do programa, verifique se todas as janelas estão / podem ser fechadas:

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

conjunto de propriedades da janela goto

 window style = none; 

você não vai chegar perto botões …

Tente adicionar um evento de fechamento à janela. Adicione este código ao manipulador de events.

 e.Cancel = true; 

Isso impedirá que a janela feche. Isto tem o mesmo efeito que esconder o botão fechar.

Use isso, modificado em 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); } } } 

Depois de muito procurar a resposta para isso, eu trabalhei para fora desta solução simples que vou compartilhar aqui na esperança de que ajude os outros.

Eu defino WindowStyle=0x10000000 .

Isso define os valores WS_VISIBLE (0x10000000) e WS_OVERLAPPED (0x0) para Estilo da janela. “Sobreposto” é o valor necessário para mostrar a barra de título e a borda da janela. Removendo os valores WS_MINIMIZEBOX (0x20000) , WS_MAXIMIZEBOX (0x10000) e WS_SYSMENU (0x80000) do meu valor de estilo, todos os botões da barra de título foram removidos, incluindo o botão Fechar.

Como afirmado em outras respostas, você pode usar WindowStyle="None" para remover a barra de título completamente.

E, como indicado nos comentários para essas outras respostas, isso impede que a janela seja arrastável, por isso é difícil movê-la de sua posição inicial.

No entanto, você pode superar isso adicionando uma única linha de código ao construtor no arquivo Code Behind da janela:

 MouseDown += delegate { DragMove(); }; 

Ou, se você preferir a syntax do Lambda:

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

Isso torna toda a janela arrastável. Quaisquer controles interativos presentes na janela, como botões, ainda funcionarão normalmente e não funcionarão como alças de arrasto para a janela.

Use WindowStyle="SingleBorderWindow" , isso irá esconder o botão max e min da janela do WPF.

Se a necessidade é apenas proibir o usuário de fechar a janela, esta é uma solução simples.

Código XAML: IsCloseButtonEnabled="False"