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

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


当前回答

使用这个,从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);
        }  

    }
}

其他回答

我只是使用交互性行为(你需要引用System.Windows.Interactivity)添加了我对Joe White的答案的实现。

代码:

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

用法:

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

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

然后把下面的代码放到Window的Loaded事件中:

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

这样就没有关闭按钮了。你也不会在标题栏的左边有一个窗口图标,这意味着没有系统菜单,即使你右键单击标题栏——它们都在一起。

重要提示:所有这些都是隐藏按钮。用户仍然可以关闭窗口!如果用户按下Alt+F4,或者通过任务栏关闭应用程序,窗口仍然会关闭。

如果你不想让窗口在后台线程完成之前关闭,那么你也可以覆盖OnClosing并将Cancel设置为true,就像Gabe建议的那样。

使用这个,从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);
        }  

    }
}

这不会隐藏按钮,但会阻止用户通过关闭窗口向前移动。

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

在寻找了很多答案之后,我想出了这个简单的解决方法,我将在这里分享,希望它能帮助到其他人。

我设置WindowStyle=0x10000000。

这设置了窗口样式的WS_VISIBLE (0x10000000)和WS_OVERLAPPED (0x0)值。"Overlapped"是显示标题栏和窗口边框的必要值。通过从我的样式值中删除WS_MINIMIZEBOX (0x20000)、WS_MAXIMIZEBOX (0x10000)和WS_SYSMENU (0x80000)值,标题栏中的所有按钮都被删除了,包括关闭按钮。