วิธีซ่อนปุ่มปิดในหน้าต่าง WPF


204

ฉันกำลังเขียนกล่องโต้ตอบโมดอลใน WPF ฉันจะตั้งค่าหน้าต่าง WPF ให้ไม่มีปุ่มปิดได้อย่างไร ฉันยังต้องการให้มันWindowStateมีแถบชื่อเรื่องปกติ

ฉันพบResizeMode, WindowStateและWindowStyle, แต่ไม่มีคุณสมบัติใดที่อนุญาตให้ฉันซ่อนปุ่มปิด แต่แสดงแถบหัวเรื่อง, เช่นเดียวกับในกล่องโต้ตอบโมดอล


9
มันเป็นกล่องโต้ตอบความคืบหน้าในการใช้เธรดพื้นหลังที่ไม่รองรับการยกเลิก ฉันเดาว่าฉันแค่พยายามทำมันดังนั้นฉันจึงไม่ต้องสนับสนุนการยกเลิก (ยัง) คุณอาจพูดถูก
Michael Hedgpeth

1
ฉันเกลียดแอปที่พยายามลบหน้าต่างโครเมี่ยมด้วย ถ้าฉันทำกล่องโต้ตอบความคืบหน้าฉันจะทำให้ปุ่มปิดหน้าต่างทำตรรกะเช่นเดียวกับการคลิกปุ่มยกเลิกจริง
Christian Hayter

13
สำหรับคริส: สมมติว่าซอฟต์แวร์ของคุณใช้สำหรับการเฝ้าระวังวิดีโอ เจ้าหน้าที่รักษาความปลอดภัยในตอนกลางคืนมีงานของเขาที่เปิดหน้าต่างอยู่ ... แต่บางครั้งงานของพวกเขาน่าเบื่อและพวกเขาต้องการท่องอินเทอร์เน็ตหรือปิดหน้าต่าง Video Matrices ไม่ว่าด้วยเหตุผลใดการถอดปุ่ม windows เป็นวิธีที่เหมาะสม ที่จะทำมัน
Jean-Marie

7
@ChrisUpchurch, "ทำไมคุณต้องการที่จะทำเช่นนี้มันนัดฉันเป็นการออกแบบ UI หมัดจริงๆ." - จริงๆ "การออกแบบ UI หมัด" คือเมื่อโปรแกรมของขวัญกล่องโต้ตอบกับOK ; ปุ่มยกเลิกและปิด สำหรับผู้ใช้อาจไม่ชัดเจนว่าCloseทำอะไร มันยกเลิกหรือส่ง ? ฉันทามติไม่รวมปุ่มปิดในกล่องโต้ตอบดังนั้นจึงมี
MickyD

1
@ Jean-Marie แต่การซ่อนปุ่มปิดไม่ได้ป้องกันสิ่งนั้นให้เกิดขึ้นมันทำให้คนโง่เท่านั้นที่ไม่รู้และขี้เกียจ (กับ Google) การซ่อนปุ่มปิดจะป้องกันการคลิกปุ่มนั้นเท่านั้น คีย์ win และคอมโบ alt 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เหตุการณ์ของ Window :

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

แล้วคุณก็ไปไม่มีปุ่มปิดอีกต่อไป คุณจะไม่มีไอคอนหน้าต่างทางด้านซ้ายของแถบชื่อเรื่องซึ่งหมายความว่าไม่มีเมนูระบบแม้ว่าคุณจะคลิกขวาที่แถบชื่อเรื่องก็ตาม

โปรดทราบว่าAlt+ F4จะยังคงปิดหน้าต่าง หากคุณไม่ต้องการให้หน้าต่างปิดก่อนที่จะเสร็จสิ้นเธรดพื้นหลังคุณสามารถแทนที่OnClosingและตั้งค่าCancelเป็นจริงได้ตามที่ Gabe แนะนำ


5
ตามเอกสารที่เราควรใช้SetWindowLongPtrแทน
Jonathan Allen

15
ส่วนใหญ่ทราบถึงตนเอง ... Namespace ของ DllImport -> System.Runtime.InteropServices.DllImport Namespace ของ WindowInteropHelper -> System.Windows.Interop.WindowInteropHelper
doobop

3
ที่จริงแล้ววิธีการนี้ซ่อนทั้งสามปุ่ม (ต่ำสุด, สูงสุดและปิด) เป็นไปได้หรือไม่ที่จะซ่อนปุ่มปิด
นิวแมน

4
@miliu ไม่ คุณสามารถปิดการใช้งานได้แต่ไม่สามารถซ่อนได้โดยไม่ต้องย่อเล็กสุด / ขยายใหญ่สุดเช่นกัน ฉันสงสัยว่า Windows devs คิดว่ามันน่าสับสนหาก Maximize อยู่ทางด้านขวาซึ่ง Close มักจะเป็น
Joe White

3
วาง WindowStyle = "None" บนแท็ก Window ของคุณในไฟล์ XAML
diegodsp

88

ฉันได้รับปัญหาที่คล้ายกันและวิธีแก้ปัญหาของ 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>

62

ตั้งค่าWindowStyleคุณสมบัติเป็นไม่มีซึ่งจะซ่อนกล่องควบคุมพร้อมกับแถบชื่อเรื่อง ไม่จำเป็นต้องโทร kernal


20
นี่จะซ่อนแถบหัวเรื่องหน้าต่างอย่างสมบูรณ์ ซึ่งหมายความว่าคุณไม่ได้รับชื่อหน้าต่างและผู้ใช้จะไม่สามารถย้ายหน้าต่างได้
นิวแมน

6
คุณสามารถทำให้หน้าต่างเคลื่อนย้ายได้โดยเพิ่มกิจกรรมthis.DragMove();ของหน้าต่างMouseDown
paul

1
สำหรับกล่องโต้ตอบโมดอลที่ควรให้ข้อมูลและบังคับอย่างหมดจดเช่นความคืบหน้าในการอัพเกรดฐานข้อมูลด้วยสคีมาเก่าที่เปิดขึ้นโซลูชันนี้จึงสมบูรณ์แบบ
Lonely Coder

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
Sheridan

4
ฉันได้รับมากเกินไปโดยใช้วิธีนี้ฉันออกฐานเมื่อปิด (e) แล้วมันทำงาน
jacobsgriffith

8
ในฐานะผู้ใช้ฉันจะเกลียดโปรแกรมเมอร์ที่ใส่สิ่งนี้ลงในแอปพลิเคชันของพวกเขา
UrbanEsc

2
@UrbanEsc ฉันมักจะเห็นด้วยว่ามันเป็นเรื่องที่น่ารำคาญ แต่เมื่อฉันทำสิ่งนี้ - และมันเป็นเพียงครั้งเดียวเท่านั้น - มันเป็นข้อกำหนดที่จำเป็นและมันเป็นความชั่วร้ายที่จำเป็นมีกระบวนการที่สำคัญมากเกิดขึ้น ไม่สามารถถูกขัดจังหวะและแอปไม่สามารถดำเนินการต่อจนกว่าจะเสร็จสิ้น มีวิธีอื่นที่สามารถทำได้ (เธรดพื้นหลังโดยที่ UI ถูกปิดใช้งานจนกว่าจะพร้อมใช้งาน) แต่เจ้านายและลูกค้าทั้งคู่ชอบวิธีนี้เพราะเน้นถึงแรงโน้มถ่วงของกระบวนการ
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
การปิดใช้งานปุ่มนั้นดีกว่าเพียงแค่ลบปุ่มออก แต่จะให้ความรู้สึกที่สอดคล้องกันในขณะที่ให้ผู้ใช้ทราบว่าการดำเนินการที่สำคัญกำลังทำงานอยู่
Robert Baker

10

ฉันลองคำตอบของ 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 );
}

1
ที่สมบูรณ์แบบ! เพิ่มเป็นWindowวิธีการขยายในโครงการของฉัน
Matt Davis

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
นอกจากนี้ยังซ่อนปุ่มสูงสุด / นาที
VoteCoffee

3
มันลบแถบชื่อเรื่องทั้งหมดแสดงผลกล่องน่าเกลียดและไม่มีคำอธิบาย วิธี Shotgun และคำตอบที่ซ้ำกัน downvote
vapcguy

นี่เป็นทางออกที่ดีที่สุดสำหรับแอปพลิเคชั่นคีออสก์ซึ่งต้องการแอปพลิเคชั่นของมันให้ใหญ่ที่สุดเสมอและไม่ควรอนุญาตให้ลูกค้าปิดแอป So UpVote
Rajon Tanducar

8

ฉันเพิ่งเพิ่มการนำคำตอบของโจไวท์ไปใช้โดยใช้พฤติกรรมการโต้ตอบ (คุณต้องอ้างอิง System.Windows.Inactactivity)

รหัส:

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

ทุกครั้งที่จะดำเนินการเธรดพื้นหลังหน้าต่าง 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

1

ดังนั้นนี่คือปัญหาของคุณ ปุ่มปิดที่มุมขวาบนของกรอบหน้าต่างไม่ได้เป็นส่วนหนึ่งของหน้าต่าง WPF แต่เป็นส่วนหนึ่งของกรอบหน้าต่างที่ควบคุมโดยระบบปฏิบัติการของคุณ หมายความว่าคุณจะต้องใช้ Win32 interop เพื่อทำเช่นนั้น

นอกจากนี้คุณสามารถใช้ noframe และระบุ "frame" ของคุณเองหรือไม่มีเฟรมเลย


1

ข้อมูลต่อไปนี้เกี่ยวกับการปิดใช้งานปุ่มปิดและย่อเล็กสุด / ย่อเล็กสุดมันไม่ได้ลบปุ่มจริง ๆ (แต่จะลบรายการเมนู!) ปุ่มต่างๆบนแถบหัวเรื่องถูกวาดในสถานะปิดการใช้งาน / เป็นสีเทา (ฉันยังไม่พร้อมที่จะรับฟังการทำงานทั้งหมดด้วยตัวเอง ^^)

สิ่งนี้แตกต่างจากโซลูชัน Virgoss เล็กน้อยซึ่งจะลบรายการเมนู (และตัวคั่นต่อท้ายหากจำเป็น) แทนการปิดใช้งานพวกเขา มันแตกต่างจากโซลูชัน Joe Whites เพราะมันไม่ได้ปิดการใช้งานเมนูระบบทั้งหมดดังนั้นในกรณีของฉันฉันสามารถเก็บไว้รอบ ๆ ปุ่มย่อเล็กสุดและไอคอน

รหัสติดตามยังรองรับการปิดการใช้งานปุ่มย่อเล็กสุด / ย่อเล็กสุดซึ่งแตกต่างจากปุ่มปิดการลบรายการออกจากเมนูไม่ทำให้ระบบแสดงปุ่ม "ถูกปิดใช้งาน" แม้ว่าการลบรายการเมนูจะเป็นการปิดการทำงานของปุ่มต่างๆ

มันใช้งานได้สำหรับฉัน YMMV

    using System;
    using System.Collections.Generic;
    using System.Text;

    using System.Runtime.InteropServices;
    using Window = System.Windows.Window;
    using WindowInteropHelper = System.Windows.Interop.WindowInteropHelper;
    using Win32Exception = System.ComponentModel.Win32Exception;

    namespace Channelmatter.Guppy
    {

        public class WindowUtil
        {
            const int MF_BYCOMMAND = 0x0000;
            const int MF_BYPOSITION = 0x0400;

            const uint MFT_SEPARATOR = 0x0800;

            const uint MIIM_FTYPE = 0x0100;

            [DllImport("user32", SetLastError=true)]
            private static extern uint RemoveMenu(IntPtr hMenu, uint nPosition, uint wFlags);

            [DllImport("user32", SetLastError=true)]
            private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

            [DllImport("user32", SetLastError=true)]
            private static extern int GetMenuItemCount(IntPtr hWnd);

            [StructLayout(LayoutKind.Sequential)]
            public struct MenuItemInfo {
                public uint   cbSize;
                public uint   fMask;
                public uint   fType;
                public uint   fState;
                public uint   wID;
                public IntPtr hSubMenu;
                public IntPtr hbmpChecked;
                public IntPtr hbmpUnchecked;
                public IntPtr dwItemData; // ULONG_PTR
                public IntPtr dwTypeData;
                public uint   cch;
                public IntPtr hbmpItem;
            };

            [DllImport("user32", SetLastError=true)]
            private static extern int GetMenuItemInfo(
                IntPtr hMenu, uint uItem,
                bool fByPosition, ref MenuItemInfo itemInfo);

            public enum MenuCommand : uint
            {
                SC_CLOSE = 0xF060,
                SC_MAXIMIZE = 0xF030,
            }

            public static void WithSystemMenu (Window win, Action<IntPtr> action) {
                var interop = new WindowInteropHelper(win);
                IntPtr hMenu = GetSystemMenu(interop.Handle, false);
                if (hMenu == IntPtr.Zero) {
                    throw new Win32Exception(Marshal.GetLastWin32Error(),
                        "Failed to get system menu");
                } else {
                    action(hMenu);
                }
            }

            // Removes the menu item for the specific command.
            // This will disable and gray the Close button and disable the
            // functionality behind the Maximize/Minimuze buttons, but it won't
            // gray out the Maximize/Minimize buttons. It will also not stop
            // the default Alt+F4 behavior.
            public static void RemoveMenuItem (Window win, MenuCommand command) {
                WithSystemMenu(win, (hMenu) => {
                    if (RemoveMenu(hMenu, (uint)command, MF_BYCOMMAND) == 0) {
                        throw new Win32Exception(Marshal.GetLastWin32Error(),
                            "Failed to remove menu item");
                    }
                });
            }

            public static bool RemoveTrailingSeparator (Window win) {
                bool result = false; // Func<...> not in .NET3 :-/
                WithSystemMenu(win, (hMenu) => {
                    result = RemoveTrailingSeparator(hMenu);
                });
                return result;
            }

            // Removes the final trailing separator of a menu if it exists.
            // Returns true if a separator is removed.
            public static bool RemoveTrailingSeparator (IntPtr hMenu) {
                int menuItemCount = GetMenuItemCount(hMenu);
                if (menuItemCount < 0) {
                    throw new Win32Exception(Marshal.GetLastWin32Error(),
                        "Failed to get menu item count");
                }
                if (menuItemCount == 0) {
                    return false;
                } else {
                    uint index = (uint)(menuItemCount - 1);
                    MenuItemInfo itemInfo = new MenuItemInfo {
                        cbSize = (uint)Marshal.SizeOf(typeof(MenuItemInfo)),
                        fMask = MIIM_FTYPE,
                    };

                    if (GetMenuItemInfo(hMenu, index, true, ref itemInfo) == 0) {
                        throw new Win32Exception(Marshal.GetLastWin32Error(),
                            "Failed to get menu item info");
                    }

                    if (itemInfo.fType == MFT_SEPARATOR) {
                        if (RemoveMenu(hMenu, index, MF_BYPOSITION) == 0) {
                            throw new Win32Exception(Marshal.GetLastWin32Error(),
                                "Failed to remove menu item");
                        }
                        return true;
                    } else {
                        return false;
                    }
                }
            }

            private const int GWL_STYLE = -16;

            [Flags]
            public enum WindowStyle : int
            {
                WS_MINIMIZEBOX = 0x00020000,
                WS_MAXIMIZEBOX = 0x00010000,
            }

            // Don't use this version for dealing with pointers
            [DllImport("user32", SetLastError=true)]
            private static extern int SetWindowLong (IntPtr hWnd, int nIndex, int dwNewLong);

            // Don't use this version for dealing with pointers
            [DllImport("user32", SetLastError=true)]
            private static extern int GetWindowLong (IntPtr hWnd, int nIndex);

            public static int AlterWindowStyle (Window win,
                WindowStyle orFlags, WindowStyle andNotFlags) 
            {
                var interop = new WindowInteropHelper(win);

                int prevStyle = GetWindowLong(interop.Handle, GWL_STYLE);
                if (prevStyle == 0) {
                    throw new Win32Exception(Marshal.GetLastWin32Error(),
                        "Failed to get window style");
                }

                int newStyle = (prevStyle | (int)orFlags) & ~((int)andNotFlags);
                if (SetWindowLong(interop.Handle, GWL_STYLE, newStyle) == 0) {
                    throw new Win32Exception(Marshal.GetLastWin32Error(),
                        "Failed to set window style");
                }
                return prevStyle;
            }

            public static int DisableMaximizeButton (Window win) {
                return AlterWindowStyle(win, 0, WindowStyle.WS_MAXIMIZEBOX);
            }
        }
    }

การใช้งาน: สิ่งนี้จะต้องทำหลังจากแหล่งที่จะเริ่มต้น สถานที่ที่ดีคือการใช้เหตุการณ์ SourceInitialized ของหน้าต่าง:

Window win = ...; /* the Window :-) */
WindowUtil.DisableMaximizeButton(win);
WindowUtil.RemoveMenuItem(win, WindowUtil.MenuCommand.SC_MAXIMIZE);
WindowUtil.RemoveMenuItem(win, WindowUtil.MenuCommand.SC_CLOSE);
while (WindowUtil.RemoveTrailingSeparator(win)) 
{
   //do it here
}

หากต้องการปิดการใช้งานฟังก์ชั่น Alt + F4 วิธีที่ง่ายคือเพียงวางสายการยกเลิกเหตุการณ์และใช้การตั้งค่าสถานะเมื่อคุณต้องการปิดหน้าต่างจริงๆ


0

รหัส XAML

<Button Command="Open" Content="_Open">
    <Button.Style>
        <Style TargetType="Button">
            <Style.Triggers>
                <Trigger Property="IsEnabled" Value="False">
                    <Setter Property="Visibility" Value="Collapsed" />
                </Trigger>
            </Style.Triggers>
        </Style>
     </Button.Style>
</Button>

ควรทำงาน

แก้ไข - สำหรับของคุณทันทีนี้กระทู้แสดงให้เห็นว่าสามารถทำได้ แต่ผมไม่คิดว่าหน้าต่างมีคุณสมบัติที่จะได้รับสิ่งที่คุณต้องการโดยไม่สูญเสียแถบชื่อเรื่องปกติ

แก้ไข 2 เธรด นี้แสดงวิธีการทำ แต่คุณต้องใช้สไตล์ของคุณเองกับเมนูระบบและจะแสดงวิธีที่คุณสามารถทำได้


ด้วยเหตุผลบางอย่าง "ควรทำงาน" เพียงแค่แสดง แต่ตอนนี้การปรับปรุงที่เกิดขึ้น
TStamper

3
ฉันกำลังพูดถึงสถานะของหน้าต่างซึ่งอยู่ในแถบชื่อเรื่อง ดูเหมือนว่าการแก้ไขปุ่มอย่างง่าย
Michael Hedgpeth

@TSTamper ฉันจะใช้ตัวอย่างข้อมูลของคุณได้อย่างไร ฉันใช้สไตล์หน้าต่างทั่วโลก (และแม่แบบ)
Shimmy Weitzhandler

@ 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"เพื่อลบแถบชื่อเรื่องทั้งหมด

และตามที่ระบุไว้ในความคิดเห็นต่อคำตอบอื่น ๆ สิ่งนี้จะป้องกันหน้าต่างจากการถูกลากได้ดังนั้นจึงเป็นการยากที่จะย้ายหน้าต่างออกจากตำแหน่งเริ่มต้น

อย่างไรก็ตามคุณสามารถเอาชนะสิ่งนี้ได้โดยการเพิ่มโค้ดหนึ่งบรรทัดลงในไฟล์ Constructor ในไฟล์ Code's Window Behind:

MouseDown += delegate { DragMove(); };

หรือถ้าคุณชอบ Lambda Syntax:

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

ทำให้ทั้งหน้าต่างสามารถลากได้ การควบคุมแบบโต้ตอบใด ๆ ที่ปรากฏในหน้าต่างเช่นปุ่มจะยังคงทำงานตามปกติและจะไม่ทำหน้าที่เป็นตัวจับลากสำหรับหน้าต่าง


ยังเป็นความคิดที่ไม่ดี มันลบแถบชื่อเรื่องทั้งหมดทำให้นี่เป็นวิธีปืนลูกซองและทำให้กล่องดูน่าเกลียดและหมายความว่าไม่มีชื่อเรื่อง / คำอธิบายสำหรับมัน มีทางเลือกที่ดีกว่ามาก
vapcguy

@vapcguy มันลบแถบชื่อเรื่องทั้งหมด มันเป็นวิธีปืนลูกซอง ทำให้กล่องดูน่าเกลียด? ความคิดเห็นของคุณ. ทางเลือกที่ดีกว่ามาก? สำหรับคุณอาจจะ ไม่ใช่สำหรับทุกคน :-)
Holf

-1

หลังจากค้นหาคำตอบนี้มากฉันหาวิธีแก้ปัญหาง่ายๆที่ฉันจะแบ่งปันที่นี่ด้วยความหวังว่ามันจะช่วยผู้อื่น

WindowStyle=0x10000000ผมชุด

ชุดนี้WS_VISIBLE (0x10000000)และWS_OVERLAPPED (0x0)ค่าสำหรับรูปแบบหน้าต่าง "Overlapped" เป็นค่าที่จำเป็นในการแสดงแถบหัวเรื่องและขอบหน้าต่าง โดยการลบWS_MINIMIZEBOX (0x20000), WS_MAXIMIZEBOX (0x10000)และWS_SYSMENU (0x80000)ค่าจากค่าสไตล์ของฉัน, ปุ่มทั้งหมดจากแถบชื่อเรื่องถูกถอดออกรวมทั้งปุ่มปิด


ใน WPF WindowStyleคือการแจงนับที่ค่าไม่ตรงกับค่าคงที่ Windows API; การบังคับค่าการWindowStyleแจงนับจะไม่ทำงาน เพื่อให้แน่ใจว่าฉันได้ตรวจสอบซอร์สโค้ด. NET ใน ILSpy แล้ว enum ค่าจะถูกแปลเป็น Windows API ในการทำงานส่วนตัวCreateWindowStyleและถ้าฟังก์ชั่นพบรู้จักค่ามันก็มีผลบังคับใช้WindowStyle WindowStyle.None(วิธีเดียวคือใช้คุณสมบัติภายใน_Styleและ_StyleExใช้การสะท้อนซึ่งฉันแนะนำอย่างยิ่ง)
Mike Rosoft


-2

หากความต้องการเป็นเพียงการห้ามไม่ให้ผู้ใช้ปิดหน้าต่างนี่เป็นทางออกที่ง่าย

รหัส XAML: IsCloseButtonEnabled="False"

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.