223

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

我找到了ResizeModeWindowStateWindowStyle,但这些属性都不允许我隐藏关闭按钮但显示标题栏,就像在模式对话框中一样。

4

22 回答 22

293

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或通过任务栏关闭应用程序,窗口仍将关闭。

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

于 2009-06-06T04:15:13.733 回答
98

我刚遇到类似的问题,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

}

然后在 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>
于 2010-07-14T15:12:02.197 回答
71

WindowStyle属性设置为 None 将隐藏控制框和标题栏。无需内核调用。

于 2012-08-23T11:25:50.050 回答
55

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

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

protected override void OnClosing(CancelEventArgs e)
{
   base.OnClosing(e);
   e.Cancel = true;
}
于 2009-05-15T05:23:17.383 回答
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;
}

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

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

allowClosing = true;
Close();
于 2009-10-26T10:05:06.357 回答
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 );
}
于 2013-06-22T10:04:11.677 回答
9

要设置的属性是 =>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">
于 2014-04-29T13:05:06.483 回答
9

我只是使用交互行为添加了我对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);
    }
}

用法:

<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>
于 2014-12-05T07:02:22.803 回答
2

让用户“关闭”窗口,但实际上只是隐藏它。

在窗口的 OnClosing 事件中,如果已经可见,则隐藏窗口:

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

每次执行后台线程时,重新显示后台 UI 窗口:

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

终止程序执行时,确保所有窗口都/可以关闭:

Private Sub CloseAll()
    If w IsNot Nothing Then
        w.Visibility = Windows.Visibility.Collapsed ' Tell OnClosing to really close
        w.Close()
    End If
End Sub
于 2010-08-06T08:06:00.240 回答
1

所以,这几乎是你的问题。窗口框架右上角的关闭按钮不是 WPF 窗口的一部分,但它属于由您的操作系统控制的窗口框架部分。这意味着您必须使用 Win32 互操作来执行此操作。

或者,您可以使用 noframe 并提供您自己的“框架”或根本没有框架。

于 2009-04-13T14:55:50.530 回答
1

以下是关于禁用关闭和最大化/最小化按钮,它实际上并没有删除按钮(但它确实删除了菜单项!)。标题栏上的按钮以禁用/灰色状态绘制。(我还没有准备好自己接管所有功能^^)

这与 Virgoss 解决方案略有不同,因为它删除了菜单项(以及尾随分隔符,如果需要),而不仅仅是禁用它们。它与 Joe Whites 解决方案不同,因为它不会禁用整个系统菜单,因此,就我而言,我可以保留最小化按钮和图标。

以下代码还支持禁用最大化/最小化按钮,因为与关闭按钮不同,从菜单中删除条目不会导致系统将按钮呈现为“禁用”,即使删除菜单条目确实会禁用按钮的功能。

这个对我有用。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);
            }
        }
    }

用法:这必须在源初始化之后完成。一个好地方是使用 Window 的 SourceInitialized 事件:

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
}

要禁用 Alt+F4 功能,最简单的方法是连接 Canceling 事件并在您确实想要关闭窗口时使用设置标志。

于 2010-04-11T00:54:25.947 回答
1

这不会隐藏按钮,但会阻止用户通过关闭窗口继续前进。

protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{            
    if (e.Cancel == false)
    {
        Application.Current.Shutdown();
    }
}
于 2019-01-11T17:42:08.983 回答
1

以下是我使用自定义样式实现类似目标的方法,而无需 DllImports 和 P/Invoke 调用。这将删除现有的标题栏,WindowStyle="none"并显示一个具有相似背景颜色的“TextBlock”以指示为标题栏。

在此处输入图像描述

XAML 代码

<Window x:Class="AddBook"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:controls="http://wpftoolkit.my-libraries.com/v5" 
    WindowStartupLocation="CenterOwner"        
    ResizeMode="NoResize" 
    Style="{DynamicResource WindowStyleX}"
    ShowInTaskbar="False"
    ShowActivated="True"
    SizeToContent="Height"
    Title="Add New Book" 
    Width="450">
..............

</Window>

XAML

<Style x:Key="WindowStyleX" TargetType="{x:Type Window}">
<Setter Property="WindowStyle" Value="None" />
<Setter Property="AllowsTransparency" Value="False" />
<Setter Property="ResizeMode" Value="NoResize" />
<Setter Property="Background" Value="White" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="{x:Type Window}">
            <Border BorderBrush="{DynamicResource BlackColor}" BorderThickness="1">
                <Grid Background="{TemplateBinding Background}">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="30" />
                        <RowDefinition Height="*" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition />
                        <ColumnDefinition Width="Auto" />
                    </Grid.ColumnDefinitions>
                    <Border
                        Grid.Row="0"
                        Grid.ColumnSpan="2"
                        Background="{DynamicResource BlackColor}">
                        <Grid>
                            <TextBlock
                                Grid.Column="1"
                                Margin="10,0,0,0"
                                HorizontalAlignment="Left"
                                VerticalAlignment="Center"
                                FontSize="16"
                                Foreground="{DynamicResource WhiteTextForeground}"
                                Text="{TemplateBinding Title}" />
                        </Grid>
                    </Border>
                    <ContentPresenter Grid.Row="1" />
                </Grid>
            </Border>
        </ControlTemplate>
    </Setter.Value>
</Setter>
于 2021-08-26T13:37:27.530 回答
0

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>

应该管用

编辑- 就你而言,这个线程显示了如何做到这一点,但我认为 Window 没有一个属性可以在不丢失正常标题栏的情况下获得你想要的东西。

编辑 2线程显示了一种完成方法,但您必须将自己的样式应用于系统菜单,它显示了一种方法,您可以如何做到这一点。

于 2009-04-13T13:45:54.553 回答
0

如其他答案所述,您可以使用WindowStyle="None"完全删除标题栏。

而且,正如对其他答案的评论中所述,这可以防止窗口被拖动,因此很难将其从初始位置移动。

但是,您可以通过在 Window 的 Code Behind 文件中的构造函数中添加一行代码来克服这个问题:

MouseDown += delegate { DragMove(); };

或者,如果您更喜欢 Lambda 语法:

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

这使得整个 Window 可拖动。Window 中存在的任何交互式控件,例如 Button,仍将正常工作,并且不会充当 Window 的拖动句柄。

于 2013-09-12T17:05:11.083 回答
0

尝试向窗口添加关闭事件。将此代码添加到事件处理程序。

e.Cancel = true;

这将防止窗口关闭。这与隐藏关闭按钮的效果相同。

于 2016-08-06T15:57:32.313 回答
0

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

    }
}
于 2017-03-21T18:24:30.940 回答
0

我非常喜欢这个使用附加属性来调解行为的答案。但是,我发现答案的实现过于复杂,而且它也没有解决即使使用Alt+也无法关闭窗口的次要目标F4。所以我提供了这个替代方案:

enum CloseButtonVisibility
{
    Visible,
    Hidden,
    CloseDisabled,
}

static class WindowEx
{
    private static readonly CancelEventHandler _cancelCloseHandler = (sender, e) => e.Cancel = true;

    public static readonly DependencyProperty CloseButtonVisibilityProperty =
        DependencyProperty.RegisterAttached(
            "CloseButtonVisibility",
            typeof(CloseButtonVisibility),
            typeof(WindowEx),
            new FrameworkPropertyMetadata(CloseButtonVisibility.Visible, new PropertyChangedCallback(_OnCloseButtonChanged)));

    [AttachedPropertyBrowsableForType(typeof(Window))]
    public static CloseButtonVisibility GetCloseButtonVisibility(Window obj)
    {
        return (CloseButtonVisibility)obj.GetValue(CloseButtonVisibilityProperty);
    }

    [AttachedPropertyBrowsableForType(typeof(Window))]
    public static void SetCloseButtonVisibility(Window obj, CloseButtonVisibility value)
    {
        obj.SetValue(CloseButtonVisibilityProperty, value);
    }

    private static void _OnCloseButtonChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (!(d is Window window))
        {
            return;
        }

        if (e.OldValue is CloseButtonVisibility oldVisibility)
        {
            if (oldVisibility == CloseButtonVisibility.CloseDisabled)
            {
                window.Closing -= _cancelCloseHandler;
            }
        }

        if (e.NewValue is CloseButtonVisibility newVisibility)
        {
            if (newVisibility == CloseButtonVisibility.CloseDisabled)
            {
                window.Closing += _cancelCloseHandler;
            }

            if (!window.IsLoaded)
            {
                // NOTE: if the property is set multiple times before the window is loaded,
                // the window will wind up with multiple event handlers. But they will all
                // set the same value, so this is fine from a functionality point of view.
                //
                // The handler is never unsubscribed, so there is some nominal overhead there.
                // But it would be incredibly unusual for this to be set more than once
                // before the window is loaded, and even a handful of delegate instances
                // being around that are no longer needed is not really a big deal.
                window.Loaded += _ApplyCloseButtonVisibility;
            }
            else
            {
                _SetVisibility(window, newVisibility);
            }
        }
    }

    #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 void _ApplyCloseButtonVisibility(object sender, RoutedEventArgs e)
    {
        Window window = (Window)sender;
        CloseButtonVisibility visibility = GetCloseButtonVisibility(window);

        _SetVisibility(window, visibility);
    }

    private static void _SetVisibility(Window window, CloseButtonVisibility visibility)
    {
        var hwnd = new WindowInteropHelper(window).Handle;

        if (visibility == CloseButtonVisibility.Visible)
        {
            SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | WS_SYSMENU);
        }
        else
        {
            SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU);
        }
    }
}

这提供了三种状态可供选择:

  1. 可见的
  2. 隐藏,但用户仍然可以使用Alt+关闭F4
  3. 隐藏,关闭完全禁用

请注意,默认情况下,从不关闭的窗口将阻止 WPF 程序的进程终止。因此,如果您选择使用该CloseButtonVisibility.CloseDisabled值,您将需要自定义Application.Run()行为,或者在退出前重新启用窗口关闭。例如,在你的主窗口中,你可能有这样的东西:

protected override void OnClosed(EventArgs e)
{
    WindowEx.SetCloseButtonVisibility(this.toolWindow.Value, CloseButtonVisibility.Hidden);
    this.toolWindow.Value.Close();

    base.OnClosed(e);
}

禁用关闭按钮的窗口toolWindow的参考在哪里。Window

以上假设窗口通常只是在正常 UI 活动期间隐藏并根据需要显示。当然,您也可以随时选择显式关闭窗口,但同样的技术——将选项设置为不禁用关闭,然后显式关闭窗口——仍然适用。

于 2020-07-13T19:18:52.833 回答
-1

转到窗口属性集

window style = none;

你不会得到关闭按钮...

于 2013-07-30T10:25:11.940 回答
-1

如果只需要禁止用户关闭窗口,这是一个简单的解决方案。

XAML 代码: IsCloseButtonEnabled="False"

它阻止了按钮。

于 2017-04-26T23:41:38.340 回答
-1

在寻找了很多答案之后,我制定了这个简单的解决方案,我将在这里分享,希望它可以帮助其他人。

我设置WindowStyle=0x10000000

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

于 2018-01-16T14:18:50.633 回答
-2

使用WindowStyle="SingleBorderWindow",这将从 WPF 窗口中隐藏最大和最小按钮。

于 2012-04-25T17:29:39.687 回答