[C#] WPF 창에서 닫기 버튼을 숨기는 방법?

WPF에서 모달 대화 상자를 작성 중입니다. 닫기 버튼이 없도록 WPF 창을 어떻게 설정합니까? 나는 여전히 WindowState일반적인 제목 표시 줄을 갖고 싶습니다 .

내가 발견 ResizeMode, WindowState그리고 WindowStyle하지만 이러한 속성 중 어느 것도 나를 닫기 버튼을 숨길 수 없지만 모달 대화 상자에서 같은 제목 표시 줄을 보여줍니다.



답변

WPF에는 제목 표시 줄의 닫기 단추를 숨길 수있는 기본 제공 속성이 없지만 몇 줄의 P / Invoke를 사용하여 수행 할 수 있습니다.

먼저 다음 선언을 Window 클래스에 추가하십시오.

private const int GWL_STYLE = -16;
private const int WS_SYSMENU = 0x80000;
[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

그런 다음이 코드를 Window Loaded이벤트 에 넣으십시오 .

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

더 이상 닫기 버튼이 없습니다. 또한 제목 표시 줄 왼쪽에 창 아이콘이 없으므로 제목 표시 줄을 마우스 오른쪽 버튼으로 클릭해도 시스템 메뉴가 없습니다.

참고 Alt+ F4것이다 여전히 창을 닫습니다. 백그라운드 스레드가 완료되기 전에 창을 닫지 않으려면 Gabe가 제안한대로 재정의 OnClosing하고 Canceltrue로 설정할 수도 있습니다 .


답변

방금 비슷한 문제가 발생하여 Joe White의 솔루션 이 간단하고 깨끗해 보입니다. 재사용하고 Window의 연결된 속성으로 정의했습니다.

public class WindowBehavior
{
    private static readonly Type OwnerType = typeof (WindowBehavior);

    #region HideCloseButton (attached property)

    public static readonly DependencyProperty HideCloseButtonProperty =
        DependencyProperty.RegisterAttached(
            "HideCloseButton",
            typeof (bool),
            OwnerType,
            new FrameworkPropertyMetadata(false, new PropertyChangedCallback(HideCloseButtonChangedCallback)));

    [AttachedPropertyBrowsableForType(typeof(Window))]
    public static bool GetHideCloseButton(Window obj) {
        return (bool)obj.GetValue(HideCloseButtonProperty);
    }

    [AttachedPropertyBrowsableForType(typeof(Window))]
    public static void SetHideCloseButton(Window obj, bool value) {
        obj.SetValue(HideCloseButtonProperty, value);
    }

    private static void HideCloseButtonChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var window = d as Window;
        if (window == null) return;

        var hideCloseButton = (bool)e.NewValue;
        if (hideCloseButton && !GetIsHiddenCloseButton(window)) {
            if (!window.IsLoaded) {
                window.Loaded += HideWhenLoadedDelegate;
            }
            else {
                HideCloseButton(window);
            }
            SetIsHiddenCloseButton(window, true);
        }
        else if (!hideCloseButton && GetIsHiddenCloseButton(window)) {
            if (!window.IsLoaded) {
                window.Loaded -= ShowWhenLoadedDelegate;
            }
            else {
                ShowCloseButton(window);
            }
            SetIsHiddenCloseButton(window, false);
        }
    }

    #region Win32 imports

    private const int GWL_STYLE = -16;
    private const int WS_SYSMENU = 0x80000;
    [DllImport("user32.dll", SetLastError = true)]
    private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
    [DllImport("user32.dll")]
    private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

    #endregion

    private static readonly RoutedEventHandler HideWhenLoadedDelegate = (sender, args) => {
        if (sender is Window == false) return;
        var w = (Window)sender;
        HideCloseButton(w);
        w.Loaded -= HideWhenLoadedDelegate;
    };

    private static readonly RoutedEventHandler ShowWhenLoadedDelegate = (sender, args) => {
        if (sender is Window == false) return;
        var w = (Window)sender;
        ShowCloseButton(w);
        w.Loaded -= ShowWhenLoadedDelegate;
    };

    private static void HideCloseButton(Window w) {
        var hwnd = new WindowInteropHelper(w).Handle;
        SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU);
    }

    private static void ShowCloseButton(Window w) {
        var hwnd = new WindowInteropHelper(w).Handle;
        SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | WS_SYSMENU);
    }

    #endregion

    #region IsHiddenCloseButton (readonly attached property)

    private static readonly DependencyPropertyKey IsHiddenCloseButtonKey =
        DependencyProperty.RegisterAttachedReadOnly(
            "IsHiddenCloseButton",
            typeof (bool),
            OwnerType,
            new FrameworkPropertyMetadata(false));

    public static readonly DependencyProperty IsHiddenCloseButtonProperty =
        IsHiddenCloseButtonKey.DependencyProperty;

    [AttachedPropertyBrowsableForType(typeof(Window))]
    public static bool GetIsHiddenCloseButton(Window obj) {
        return (bool)obj.GetValue(IsHiddenCloseButtonProperty);
    }

    private static void SetIsHiddenCloseButton(Window obj, bool value) {
        obj.SetValue(IsHiddenCloseButtonKey, value);
    }

    #endregion

}

그런 다음 XAML에서 다음과 같이 설정했습니다.

<Window
    x:Class="WafClient.Presentation.Views.SampleWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:u="clr-namespace:WafClient.Presentation.Behaviors"
    ResizeMode="NoResize"
    u:WindowBehavior.HideCloseButton="True">
    ...
</Window>


답변

WindowStyle속성을 없음으로 설정 하면 제목 표시 줄과 함께 컨트롤 상자가 숨겨집니다. 전화를 걸 필요가 없습니다.


답변

이것은 닫기 버튼을 제거하지는 않지만 누군가가 창을 닫는 것을 막을 것입니다.

이것을 코드 뒤에 파일 뒤에 넣으십시오.

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


답변

닫기 버튼을 비활성화하려면 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();


답변

나는 버튼을 제거하지 않고 비활성화하는 아이디어를 좋아했기 때문에 Viachaslau의 대답을 시도했지만 어떤 이유로 든 항상 작동하지는 않았습니다. 닫기 버튼은 여전히 ​​활성화되었지만 오류는 없습니다.

반면에 이것은 항상 작동했습니다 (오류 검사 생략).

[DllImport( "user32.dll" )]
private static extern IntPtr GetSystemMenu( IntPtr hWnd, bool bRevert );
[DllImport( "user32.dll" )]
private static extern bool EnableMenuItem( IntPtr hMenu, uint uIDEnableItem, uint uEnable );

private const uint MF_BYCOMMAND = 0x00000000;
private const uint MF_GRAYED = 0x00000001;
private const uint SC_CLOSE = 0xF060;
private const int WM_SHOWWINDOW = 0x00000018;

protected override void OnSourceInitialized( EventArgs e )
{
  base.OnSourceInitialized( e );
  var hWnd = new WindowInteropHelper( this );
  var sysMenu = GetSystemMenu( hWnd.Handle, false );
  EnableMenuItem( sysMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED );
}


답변

설정할 속성은 =>입니다. 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">