如何在WPF窗口中隐藏关闭按钮?

Mic*_*eth 200 wpf xaml dialog button

我正在WPF中编写一个模态对话框.如何将WPF窗口设置为没有关闭按钮?我仍然希望它的WindowState有一个普通的标题栏.

我找到了ResizeMode,WindowState和WindowStyle,但这些属性都不允许我隐藏关闭按钮但显示标题栏,就像在模态对话框中一样.

Joe*_*ite 270

WPF没有内置属性来隐藏标题栏的"关闭"按钮,但您可以使用几行P/Invoke来完成.

首先,将这些声明添加到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);
Run Code Online (Sandbox Code Playgroud)

然后将此代码放入Window的Loaded事件中:

var hwnd = new WindowInteropHelper(this).Handle;
SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU);
Run Code Online (Sandbox Code Playgroud)

你去了:没有更多关闭按钮.你也不会在标题栏的左侧有一个窗口图标,这意味着没有系统菜单,即使你右键单击标题栏 - 它们都在一起.

请注意,Alt + F4仍将关闭窗口.如果您不想在后台线程完成之前允许窗口关闭,那么您也可以覆盖OnClosing并将Cancel设置为true,如Gabe建议的那样.

  • 主要是自我注释...... DllImport的命名空间 - > System.Runtime.InteropServices.DllImport.WindowInteropHelper的命名空间 - > System.Windows.Interop.WindowInteropHelper (15认同)
  • 根据文档,我们应该使用`SetWindowLongPtr`. (5认同)
  • @miliu,不.你可以[禁用它](http://stackoverflow.com/a/1623991/87399),但你不能隐藏它而不隐藏最小化/最大化.我怀疑Windows开发人员认为如果Maximize位于Close通常所在的右侧,那将会令人困惑. (4认同)
  • 实际上,这种方法隐藏了所有三个按钮(Min,Max和Close).是否可以隐藏关闭按钮? (3认同)
  • 将WindowStyle ="None"放在XAML文件中的Window标记上. (2认同)
  • @diegodsp,来自最初的问题:“我仍然希望它的 WindowState 有一个正常的标题栏。” WindowStyle=None 没有*没有*标题栏。 (2认同)
  • 对于最琐碎的任务,WPF的难度更大。我不喜欢学习WPF。 (2认同)

小智 86

我只是遇到了类似的问题,Joe White的解决方案在我看来简单而干净.我重用它并将其定义为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

}
Run Code Online (Sandbox Code Playgroud)

然后在XAML中你只需这样设置:

<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>
Run Code Online (Sandbox Code Playgroud)

  • 应该是 `window.Loaded += ShowWhenLoadedDelegate;` 而不是 `-=` 吗?否则我看不到任何可以调用 ShowWhenLoadedDelegate 的地方。 (2认同)

Sri*_*ake 59

WindowStyle属性设置为None,这将隐藏控件框和标题栏.不需要kernal电话.

  • 好吧,这将完全隐藏窗口标题栏.这意味着您没有获得窗口标题,用户将无法移动窗口. (19认同)
  • 您可以通过将`this.DragMove();`添加到窗口的`MouseDown`事件来使窗口可移动 (6认同)
  • 对于应该纯粹提供信息和强制性的模式对话框,例如使用已打开的旧模式升级数据库的进度,此解决方案是完美的。 (2认同)
  • 绝对是最佳解决方案。在面板上添加边框或实现移动没有问题。 (2认同)

flu*_*ius 48

这不会摆脱关闭按钮,但它会阻止某人关闭窗口.

把它放在你的代码后面的文件中:

protected override void OnClosing(CancelEventArgs e)
{
   base.OnClosing(e);
   e.Cancel = true;
}
Run Code Online (Sandbox Code Playgroud)

  • 作为一个用户,我会讨厌把它放到他们的应用程序中的程序员 (8认同)
  • 请注意,在设置为模式对话框的"Window"中执行此操作会干扰设置其"DialogResult"属性的"Window",并可能使其无法使用.http://stackoverflow.com/questions/898708/cant-set-dialogresult-in-wpf (7认同)
  • 我使用这种方法得到溢出,我拿出base.OnClosing(e)然后它工作了 (4认同)
  • @UrbanEsc我倾向于同意这样做是一件烦人的事,但是当我这样做(只有一次)时,这是强制性的要求,而且是必要的恶行,正在进行一些非常重要的过程无法中断,直到完成,应用程序才能继续。还有其他方法可以完成(后台线程,禁用UI直到准备就绪),但是老板和客户都喜欢这种方式,因为它强调了流程的重要性。 (2认同)

Via*_*huk 15

要禁用关闭按钮,您应该将以下代码添加到Window类中(代码取自此处,编辑并重新格式化一点):

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;
}
Run Code Online (Sandbox Code Playgroud)

此代码还禁用"系统"菜单中的"关闭"项,并禁止使用Alt + F4关闭对话框.

您可能希望以编程方式关闭窗口.只是打电话Close()不起作用.做这样的事情:

allowClosing = true;
Close();
Run Code Online (Sandbox Code Playgroud)

  • 禁用按钮比删除按钮更好,它让用户知道重要的操作正在运行时保持一致的感觉. (3认同)

sti*_*ijn 10

我正在尝试Viachaslau的答案,因为我喜欢不删除按钮但禁用它的想法,但由于某种原因它并不总是有效:关闭按钮仍然启用但没有任何错误.

另一方面,这总是起作用(省略错误检查):

[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 );
}
Run Code Online (Sandbox Code Playgroud)


dan*_*004 8

要设置的属性是=> 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">
Run Code Online (Sandbox Code Playgroud)

  • 这也隐藏了最大/最小按钮 (4认同)
  • 它删除整个标题栏,使框变得丑陋而没有描述.霰弹枪的方法和重复的答案.Downvote. (3认同)

tom*_*ska 8

我只是使用Interactivity Behavior 添加我对Joe White的回答的实现(您需要引用System.Windows.Interactivity).

码:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

<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>
Run Code Online (Sandbox Code Playgroud)