Як приховати кнопку закриття у вікні WPF?


204

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

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


9
Це діалог прогресу, який виконує фоновий потік, який не підтримує скасування; Я думаю, що я просто намагаюся зробити це, щоб мені не потрібно підтримувати скасування (поки). Ти, мабуть, маєш рацію.
Майкл Хедгпет

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

13
Для Кріса: Давайте уявимо, що ваше програмне забезпечення призначене для відеоспостереження. Агент безпеки протягом ночі ВІДПОВІДАЄ (це його робота) тримати вікна відкритими ... але іноді їх робота нудна, і вони хочуть переглядати Інтернет або закривати вікна відеоматриць з будь-якої причини, видалення кнопок Windows - це правильний спосіб зробити це.
Жан-Марі

7
@ChrisUpchurch: "Чому ти хочеш це робити? Мене це вражає як справді паршивий дизайн інтерфейсу". - Дійсно "паршивий дизайн інтерфейсу" - це коли програма представляє діалогове вікно з ОК ; Кнопки скасування та закриття . Для користувача може бути не очевидно, що робить Close . Він скасовує чи подає ? Консенсус не включати кнопки закриття в діалогові вікна, так що це
MickyD

1
@ Жан-Марі Але ховання кнопки закриття не заважає цього статися, вона лише дурить неінформованих і ледачих (для Google). Приховування кнопки закриття лише запобігає натисканню на неї. Комбінації клавіш Win та комбінації клавіш alt все одно працюватимуть як звичайний. "Правильним" способом зробити це - створити обліковий запис користувача для працівників із груповою політикою, яка не дозволяє їм відкривати / встановлювати будь-яке програмне забезпечення, окрім затвердженого. акаунт адміністратора, до якого наглядачі мають доступ, щоб обробляти будь-яке обслуговування.
Digital_Utopia

Відповіді:


275

У 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
Насправді цей підхід приховує всі три кнопки (Min, Max і Close). Чи можливо просто приховати кнопку Закрити?
новачок

4
@miliu, nope. Ви можете відключити його , але ви не можете його приховати, не ховаючи також Згорнути / Максимізувати. Я підозрюю, що розробники Windows вважають, що це буде заплутано, якщо Maximize знаходиться праворуч там, де зазвичай знаходиться Close.
Джо Уайт

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

88

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

62

Встановіть WindowStyleвластивість None, що приховатиме поле керування разом із заголовком. Не потрібно дзвонити в ядро.


20
Ну, це повністю приховає заголовок вікна. Це означає, що ви не отримаєте назву вікна, і користувач не зможе перемістити вікно.
новачок

6
Ви можете зробити вікно переміщуваного шляхом додавання 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), а потім це спрацювало
jacobsgriffith

8
Як користувач, я ненавиджу програміста, який вклав це у свою програму
UrbanEsc

2
@UrbanEsc Я схильний би погодитися, що це дратівлива річ робити, але коли я це зробив - і це було лише один раз - це була обов'язкова вимога, і це було необхідне зло, відбувався якийсь дуже важливий процес це не вдалося перервати, і додаток не міг продовжувати роботу, поки це не було зроблено. Були й інші способи (фонова нитка, користувальницький інтерфейс відключений до готовності), але босу і клієнту це подобалося саме так, оскільки це підкреслювало серйозність процесу.
flurbius

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
Тут також ховаються кнопки max / min
VoteCoffee

3
Це видаляє весь рядок заголовка, робить поле некрасивим і без опису. Підхід рушниці та дублююча відповідь. Downvote.
vapcguy

Це найкраще рішення для кіоскових додатків, які завжди потребують максимізації його застосування та не повинні дозволяти клієнтам закривати додаток. Так 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 тим, що воно видаляє пункти меню (і розділовий механізм, якщо це потрібно), а не просто вимикає їх. Він відрізняється від рішення Джо Уайтса тим, що не вимикає все системне меню, тому в моєму випадку я можу тримати навколо кнопки та піктограми мінімізації.

Код подальшого також підтримує відключення 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:

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
Я зараз говорю про стан Window, який знаходиться в заголовку. Це виглядає як редагування простої кнопки.
Майкл Хедгпет

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

@ Shimmy- про кого ти йдеш?
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

window style = none;

ти не хочеш закрити кнопки ...


Downvote. Це насправді WindowStyle = "None"- спостерігайте за своїм синтаксисом. Для іншого - це підхід рушниці, який також видаляє заголовок, роблячи поле некрасивим і не має заголовка, коли існує стільки набагато кращих способів впоратися з цим (про що свідчать інші відповіді), і є дублюючою відповіддю.
vapcguy

-1

Як зазначено в інших відповідях, ви можете WindowStyle="None"повністю видалити рядок заголовків.

І, як зазначено в коментарях до цих інших відповідей, це запобігає перетягуванню вікна, тому важко перемістити його з початкового положення.

Однак ви можете подолати це, додавши один рядок коду до конструктора у файлі «Код вікна» за файлом:

MouseDown += delegate { DragMove(); };

Або, якщо ви віддаєте перевагу синтаксис Lambda:

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- це перерахунок, значення якого не відповідають константам API API; примусити значення до WindowStyleперерахування не вийде. Щоб переконатися, я перевірив вихідний код .NET в ILSpy; значення enum переводиться в API Windows в приватній функції CreateWindowStyle, і якщо функція зустрічається з невідомим WindowStyleзначенням, вона просто застосовується WindowStyle.None. (Єдиним способом було б використання внутрішніх властивостей _Styleта _StyleExвикористання рефлексії, проти чого я настійно рекомендую.)
Майк Рософт


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.