programing

WPF 창에서 닫기 단추를 숨기는 방법은 무엇입니까?

topblog 2023. 5. 23. 21:19
반응형

WPF 창에서 닫기 단추를 숨기는 방법은 무엇입니까?

저는 WPF로 모달 대화를 쓰고 있습니다.WPF 창에 닫기 단추가 없도록 설정하려면 어떻게 해야 합니까?의 그도갖싶어요고래▁▁for를 원합니다.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);

다음 이 의 그다이코창넣에습다니에 넣습니다.Loaded 이벤트:

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

여기 있습니다. 닫기 버튼이 없습니다.또한 제목 표시줄 왼쪽에는 창 아이콘이 없으므로 제목 표시줄을 마우스 오른쪽 단추로 클릭해도 시스템 메뉴가 없습니다. 모두 함께 사용할 수 있습니다.

중요한 참고: 이 모든 것은 버튼을 숨기는 것입니다.사용자는 여전히 창을 닫을 수 있습니다!사용자가 F4+를 누르거나 작업 표시줄을 통해 앱을 닫더라도 창은 계속 닫힙니다.

백그라운드 스레드가 완료되기 전에 창이 닫히는 것을 허용하지 않으려면 다음을 재정의할 수도 있습니다.OnClosing 트세를 합니다.Cancel게이브가 제안한 것처럼 사실입니다.

저는 방금 비슷한 문제에 도달했고 조 화이트의 해결책은 단순하고 깨끗해 보입니다.재사용하여 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();

저는 버튼을 제거하지 않고 비활성화하는 아이디어가 마음에 들기 때문에 비아차슬라우의 답변을 시도했지만, 어떤 이유에서인지 항상 작동하지는 않았습니다. 닫기 버튼은 여전히 활성화되었지만 오류는 전혀 없었습니다.

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

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

저는 상호작용 행동을 사용하여 Joe White의 답변 구현을 추가할 뿐입니다(시스템을 참조해야 합니다.창문들.상호작용).

코드:

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>

사용자가 창을 "닫게" 하지만 실제로는 숨깁니다.

윈도우의 OnClosing 이벤트에서 이미 표시된 경우 윈도우를 숨깁니다.

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

백그라운드 스레드를 실행할 때마다 백그라운드 UI 창을 다시 표시합니다.

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

프로그램 실행을 종료할 때는 모든 창이 닫히거나 닫힐 수 있는지 확인합니다.

Private Sub CloseAll()
    If w IsNot Nothing Then
        w.Visibility = Windows.Visibility.Collapsed ' Tell OnClosing to really close
        w.Close()
    End If
End Sub

다음은 닫기 및 최대화/최소화 단추를 비활성화하는 방법입니다. 실제로 단추를 제거하지는 않지만 메뉴 항목은 제거합니다!제목 표시줄의 단추는 비활성화/회색 상태로 그려집니다.(모든 기능을 직접 인수할 준비가 되지 않았습니다 ^^)

이는 메뉴 항목(및 필요한 경우 후행 구분 기호)을 사용하지 않도록 설정하는 대신 제거한다는 점에서 Virgoss 솔루션과 약간 다릅니다.전체 시스템 메뉴를 비활성화하지 않으므로 Joe Whites 솔루션과는 다릅니다. 따라서 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 기능을 비활성화하려면 Canceling 이벤트를 연결하고 창을 닫고 싶을 때 플래그를 설정하는 것이 좋습니다.

DllImports 및 P/Invoke 호출 없이 사용자 지정 스타일을 사용하여 유사한 목표를 달성한 방법은 다음과 같습니다. 다을사용기제존제표거다니합시을을 사용하여 이 제거됩니다.WindowStyle="none"제목 표시줄로 표시하기 위해 비슷한 배경색의 '텍스트 블록'을 표시합니다.

여기에 이미지 설명 입력

XAML 코드

<Window x:Class="AddBook"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:controls="http://wpftoolkit.my-libraries.com/v5" 
    WindowStartupLocation="CenterOwner"        
    ResizeMode="NoResize" 
    Style="{DynamicResource WindowStyleX}"
    ShowInTaskbar="False"
    ShowActivated="True"
    SizeToContent="Height"
    Title="Add New Book" 
    Width="450">
..............

</Window>

XAML

<Style x:Key="WindowStyleX" TargetType="{x:Type Window}">
<Setter Property="WindowStyle" Value="None" />
<Setter Property="AllowsTransparency" Value="False" />
<Setter Property="ResizeMode" Value="NoResize" />
<Setter Property="Background" Value="White" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="{x:Type Window}">
            <Border BorderBrush="{DynamicResource BlackColor}" BorderThickness="1">
                <Grid Background="{TemplateBinding Background}">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="30" />
                        <RowDefinition Height="*" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition />
                        <ColumnDefinition Width="Auto" />
                    </Grid.ColumnDefinitions>
                    <Border
                        Grid.Row="0"
                        Grid.ColumnSpan="2"
                        Background="{DynamicResource BlackColor}">
                        <Grid>
                            <TextBlock
                                Grid.Column="1"
                                Margin="10,0,0,0"
                                HorizontalAlignment="Left"
                                VerticalAlignment="Center"
                                FontSize="16"
                                Foreground="{DynamicResource WhiteTextForeground}"
                                Text="{TemplateBinding Title}" />
                        </Grid>
                    </Border>
                    <ContentPresenter Grid.Row="1" />
                </Grid>
            </Border>
        </ControlTemplate>
    </Setter.Value>
</Setter>

자, 여기 거의 여러분의 문제가 있습니다.창 프레임의 오른쪽 상단에 있는 닫기 버튼은 WPF 창에 속하지 않지만 OS에서 제어하는 창 프레임의 일부에 속합니다.이는 Win32 interop을 사용해야 한다는 것을 의미합니다.

또는 프레임을 사용하지 않고 자신의 "프레임"을 제공하거나 프레임이 아예 없을 수 있습니다.

이렇게 하면 단추가 숨겨지지는 않지만 창을 종료하여 사용자가 앞으로 이동할 수 없습니다.

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

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>

효과가 있어야 합니다.

편집 - 이 쓰레드는 이 작업을 수행하는 방법을 보여주지만 Windows에는 일반 제목 표시줄을 잃지 않고 원하는 것을 얻을 수 있는 속성이 없다고 생각합니다.

편집 2 이 스레드는 수행 방법을 보여주지만 시스템 메뉴에 자신만의 스타일을 적용해야 하며 이를 수행하는 방법을 보여줍니다.

다른 답변에 명시된 바와 같이 다음을 사용할 수 있습니다.WindowStyle="None"제목 표시줄을 모두 제거합니다.

그리고 다른 답변에 대한 의견에서 언급한 것처럼 창을 끌 수 없으므로 창을 처음 위치에서 이동하기가 어렵습니다.

그러나 창 코드 뒤에 있는 파일의 생성자에 코드 한 줄을 추가하면 이 문제를 해결할 수 있습니다.

MouseDown += delegate { DragMove(); };

또는 람다 구문을 선호하는 경우:

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

이렇게 하면 전체 창을 끌 수 있습니다.단추와 같이 창에 있는 대화형 컨트롤은 여전히 정상적으로 작동하며 창에 대한 드래그 핸들로 작동하지 않습니다.

창에 닫기 이벤트를 추가합니다.이 코드를 이벤트 처리기에 추가합니다.

e.Cancel = true;

이렇게 하면 창이 닫히지 않습니다.이는 닫기 단추를 숨기는 것과 동일한 효과가 있습니다.

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

    }
}

저는 첨부된 속성을 사용하여 행동을 중재하는 이 답변을 매우 좋아합니다.하지만 답변의 구현이 지나치게 복잡하다는 F4것을 알게 되었고, +로도 창이 닫히지 않도록 하는 2차적인 목표도 다루지 못했습니다.그래서 저는 다음과 같은 대안을 제시합니다.

enum CloseButtonVisibility
{
    Visible,
    Hidden,
    CloseDisabled,
}

static class WindowEx
{
    private static readonly CancelEventHandler _cancelCloseHandler = (sender, e) => e.Cancel = true;

    public static readonly DependencyProperty CloseButtonVisibilityProperty =
        DependencyProperty.RegisterAttached(
            "CloseButtonVisibility",
            typeof(CloseButtonVisibility),
            typeof(WindowEx),
            new FrameworkPropertyMetadata(CloseButtonVisibility.Visible, new PropertyChangedCallback(_OnCloseButtonChanged)));

    [AttachedPropertyBrowsableForType(typeof(Window))]
    public static CloseButtonVisibility GetCloseButtonVisibility(Window obj)
    {
        return (CloseButtonVisibility)obj.GetValue(CloseButtonVisibilityProperty);
    }

    [AttachedPropertyBrowsableForType(typeof(Window))]
    public static void SetCloseButtonVisibility(Window obj, CloseButtonVisibility value)
    {
        obj.SetValue(CloseButtonVisibilityProperty, value);
    }

    private static void _OnCloseButtonChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (!(d is Window window))
        {
            return;
        }

        if (e.OldValue is CloseButtonVisibility oldVisibility)
        {
            if (oldVisibility == CloseButtonVisibility.CloseDisabled)
            {
                window.Closing -= _cancelCloseHandler;
            }
        }

        if (e.NewValue is CloseButtonVisibility newVisibility)
        {
            if (newVisibility == CloseButtonVisibility.CloseDisabled)
            {
                window.Closing += _cancelCloseHandler;
            }

            if (!window.IsLoaded)
            {
                // NOTE: if the property is set multiple times before the window is loaded,
                // the window will wind up with multiple event handlers. But they will all
                // set the same value, so this is fine from a functionality point of view.
                //
                // The handler is never unsubscribed, so there is some nominal overhead there.
                // But it would be incredibly unusual for this to be set more than once
                // before the window is loaded, and even a handful of delegate instances
                // being around that are no longer needed is not really a big deal.
                window.Loaded += _ApplyCloseButtonVisibility;
            }
            else
            {
                _SetVisibility(window, newVisibility);
            }
        }
    }

    #region Win32 imports

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

    #endregion

    private static void _ApplyCloseButtonVisibility(object sender, RoutedEventArgs e)
    {
        Window window = (Window)sender;
        CloseButtonVisibility visibility = GetCloseButtonVisibility(window);

        _SetVisibility(window, visibility);
    }

    private static void _SetVisibility(Window window, CloseButtonVisibility visibility)
    {
        var hwnd = new WindowInteropHelper(window).Handle;

        if (visibility == CloseButtonVisibility.Visible)
        {
            SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | WS_SYSMENU);
        }
        else
        {
            SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU);
        }
    }
}

선택할 수 있는 세 가지 상태를 제공합니다.

  1. 보이는
  2. 숨겼지만 +를 F4사용하여 닫을 수 있습니다.
  3. 숨김 및 닫기가 완전히 비활성화됩니다.

기본적으로 창이 닫히지 않으면 WPF 프로그램의 프로세스가 종료되지 않습니다.그래서 만약 당신이 사용하기로 선택한다면.CloseButtonVisibility.CloseDisabled하려면 , 당은사용정필것요입니다할의가값자신▁the▁customize다▁value,▁either를 사용자 정의해야 합니다.Application.Run()e▁window,. 예를 기본 같은 .예를 들어 기본 창에는 다음과 같은 것이 있을 수 있습니다.

protected override void OnClosed(EventArgs e)
{
    WindowEx.SetCloseButtonVisibility(this.toolWindow.Value, CloseButtonVisibility.Hidden);
    this.toolWindow.Value.Close();

    base.OnClosed(e);
}

어디에toolWindow그것은Window닫기 버튼이 비활성화된 윈도우에 대한 참조입니다.

위에서는 일반적으로 일반적인 UI 활동 중에 창이 숨겨지고 필요에 따라 표시되는 것으로 가정합니다.물론 언제든지 창을 명시적으로 닫도록 선택할 수도 있지만, 닫기를 비활성화하지 않도록 옵션을 설정한 다음 창을 명시적으로 닫도록 설정하는 것과 같은 방법이 적용됩니다.

현재 표시되는 페이지 또는 사용자 컨트롤에 따라 창 상태를 전환해야 할 수 있습니다.(네, 이것은 특이한 시나리오이지만 발생할 수 있습니다.이 경우 애플리케이션에 외부 터치 스크린에 표시되는 사용자 컨트롤이 있어 고객이 상호 작용할 수 있습니다.우리는 고객이 화면을 닫기 위해 터치 액세스 권한을 갖지 않기를 원하지 않습니다.그러나 나머지 애플리케이션은 표준 윈도우 프레임을 사용합니다.)페이지 또는 사용자 컨트롤 뒤의 코드에서 이 작업을 수행합니다.참고: 컨트롤이 생성자에 채워지지 않았고 예외가 발생하므로 생성자가 아닌 로드된 이벤트에서 실행해야 합니다.

// To toggle it off
Window.GetWindow(this).WindowStyle = WindowStyle.None;

// To turn it back on toggle it off
Window.GetWindow(this).WindowStyle = WindowStyle.SingleBorderWindow;

창 속성 집합으로 이동

window style = none;

버튼이 닫히지 않을 것입니다.

이것에 대한 답을 많이 찾은 후에, 저는 다른 사람들에게 도움이 되기를 바라며 여기서 공유할 이 간단한 해결책을 생각해 냈습니다.

나는 설정WindowStyle=0x10000000.

이렇게 설정합니다.WS_VISIBLE (0x10000000)그리고.WS_OVERLAPPED (0x0)창 스타일 값을 입력합니다.제목 표시줄과 창 테두리를 표시하는 데 필요한 값은 "중첩"입니다.제거를 통해WS_MINIMIZEBOX (0x20000),WS_MAXIMIZEBOX (0x10000),그리고.WS_SYSMENU (0x80000)내 스타일 값에서 값을 선택하고, 닫기 단추를 포함하여 제목 표시줄의 모든 단추가 제거되었습니다.

사용자가 창을 닫는 것을 금지하는 것만 필요한 경우 이는 간단한 해결 방법입니다.

XAML 코드:IsCloseButtonEnabled="False"

버튼을 막았습니다.

사용하다WindowStyle="SingleBorderWindow"이렇게 하면 WPF 창에서 max 및 min 버튼이 숨겨집니다.

언급URL : https://stackoverflow.com/questions/743906/how-to-hide-close-button-in-wpf-window

반응형