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

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


当前回答

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

并且,正如其他答案的评论中所述,这阻止了窗口的可拖动性,因此很难将其从初始位置移动。

但是,你可以通过在窗口的代码后面文件的构造函数中添加一行代码来克服这个问题:

MouseDown += delegate { DragMove(); };

或者,如果你喜欢Lambda语法:

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

这使得整个窗口可拖动。窗口中出现的任何交互控件,如按钮,仍将正常工作,不会作为窗口的拖拽句柄。

其他回答

要设置的属性是=> 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">

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

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

e.Cancel = true;

这样可以防止窗口关闭。这与隐藏关闭按钮具有相同的效果。

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

在窗口的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

我非常喜欢这个答案,它使用附加属性来调节行为。然而,我发现答案的实现过于复杂,它也没有解决防止窗口关闭的次要目标,即使使用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);
        }
    }
}

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

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

请注意,默认情况下,永不关闭的窗口将防止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是关闭按钮被禁用的窗口的窗口引用。

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