Как скрыть кнопку закрытия в окне WPF?


204

Я пишу модальный диалог в WPF. Как настроить окно WPF, чтобы не было кнопки закрытия? Я все еще хотел бы для егоWindowState чтобы у него была нормальная строка заголовка.

Я обнаружил ResizeMode, WindowStateи WindowStyle, но ни одно из этих свойств не позволяет мне скрыть кнопку закрытия, но показать строку заголовка, как в модальных диалогах.


9
Это диалоговое окно прогресса, запускающее фоновый поток, который не поддерживает отмену; Я думаю, я просто пытаюсь сделать это, поэтому мне не нужно поддерживать отмену (пока). Вы, вероятно, правы, хотя.
Майкл Хедгпет

1
Я также ненавижу приложения, пытающиеся удалить хром окна. Если я создаю диалоговое окно прогресса, я всегда заставляю кнопку «Закрыть окно» выполнять ту же логику, что и нажатие самой кнопки «Отмена».
Кристиан Хейтер

13
Для Криса: давайте представим, что ваше программное обеспечение для видеонаблюдения. Ночью агент по безопасности ХОЧЕТ (это его работа) держать окна открытыми ... но иногда их работа скучна, и они хотят выходить в Интернет или закрывать окна Видео Матрицы по любой причине, удаление кнопок окон является правильным способом сделать это.
Жан-Мари

7
@ChrisUpchurch, «Почему вы хотите это сделать? Мне кажется, это действительно паршивый дизайн пользовательского интерфейса.» - действительно «паршивый дизайн пользовательского интерфейса» - это когда программа представляет диалоговое окно с OK ; Кнопки Отмена и Закрыть . Для пользователя может быть неочевидно, что делает Close . Есть ли отменить или отправить ? Консенсус не должен включать кнопки закрытия в диалогах, поэтому есть
MickyD

1
@ Жан-Мари Но сокрытие кнопки закрытия не предотвращает этого, а только обманывает неосведомленных и ленивых (для Google). Скрытие кнопки закрытия только предотвращает нажатие этой кнопки. Комбинации клавиш Win и Alt Key по-прежнему будут работать в обычном режиме. «Правильный» способ сделать это - создать учетную запись пользователя для работников с помощью групповой политики, которая не позволяет им открывать / устанавливать любое программное обеспечение, кроме утвержденного. учетная запись администратора, к которой у супервайзеров есть доступ для обслуживания.
Digital_Utopia

Ответы:


276

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

Затем поместите этот код в Loadedсобытие окна :

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

И вот вы здесь: больше нет кнопки «Закрыть». У вас также не будет значка окна с левой стороны строки заголовка, что означает отсутствие системного меню, даже если вы щелкнете правой кнопкой мыши на строке заголовка - все они будут объединены.

Обратите внимание, что Alt+ F4все равно закроет окно. Если вы не хотите, чтобы окно закрывалось до завершения фонового потока, вы также можете переопределить OnClosingи установить Cancelзначение true, как предложил Гейб.


5
Согласно документам мы должны использовать SetWindowLongPtrвместо этого.
Джонатан Аллен

15
Главным образом примечание к себе ... Пространство имен DllImport -> System.Runtime.InteropServices.DllImport. Пространство имен WindowInteropHelper -> System.Windows.Interop.WindowInteropHelper
doobop

3
На самом деле, этот подход скрывает все три кнопки (Мин, Макс и Закрыть). Можно ли просто скрыть кнопку Закрыть?
новичок

4
@miliu, нет. Вы можете отключить это , но вы не можете скрыть это, не скрывая также Свернуть / Развернуть. Я подозреваю, что разработчики Windows думали, что было бы непонятно, если бы Maximize был справа, где обычно находится Close.
Джо Уайт

3
Поместите WindowStyle = "None" в свой тег Window в файле XAML.
diegodsp

89

Я только что столкнулся с подобной проблемой, и решение Джо Уайта кажется мне простым и понятным. Я использовал его снова и определил как прикрепленное свойство 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>

64

Установите для WindowStyleсвойства значение None, что будет скрывать поле управления вместе с заголовком. Не надо кернал звонков.


20
Ну, это полностью скрывает строку заголовка окна. Это означает, что вы не получите заголовок окна, и пользователь не сможет переместить окно.
новичок

8
Вы можете сделать окно подвижным, добавив this.DragMove();к нему MouseDownсобытие
Пол

1
Для модального диалога, который должен быть чисто информационным и обязательным, как, например, прогресс в обновлении базы данных со старой открытой схемой, это решение идеально.
Одинокий кодер

1
Я думаю, что некоторые люди хотели бы иметь границу
pjdupreez

2
Определенно лучшее решение. Нет проблем с добавлением границы на панель или выполнением перемещения.
Buks

50

Это не избавит от кнопки закрытия, но остановит того, кто закроет окно.

Поместите это в свой код за файлом:

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

7
Имейте в виду, что выполнение этого в объекте, Windowкоторый настроен как модальный диалог, повлияет на Windowнастройку его DialogResultсвойства и может сделать его непригодным для использования. stackoverflow.com/questions/898708/cant-set-dialogresult-in-wpf
Шеридан

4
Я получал переполнение, используя этот метод, я вынул base.OnClosing (e), а затем он
заработал

8
Как пользователь, я бы ненавидел программиста, который поместил это в свое приложение
UrbanEsc

2
@UrbanEsc Я бы согласился с тем, что это раздражает, но когда я сделал это - и только один раз - это было обязательное требование, и это было неизбежное зло, происходил какой-то очень важный процесс это не могло быть прервано, и приложение не могло продолжаться, пока это не было сделано. Существовали и другие способы сделать это (фоновый поток с отключенным пользовательским интерфейсом, пока он не был готов), но боссу и клиенту это понравилось, потому что это подчеркивало серьезность процесса.
Флорбиус

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

В Windows 7: выше также отключает (но не удаляет) пункт «Закрыть» в раскрывающемся меню «Система». Сама кнопка Закрыть отключена (выглядит серой), но не удалена. Этот прием не работает для элемента / кнопки «Свернуть / Развернуть» - я подозреваю, что WPF снова их активирует.

3
Отключение кнопки лучше, чем просто ее удаление, она сохраняет ощущение, давая пользователю понять, что выполняется важная операция.
Роберт Бейкер

10

Я пытался ответить Вячеславу, так как мне нравится идея не удалять кнопку, а отключать ее, но по какой-то причине она не всегда работала: кнопка закрытия все еще была включена, но никаких ошибок вообще не было.

С другой стороны, это всегда работало (проверка ошибок пропущена):

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

1
Отлично! Добавлен в качестве Windowметода расширения в моем проекте.
Мэтт Дэвис

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

4
Это также скрывает кнопки макс / мин
Голосование Кофе

3
Он удаляет всю строку заголовка, делая окно безобразным и без описания. Подход к дробовику и двойной ответ. Downvote.
vapcguy

Это лучшее решение для приложений киоска, которые всегда нуждаются в максимальном увеличении и не должны позволять клиентам закрывать приложение. So UpVote
Раджон Тандукар,

8

Я просто добавляю свою реализацию ответа Джо Уайта используя поведение интерактивности (вам нужно сослаться на 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>

2

Позвольте пользователю "закрыть" окно, но на самом деле просто скрыть его.

В событии OnClosing окна скройте окно, если оно уже видно:

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

Каждый раз, когда должен выполняться фоновый поток, повторно отображайте фоновое окно пользовательского интерфейса:

    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

1

Итак, в значительной степени здесь ваша проблема. Кнопка закрытия в правом верхнем углу оконной рамы не является частью окна WPF, но она принадлежит той части оконной рамы, которая контролируется вашей ОС. Это означает, что для этого вам понадобится взаимодействие с Win32.

В качестве альтернативы, вы можете использовать noframe и предоставить свой собственный «фрейм» или вообще не иметь фрейма.


1

Ниже приведено отключение кнопок закрытия и максимизации / минимизации, на самом деле кнопки не удаляются (но удаляются элементы меню!). Кнопки в строке заголовка отображаются в отключенном / сером состоянии. (Я не совсем готов взять на себя всю функциональность сам ^^)

Это немного отличается от решения Virgoss тем, что оно удаляет пункты меню (и конечный разделитель, если необходимо), а не просто отключает их. Он отличается от решения Joe Whites, поскольку не отключает все системное меню, поэтому в моем случае я могу держать кнопку и значок «Свернуть».

Код последующего также поддерживает отключение Maximize / Minimize кнопки , как, в отличие от кнопки Закрыть, удаление записи из меню не вызывает систему для отображения кнопки «отключены» , даже если удаление пунктов меню делает отключение функциональных кнопок.

Меня устраивает. 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);
            }
        }
    }

Использование: Это должно быть сделано ПОСЛЕ инициализации источника. Хорошее место - использовать событие 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, проще всего подключить событие отмены и использовать команду установки флага, когда вы действительно хотите закрыть окно.


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 В этой теме показывается, как это сделать, но вы должны применить свой собственный стиль к системному меню и показать, как вы можете это сделать.


по какой-то причине «должно работать» просто отображалось, но теперь произошли обновления
TStamper

3
Я говорю о состоянии окна, которое находится в строке заголовка. Это похоже на редактирование простой кнопки.
Майкл Хедгпет

@TStamper, как мне использовать твой фрагмент? Я использую глобальный стиль окна (и шаблон).
Шимми Вайцхандлер

@ Шимми, на кого ты ссылаешься?
TStamper

0

Попробуйте добавить событие закрытия в окно. Добавьте этот код в обработчик событий.

e.Cancel = true;

Это предотвратит закрытие окна. Это имеет тот же эффект, что и скрытие кнопки закрытия.


1
«Это имеет тот же эффект, что и скрытие кнопки закрытия». за исключением того, что кнопка все еще видима и активна, то есть она анимирована и визуально нажимает при нажатии - что не поддается POLA .
rory.ap

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

    }
}

0

Это не скрывает кнопку, но предотвратит продвижение пользователя, закрыв окно.

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

-1

свойства окна goto set

window style = none;

ты не получишь кнопки закрытия ...


Downvote. Это на самом деле WindowStyle = "None"- следите за своим синтаксисом. С другой стороны, это подход с использованием дробовика, который также удаляет строку заголовка, делая коробку уродливой и не имеющей заголовка, когда есть намного более совершенные способы справиться с этим (о чем свидетельствуют другие ответы), и является дублирующим ответом.
vapcguy

-1

Как указано в других ответах, вы можете использовать WindowStyle="None" для удаления строки заголовка в целом.

И, как указано в комментариях к этим другим ответам, это предотвращает перетаскивание окна, поэтому его трудно переместить из исходного положения.

Однако вы можете преодолеть это, добавив одну строчку кода в конструктор в файле Code Behind окна:

MouseDown += delegate { DragMove(); };

Или, если вы предпочитаете лямбда-синтаксис:

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

Это делает все окно перетаскиваемым. Любые интерактивные элементы управления, присутствующие в окне, такие как кнопки, по-прежнему будут работать в обычном режиме и не будут действовать как дескрипторы перетаскивания для окна.


Все еще плохая идея. Он удаляет всю строку заголовка, делая это подходом для дробовика, и делает коробку неприглядной и означает, что для нее нет названия / описания. Есть намного лучшие альтернативы.
vapcguy

@vapcguy Удаляет всю строку заголовка. Это подход дробовика. Делает ли коробка выглядеть безобразно? Ваше мнение. Намного лучшие альтернативы? Возможно, для вас. Не для всех. :-)
Холф

-1

После долгих поисков ответа на этот вопрос я разработал это простое решение, которым я поделюсь здесь в надежде, что оно поможет другим.

Я поставил WindowStyle=0x10000000.

Это устанавливает WS_VISIBLE (0x10000000)и WS_OVERLAPPED (0x0)значения для стиля окна. «Перекрытый» является необходимым значением для отображения строки заголовка и границы окна. Удалив WS_MINIMIZEBOX (0x20000), WS_MAXIMIZEBOX (0x10000)и WS_SYSMENU (0x80000)значение из моего значения стиля, все кнопки из заголовка были удалены, в том числе кнопки Закрыть.


В WPF WindowStyleесть перечисление, значения которого не совпадают с константами Windows API; Приведение значения к WindowStyleперечислению не будет работать. Чтобы быть уверенным, я проверил исходный код .NET в ILSpy; значение enum транслируется в Windows API в закрытой функции CreateWindowStyle, и если функция встречает неизвестное WindowStyleзначение, оно просто применяется WindowStyle.None. (Единственный способ состоит в том, чтобы использовать внутренние свойства _Styleи _StyleExиспользовать отражение, против чего я настоятельно рекомендую.)
Майк Рософт,


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.