Làm thế nào để ẩn nút đóng trong cửa sổ WPF?


204

Tôi đang viết một hộp thoại phương thức trong WPF. Làm cách nào để đặt cửa sổ WPF không có nút đóng? Tôi vẫn muốn nó WindowStatecó một thanh tiêu đề bình thường.

Tôi đã tìm thấy ResizeMode, WindowStateWindowStyle, nhưng không có thuộc tính nào trong số đó cho phép tôi ẩn nút đóng nhưng hiển thị thanh tiêu đề, như trong các hộp thoại phương thức.


9
Đó là hộp thoại tiến trình chạy một luồng nền không hỗ trợ hủy; Tôi đoán tôi chỉ đang cố gắng để làm điều đó vì vậy tôi không phải hỗ trợ hủy bỏ (chưa). Bạn có lẽ đúng, mặc dù.
Michael Hedgpeth

1
Tôi cũng ghét các ứng dụng cố gắng loại bỏ chrome cửa sổ. Nếu tôi thực hiện hộp thoại tiến trình, tôi luôn làm cho nút Đóng cửa sổ thực hiện logic tương tự như nhấp vào nút Hủy thực tế.
Christian Hayter

13
Đối với Chris: Hãy tưởng tượng phần mềm của bạn là dành cho Giám sát video. Một nhân viên bảo mật vào ban đêm ĐÃ (đó là công việc của anh ta) để mở cửa sổ ... nhưng đôi khi công việc của họ thật nhàm chán và họ muốn lướt Internet hoặc đóng cửa sổ Video Ma trận vì bất kỳ lý do gì, loại bỏ các nút cửa sổ là cách thích hợp để làm điều đó.
Jean-Marie

7
@ChrisUpecl, "Tại sao bạn muốn làm điều này? Nó gây ấn tượng với tôi là thiết kế UI thực sự tệ hại." - thực sự "thiết kế UI tệ hại" là khi một chương trình trình bày một hộp thoại với OK ; Hủy bỏĐóng nút. Đối với người dùng, có thể không rõ ràng những gì Đóng làm. Nó hủy bỏ hoặc gửi ? Đồng thuận là không bao gồm các nút đóng trong các hộp thoại vì vậy có
MickyD

1
@ Jean-Marie Nhưng việc ẩn nút đóng không ngăn điều đó xảy ra, nó chỉ đánh lừa những người không hiểu biết và lười biếng (với Google). Ẩn nút đóng chỉ ngăn việc nhấp vào nút đó. Các tổ hợp win key và alt key vẫn sẽ hoạt động như bình thường Cách "đúng" để làm điều đó là tạo một tài khoản người dùng cho công nhân, với chính sách nhóm ngăn họ mở / cài đặt bất kỳ phần mềm nào ngoài những gì được phê duyệt. tài khoản quản trị viên, người giám sát có quyền truy cập, để xử lý bất kỳ bảo trì nào.
Digital_Utopia

Câu trả lời:


275

WPF không có thuộc tính tích hợp để ẩn nút Đóng của thanh tiêu đề, nhưng bạn có thể làm điều đó với một vài dòng P / Gọi.

Đầu tiên, thêm các khai báo này vào lớp Window của bạn:

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

Sau đó đặt mã này vào Loadedsự kiện của Window :

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

Và ở đó bạn đi: không có nút Đóng nữa. Bạn cũng sẽ không có biểu tượng cửa sổ ở bên trái của thanh tiêu đề, có nghĩa là không có menu hệ thống, ngay cả khi bạn nhấp chuột phải vào thanh tiêu đề - tất cả chúng đều đi cùng nhau.

Lưu ý rằng Alt+ F4vẫn sẽ đóng Cửa sổ. Nếu bạn không muốn cho phép cửa sổ đóng trước khi hoàn thành luồng nền, thì bạn cũng có thể ghi đè OnClosingvà đặt Cancelthành đúng, như Gabe đề xuất.


5
Theo các tài liệu chúng ta nên sử dụng SetWindowLongPtrthay thế.
Jonathan Allen

15
Chủ yếu là một ghi chú cho bản thân ... Không gian tên của DLLImport -> System.R nb.InteropService.DllImport. Không gian tên của WindowInteropHelper -> System.Windows.Interop.WindowInteropHelper
doobop

3
Trên thực tế, phương pháp này ẩn tất cả ba nút (Tối thiểu, Tối đa và Đóng). Có thể chỉ ẩn nút Đóng?
newman

4
@miliu, không. Bạn có thể vô hiệu hóa nó , nhưng bạn cũng không thể ẩn nó mà không ẩn Thu nhỏ / Tối đa hóa. Tôi nghi ngờ các nhà phát triển Windows nghĩ rằng nó sẽ gây nhầm lẫn nếu Tối đa hóa ở bên phải nơi thường đóng.
Joe White

3
Đặt WindowStyle = "Không" trên thẻ Window của bạn trong tệp XAML.
diegodsp

88

Tôi chỉ gặp vấn đề tương tự và giải pháp của Joe White có vẻ đơn giản và gọn gàng. Tôi đã sử dụng lại và định nghĩa nó là một thuộc tính đính kèm của 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

}

Sau đó, trong XAML, bạn chỉ cần đặt nó như thế này:

<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

Đặt thuộc WindowStyletính thành Không có sẽ ẩn hộp điều khiển cùng với thanh tiêu đề. Không cần phải gọi hạt nhân.


20
Vâng, điều này sẽ ẩn thanh tiêu đề cửa sổ hoàn toàn. Điều đó có nghĩa là bạn không nhận được tiêu đề cửa sổ và người dùng sẽ không thể di chuyển cửa sổ.
newman

6
Bạn có thể làm cho cửa sổ có thể di chuyển bằng cách thêm this.DragMove();vào MouseDownsự kiện của cửa sổ
paul

1
Đối với một hộp thoại phương thức nên hoàn toàn là thông tin và bắt buộc, như tiến trình nâng cấp cơ sở dữ liệu với một lược đồ cũ đã được mở, giải pháp này là hoàn hảo.
Bộ giải mã cô đơn

1
Tuy nhiên, tôi nghĩ rằng một số người muốn có đường viền
pjdupreez

2
Chắc chắn là giải pháp tốt nhất. Không có vấn đề với việc thêm đường viền vào bảng điều khiển hoặc thực hiện di chuyển.
buks

50

Điều này sẽ không thoát khỏi nút đóng, nhưng nó sẽ ngăn ai đó đóng cửa sổ.

Đặt mã này trong mã của bạn đằng sau tập tin:

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

7
Xin lưu ý rằng thực hiện việc này trong một Windowhộp thoại được thiết lập dưới dạng hộp thoại phương thức sẽ can thiệp vào Windowcài đặt thuộc tính của nó DialogResultvà có thể làm cho nó không sử dụng được. stackoverflow.com/questions/898708/cant-set-dialogresult-in-wpf
Sheridan

4
Tôi đã nhận được một tràn bằng cách sử dụng phương pháp này, tôi đã lấy ra cơ sở. OnClose (e) và sau đó nó đã hoạt động
jacobsgriffith

8
Là người dùng, tôi sẽ ghét lập trình viên đưa ứng dụng này vào ứng dụng của họ
UrbanEsc

2
@UrbanEsc Tôi có xu hướng đồng ý rằng đó là một điều khó chịu phải làm, nhưng khi tôi làm điều này - và đó chỉ là một lần duy nhất - đó là một yêu cầu bắt buộc, và đó là một điều ác cần thiết, có một quá trình rất quan trọng đang diễn ra điều đó không thể bị gián đoạn và ứng dụng không thể tiến hành cho đến khi hoàn thành. Có nhiều cách khác có thể được thực hiện (một luồng nền, với giao diện người dùng bị vô hiệu hóa cho đến khi sẵn sàng) nhưng cả ông chủ và khách hàng đều thích nó theo cách này vì nó nhấn mạnh vào mức độ nghiêm trọng của quy trình.
flurbius

15

Để tắt nút đóng, bạn nên thêm mã sau vào lớp Window của mình (mã được lấy từ đây , chỉnh sửa và định dạng lại một chút):

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

Mã này cũng vô hiệu hóa mục đóng trong menu Hệ thống và không cho phép đóng hộp thoại bằng Alt + F4.

Bạn có thể sẽ muốn đóng cửa sổ lập trình. Chỉ gọi Close()sẽ không hoạt động. Làm một cái gì đó như thế này:

allowClosing = true;
Close();

Trong Windows 7: Ở trên cũng vô hiệu hóa (nhưng không xóa) mục Đóng trong menu Hệ thống thả xuống. Nút Đóng tự tắt (trông màu xám), nhưng không được gỡ bỏ. Thủ thuật này không hoạt động đối với nút / Tối thiểu hóa mục / Tối đa hóa - Tôi nghi ngờ WPF kích hoạt lại chúng.

3
Vô hiệu hóa nút tốt hơn là chỉ loại bỏ chúng, nó giữ một cảm giác nhất quán trong khi cho người dùng biết rằng một hoạt động quan trọng đang chạy.
Robert Baker

10

Tôi đã thử trả lời Viachaslau vì tôi thích ý tưởng không tháo nút mà vô hiệu hóa nó, nhưng vì một số lý do không phải lúc nào nó cũng hoạt động: nút đóng vẫn được bật nhưng không có lỗi gì.

Mặt khác, điều này luôn hoạt động (kiểm tra lỗi được bỏ qua):

[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
Hoàn hảo! Đã thêm như một Windowphương thức mở rộng trong dự án của tôi.
Matt Davis

8

Thuộc tính cần đặt là => 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
Điều này cũng ẩn các nút tối đa / phút
VoteCoffee

3
Nó loại bỏ toàn bộ thanh tiêu đề, làm cho hộp xấu xí và không có mô tả. Cách tiếp cận shotgun và một câu trả lời trùng lặp. Downvote.
vapcguy

Đây là giải pháp tốt nhất cho các ứng dụng kiosk luôn cần ứng dụng của nó được tối đa hóa và không cho phép khách hàng đóng ứng dụng. Vì vậy, UpVote
Rajon Tanducar

8

Tôi chỉ cần thêm cách triển khai câu trả lời của Joe White bằng Hành vi Tương tác (bạn cần tham khảo System.Windows.Interactivity).

mã:

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

sử dụng:

<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

Hãy để người dùng "đóng" cửa sổ nhưng thực sự chỉ cần ẩn nó.

Trong sự kiện OnClose của cửa sổ, ẩn cửa sổ nếu đã hiển thị:

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

Mỗi khi chủ đề nền được thực thi, hiển thị lại cửa sổ UI nền:

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

Khi chấm dứt thực thi chương trình, đảm bảo tất cả các cửa sổ được / có thể đóng:

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

Vì vậy, khá nhiều ở đây là vấn đề của bạn. Nút đóng ở phía trên bên phải của khung cửa sổ không phải là một phần của cửa sổ WPF, nhưng nó thuộc về một phần của khung cửa sổ được điều khiển bởi HĐH của bạn. Điều này có nghĩa là bạn sẽ phải sử dụng Win32 interop để làm điều đó.

cách khác, bạn có thể sử dụng noframe và cung cấp "khung" của riêng bạn hoặc không có khung nào cả.


1

Sau đây là về việc vô hiệu hóa các nút đóng và Tối đa hóa / Thu nhỏ, nó không thực sự loại bỏ các nút (nhưng nó sẽ loại bỏ các mục menu!). Các nút trên thanh tiêu đề được vẽ ở trạng thái tắt / xám. (Tôi chưa sẵn sàng để tự mình đảm nhận tất cả các chức năng ^^)

Điều này hơi khác so với giải pháp Virgoss ở chỗ nó loại bỏ các mục menu (và dấu phân cách, nếu cần) thay vì chỉ vô hiệu hóa chúng. Nó khác với giải pháp Joe Whites vì ​​nó không vô hiệu hóa toàn bộ menu hệ thống và vì vậy, trong trường hợp của tôi, tôi có thể giữ xung quanh nút Thu nhỏ và biểu tượng.

Các mã sau cũng hỗ trợ việc vô hiệu hóa Tối đa hóa / Giảm thiểu các nút như, không giống như các nút Close, loại bỏ các mục từ menu không làm cho hệ thống làm cho nút "tàn tật" mặc dù loại bỏ các mục trình đơn không vô hiệu hóa chức năng của các nút.

Nó làm việc cho tôi. 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);
            }
        }
    }

Cách sử dụng: Điều này phải được thực hiện SAU khi nguồn được khởi tạo. Một nơi tốt là sử dụng sự kiện SourceInitialized của 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
}

Để vô hiệu hóa chức năng Alt + F4, phương pháp đơn giản chỉ là kết nối sự kiện Hủy và sử dụng đặt cờ khi bạn thực sự muốn đóng cửa sổ.


0

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

nên làm việc

Chỉnh sửa - ngay lập tức Chủ đề này cho thấy cách thực hiện điều đó nhưng tôi không nghĩ Window có một tài sản để có được những gì bạn muốn mà không mất thanh tiêu đề bình thường.

Chỉnh sửa 2 Chủ đề này cho thấy một cách để nó được thực hiện, nhưng bạn phải áp dụng phong cách của riêng bạn vào menu hệ thống và nó cho thấy cách bạn có thể làm điều đó.


vì một số lý do "nên hoạt động" vừa được hiển thị, nhưng hiện tại đã cập nhật
TStamper

3
Tôi đang nói về trạng thái Window, trong thanh tiêu đề. Điều này trông giống như chỉnh sửa một nút đơn giản.
Michael Hedgpeth

@TStamper, làm cách nào để sử dụng đoạn trích của bạn? Tôi đang sử dụng kiểu Cửa sổ toàn cầu (và mẫu).
Shimmy Weitzhandler

@ Shimmy- bạn đang đề cập đến cái nào?
TStamper

0

Hãy thử thêm một sự kiện kết thúc vào cửa sổ. Thêm mã này vào xử lý sự kiện.

e.Cancel = true;

Điều này sẽ ngăn cửa sổ đóng lại. Điều này có tác dụng tương tự như ẩn nút đóng.


1
"Điều này có tác dụng tương tự như ẩn nút đóng." ngoại trừ nút vẫn có thể nhìn thấy và có thể nhấp, nghĩa là nó hoạt hình và ấn xuống trực quan khi bạn nhấp vào nút - điều này bất chấp Pola .
rory.ap

0

Sử dụng cái này, được sửa đổi từ 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

Điều này không ẩn nút nhưng sẽ ngăn người dùng di chuyển về phía trước bằng cách tắt cửa sổ.

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

-1

thuộc tính cửa sổ goto

window style = none;

bạn sẽ không nhận được các nút đóng ...


Downvote. Đó thực sự là WindowStyle = "None"- xem cú pháp của bạn. Đối với một cách khác, đó là một cách tiếp cận shotgun cũng loại bỏ thanh tiêu đề, làm cho hộp trở nên xấu xí và thiếu tiêu đề, khi có rất nhiều cách tốt hơn để xử lý điều này (bằng chứng là các câu trả lời khác), và là một câu trả lời trùng lặp.
vapcguy

-1

Như đã nêu trong các câu trả lời khác, bạn có thể sử dụng WindowStyle="None"để loại bỏ hoàn toàn Thanh tiêu đề.

Và, như đã nêu trong các bình luận cho những câu trả lời khác, điều này ngăn cửa sổ không thể kéo được nên khó di chuyển nó khỏi vị trí ban đầu.

Tuy nhiên, bạn có thể khắc phục điều này bằng cách thêm một dòng mã vào Trình xây dựng trong tệp Mã phía sau của Window:

MouseDown += delegate { DragMove(); };

Hoặc, nếu bạn thích Cú pháp Lambda:

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

Điều này làm cho toàn bộ Cửa sổ có thể kéo được. Bất kỳ điều khiển tương tác nào có trong Cửa sổ, như Nút, vẫn sẽ hoạt động như bình thường và sẽ không hoạt động như tay cầm kéo cho Cửa sổ.


Vẫn là một ý tưởng tồi. Nó loại bỏ toàn bộ thanh tiêu đề, làm cho nó trở thành một cách tiếp cận shotgun và làm cho hộp trông xấu xí và có nghĩa là không có tiêu đề / mô tả cho nó. Có nhiều lựa chọn thay thế tốt hơn.
vapcguy

@vapcguy Nó xóa toàn bộ thanh tiêu đề. Đó là một cách tiếp cận shotgun. Làm cho hộp trông xấu xí? Ý kiến ​​của bạn. Lựa chọn thay thế tốt hơn nhiều? Đối với bạn, có lẽ. Không phải cho tất cả mọi người. :-)
Holf

-1

Sau nhiều tìm kiếm cho câu trả lời cho điều này, tôi đã tìm ra giải pháp đơn giản này mà tôi sẽ chia sẻ ở đây với hy vọng nó sẽ giúp ích cho người khác.

Tôi đặt WindowStyle=0x10000000.

Cái này đặt WS_VISIBLE (0x10000000)WS_OVERLAPPED (0x0)các giá trị cho Window Style. "Chồng chéo" là giá trị cần thiết để hiển thị thanh tiêu đề và viền cửa sổ. Bằng cách loại bỏ các WS_MINIMIZEBOX (0x20000), WS_MAXIMIZEBOX (0x10000)WS_SYSMENU (0x80000)các giá trị từ giá trị phong cách của tôi, tất cả các nút trên thanh tiêu đề đã được gỡ bỏ, bao gồm nút Close.


Trong WPF WindowStylelà một phép liệt kê có các giá trị không khớp với các hằng số API của Windows; ép buộc giá trị WindowStyleliệt kê sẽ không hoạt động. Để chắc chắn, tôi đã kiểm tra mã nguồn .NET trong ILSpy; giá trị enum được dịch sang API Windows trong hàm riêng CreateWindowStylevà nếu hàm gặp một WindowStylegiá trị không xác định , nó chỉ đơn giản được áp dụng WindowStyle.None. (Cách duy nhất là sử dụng các thuộc tính bên trong _Style_StyleExsử dụng sự phản chiếu, điều mà tôi đặc biệt khuyên bạn nên chống lại.)
Mike Rosoft


-2

Nếu nhu cầu chỉ là cấm người dùng đóng cửa sổ, đây là một giải pháp đơn giản.

Mã XAML: IsCloseButtonEnabled="False"

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.