WPF-Fenster Buttons Disable, Enable oder Manipulieren

Veröffentlicht von

Normalerweise sind alle drei SystemButtons vorhanden und aktiv. Das Setzen der folgenden Styles bzw. Modes ändert nichts an den drei SystemButtons. this bezeichne hier und im folgenden ein TopLevel-Fenster. Mit den Properties ResizeMode und WindowStyle kann man die folgenden Einstellungen vornehmen.

Default

cs

this.ResizeMode = ResizeMode.CanResize;  // ändert nichts
this.WindowStyle = WindowStyle.SingleBorderWindow;  // ändert nichts
this.ResizeMode = ResizeMode.CanResizeWithGrip;  // zeigt unten rechts das Resize-Symbol anCode-Sprache: JavaScript (javascript)

axml

<Window x:Class="StartEXEjar.view.WindowVersion"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:StartEXEjar.view"
        mc:Ignorable="d"
        WindowStyle="SingleBorderWindow" 
        ResizeMode="CanResizeWithGrip" // zeigt unten rechts das Resize-Symbol an
        Title="Infos" Width="700" Height="300"  MinWidth="700" MinHeight="300">
    <Grid>

    </Grid>
</Window>
Code-Sprache: HTML, XML (xml)

Min- und Max Button entfernen, Close Button bleibt aktiv

cs

this.ResizeMode = ResizeMode.NoResize;  // verschwindet Min- und MaxSystembutton
this.WindowStyle = WindowStyle.ToolWindow; // verschwindet Min- und MaxSystembutton, Titelzeile wird etwas kleinerCode-Sprache: JavaScript (javascript)

axml

ResizeMode="NoResize"
WindowStyle="ToolWindow"   Code-Sprache: JavaScript (javascript)

Max Button deaktivieren, Min- und Close Button aktiv

cs

this.ResizeMode = ResizeMode.CanMinimize;  // disables MaxSystemButton

axml

ResizeMode="CanMinimize" Code-Sprache: JavaScript (javascript)

Ganze Titelzeile verschwinden lassen

cs

this.WindowStyle = WindowStyle.None;  // ganze Titelzeile wegCode-Sprache: JavaScript (javascript)

axml

WindowStyle="None"   Code-Sprache: JavaScript (javascript)

Zugriff auf die WinApi-Funktionen


Für weitere Einstellungen muß man WinApi-Funktionen benutzen, die man in C# relativ leicht importieren kann. Hier zunächst das Vorgehen für den Zugriff auf die WinApi-Funktionen.

Notwendige usings

using System.Runtime.InteropServices;
using System.Windows.Interop;Code-Sprache: CSS (css)

WinApi-Funktionen importieren

namespace WpfApplication1
{
  public partial class Window1 : Window
  {
    private const Int32 GWL_STYLE = -16;
    private const Int32 WS_MAXIMIZEBOX = 0x00010000;
    private const Int32 WS_MINIMIZEBOX = 0x00020000;
    private const Int32 WS_SYSMENU = 0x80000;

    [DllImport("User32.dll", EntryPoint = "GetWindowLong")]
    private extern static Int32 GetWindowLongPtr(IntPtr hWnd, Int32 nIndex);

    [DllImport("User32.dll", EntryPoint = "SetWindowLong")]
    private extern static Int32 SetWindowLongPtr(IntPtr hWnd, Int32 nIndex, Int32 dwNewLong);

    [DllImport("user32.dll")]
    static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

    [DllImport("user32.dll")]
    static extern uint RemoveMenu(IntPtr hMenu, uint nPosition, uint wFlags);
  }
}Code-Sprache: PHP (php)

Die später vorgestellte Hilfsklasse SysMenuUtil verwendet auch noch die folgende Funktion.

[DllImport("user32.dll")]
static extern bool DrawMenuBar(IntPtr hWnd);

OnSourceInitialized(EventArgs e) -> Methode für dauerhafte Änderung

Will man die Änderungen am Systemmenu dauerhaft einrichten, so überschreibt man die Methode OnSourceInitialized(EventArgs e). Diese Methode wird nach dem Konstruktor gerufen, aber ausgeführt bevor das Fenster sichtbar wird. Im Konstruktor sind diese Aufrufe wirkungslos, da die Titelzeile des Fensters noch nicht im Hauptspeicher angelegt ist. Um die WinApi-Funktionen aufzurufen braucht man einen Pointer (Handle //2) auf das Fenster, den man über eine Instanz vom Typ WindowInteropHelper (//1)erhält. Danach ruft man die WinApi-Funktionen als klassische Funktionen ohne Klassenbezug auf (//3 und //4). Die Werte der Konstanten folgen in den nächsten Beispielen.

protected override void OnSourceInitialized(EventArgs e)
{
  base.OnSourceInitialized(e);

  WindowInteropHelper wih = new WindowInteropHelper(this); //1
  IntPtr hWnd = wih.Handle;  //2

  Int32 windowStyle = GetWindowLongPtr(hWnd, GWL_STYLE); //3
  // MaxSysbutton disabled
  SetWindowLongPtr(hWnd, GWL_STYLE, windowStyle & ~WS_MAXIMIZEBOX); //4

  //...
}

Min Button deaktivieren, Max- und Close Button aktiv

Für diese und die nächste Konfiguration brauchen wir die Funktionen GetWindowLongPtr() und SetWindowLongPtr() und drei Konstanten. Die Funktionen müssen in der Methode OnSourceInitialized() aufgerufen werden. Diese Methode wird nach dem Konstruktor abgearbeitet. Im Konstruktor sind diese Methoden wirkungslos.

using System.Runtime.InteropServices;
using System.Windows.Interop;
...

namespace WpfApplication1
{
  public partial class Window1 : Window
  {
    private const Int32 GWL_STYLE = -16;
    private const Int32 WS_MAXIMIZEBOX = 0x00010000;
    private const Int32 WS_MINIMIZEBOX = 0x00020000;
    private const Int32 WS_SYSMENU = 0x80000;


    [DllImport("User32.dll", EntryPoint = "GetWindowLong")]
    private extern static Int32 GetWindowLongPtr(IntPtr hWnd, Int32 nIndex);

    [DllImport("User32.dll", EntryPoint = "SetWindowLong")]
    private extern static Int32 SetWindowLongPtr(IntPtr hWnd, Int32 nIndex, Int32 dwNewLong);


    protected override void OnSourceInitialized(EventArgs e)
    {
      base.OnSourceInitialized(e);

      WindowInteropHelper wih = new WindowInteropHelper(this);
      IntPtr hWnd = wih.Handle;
      Int32 windowStyle = GetWindowLongPtr(hWnd, GWL_STYLE);

      //MinSysbutton disabled
      SetWindowLongPtr(hWnd, GWL_STYLE, windowStyle & ~WS_MINIMIZEBOX);
    }
    ...
  }
  ...
}Code-Sprache: PHP (php)

Keine Buttons

// wie oben
...
...
    protected override void OnSourceInitialized(EventArgs e)
    {
      base.OnSourceInitialized(e);

      WindowInteropHelper wih = new WindowInteropHelper(this);
      IntPtr hWnd = wih.Handle;
      Int32 windowStyle = GetWindowLongPtr(hWnd, GWL_STYLE);

      //MinSysbutton disabled
      SetWindowLongPtr(hWnd, GWL_STYLE, windowStyle & ~WS_SYSMENU);
    }
    ...
  }
  ...
}Code-Sprache: JavaScript (javascript)

Close Button deaktiviert

Um an den CloseButton heranzukommen braucht man die WinAPI-Funktionen GetSystemMenu() und RemoveMenu().

using System.Runtime.InteropServices;
using System.Windows.Interop;
...

namespace WpfApplication1
{
  public partial class Window1 : Window
  {
    private const Int32 GWL_STYLE = -16;
    private const uint MF_BYCOMMAND  = 0x00000000;
    private const uint MF_BYPOSITION = 0x00000400;
    private const uint SC_CLOSE      = 0xF060;

    [DllImport("user32.dll")]
    static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

    [DllImport("user32.dll")]
    static extern uint RemoveMenu(IntPtr hMenu, uint nPosition, uint wFlags);


    protected override void OnSourceInitialized(EventArgs e)
    {
      base.OnSourceInitialized(e);

      WindowInteropHelper wih = new WindowInteropHelper(this);
      IntPtr hWnd = wih.Handle;
      IntPtr hMenu = GetSystemMenu(hWnd, false);

      // CloseButton disabled
      RemoveMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
    }
    ...
  }
  ...
}Code-Sprache: PHP (php)

Max- und Close Button deaktiviert

using System.Runtime.InteropServices;
using System.Windows.Interop;
...

namespace WpfApplication1
{
  public partial class Window1 : Window
  {
    private const Int32 GWL_STYLE = -16;
    private const uint MF_BYCOMMAND  = 0x00000000;
    private const uint MF_BYPOSITION = 0x00000400;
    private const uint SC_CLOSE      = 0xF060;

    [DllImport("user32.dll")]
    static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

    [DllImport("user32.dll")]
    static extern uint RemoveMenu(IntPtr hMenu, uint nPosition, uint wFlags);

    public Window1()  // Konstruktor
    {
      InitializeComponent();
      this.ResizeMode = ResizeMode.CanMinimize;  // disables MaxSystembutton
    }


    protected override void OnSourceInitialized(EventArgs e)
    {
      base.OnSourceInitialized(e);

      WindowInteropHelper wih = new WindowInteropHelper(this);
      IntPtr hWnd = wih.Handle;
      IntPtr hMenu = GetSystemMenu(hWnd, false);

      // CloseButton disabled
      RemoveMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
    }
    ...
  }
  ...
}Code-Sprache: PHP (php)

Min- und Close Button deaktiviert

using System.Runtime.InteropServices;
using System.Windows.Interop;
...

namespace WpfApplication1
{
  public partial class Window1 : Window
  {
    private const Int32 GWL_STYLE = -16;
    private const Int32 WS_MAXIMIZEBOX = 0x00010000;
    private const Int32 WS_MINIMIZEBOX = 0x00020000;
    private const Int32 WS_SYSMENU = 0x80000;

    private const uint MF_BYCOMMAND  = 0x00000000;
    private const uint MF_BYPOSITION = 0x00000400;
    private const uint SC_CLOSE      = 0xF060;

    [DllImport("User32.dll", EntryPoint = "GetWindowLong")]
    private extern static Int32 GetWindowLongPtr(IntPtr hWnd, Int32 nIndex);

    [DllImport("User32.dll", EntryPoint = "SetWindowLong")]
    private extern static Int32 SetWindowLongPtr(IntPtr hWnd, Int32 nIndex, Int32 dwNewLong);

    [DllImport("user32.dll")]
    static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

    [DllImport("user32.dll")]
    static extern uint RemoveMenu(IntPtr hMenu, uint nPosition, uint wFlags);


    protected override void OnSourceInitialized(EventArgs e)
    {
      base.OnSourceInitialized(e);

      WindowInteropHelper wih = new WindowInteropHelper(this);
      IntPtr hWnd = wih.Handle;
      Int32 windowStyle = GetWindowLongPtr(hWnd, GWL_STYLE);
      IntPtr hMenu = GetSystemMenu(hWnd, false);

      // CloseButton disabled
      RemoveMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);

      //MinSysbutton disabled
      SetWindowLongPtr(hWnd, GWL_STYLE, windowStyle & ~WS_MINIMIZEBOX);
    }
    ...
  }
  ...
}

Die Hilfsklasse SysMenuUtils


Wendet man die WinApi-SysMenu-Funktionen außerhalb von OnSourceInitialized() an, so muß man selbst dafür sorgen, daß das SysMenu neu gezeichnet wird. Dies wird durch den Aufruf von DrawMenuBar(hWnd) erreicht. Die Klasse hat auch Methoden mit denen man die Veränderungen rückgängig machen kann. Auch dazu benötigt man die Funktion DrawMenuBar(hWnd).

using System;
using System.Windows;
using System.Windows.Interop;
using System.Runtime.InteropServices;

namespace WpfApplication1
{
    class SysMenuUtils
    {
        private const Int32 GWL_STYLE = -16;
        private const Int32 WS_MAXIMIZEBOX = 0x00010000;
        private const Int32 WS_MINIMIZEBOX = 0x00020000;
        private const Int32 WS_SYSMENU     = 0x00080000;
        private const Int32 WS_OVERLAPPED  = 0x00000000;

        private const uint MF_REMOVE     = 0x00001000;
        private const uint MF_DISABLED   = 0x00000002;
        private const uint MF_BYCOMMAND  = 0x00000000;
        private const uint MF_BYPOSITION = 0x00000400;
        private const uint MF_GRAYED     = 0x00000001;
        private const uint MF_ENABLED    = 0x00000000;

        private const uint SC_CLOSE      = 0x0000F060;
        private const uint SC_SIZE       = 0x0000F000; //61440
        private const uint SC_MOVE       = 0x0000F010; //61456

        [DllImport("user32.dll")]
        static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

        [DllImport("user32.dll")]
        static extern int GetMenuItemCount(IntPtr hMenu);

        [DllImport("user32.dll")]
        static extern uint RemoveMenu(IntPtr hMenu, uint nPosition, uint wFlags);

        [DllImport("user32.dll")]
        static extern bool DrawMenuBar(IntPtr hWnd);

        [DllImport("User32.dll", EntryPoint = "GetWindowLong")]
        private extern static Int32 GetWindowLongPtr(IntPtr hWnd, Int32 nIndex);

        [DllImport("User32.dll", EntryPoint = "SetWindowLong")]
        private extern static Int32 SetWindowLongPtr(IntPtr hWnd, Int32 nIndex, Int32 dwNewLong);


        private SysMenuUtils()
        {}


        public static void disableCloseButton(Window window)
        {
            Console.WriteLine("disableCloseButton");
            WindowInteropHelper wih = new WindowInteropHelper(window);
            IntPtr hWnd = wih.Handle;
            IntPtr hMenu = GetSystemMenu(hWnd, false);
            RemoveMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
            //oder
            //RemoveMenu(hMenu, menuItemCount-1 , MF_DISABLED | MF_BYPOSITION);
            // es geht nur -1
            DrawMenuBar(hWnd);  // braucht man, wenn man nach OnSourceInitialized arbeitet
        }

        public static void enableCloseButton(Window window)
        {
            WindowInteropHelper wih = new WindowInteropHelper(window);
            IntPtr hWnd = wih.Handle;
            IntPtr hMenu = GetSystemMenu(hWnd, true);  // beachte true
            DrawMenuBar(hWnd);
        }

        public static void disableMaximizeButton(Window window)
        {
            WindowInteropHelper wih = new WindowInteropHelper(window);
            IntPtr hWnd = wih.Handle;
            Int32 windowStyle = GetWindowLongPtr(hWnd, GWL_STYLE);
            SetWindowLongPtr(hWnd, GWL_STYLE, windowStyle & ~WS_MAXIMIZEBOX);
            DrawMenuBar(hWnd);
        }

        public static void enableMaximizeButton(Window window)
        {
            WindowInteropHelper wih = new WindowInteropHelper(window);
            IntPtr hWnd = wih.Handle;
            Int32 windowStyle = GetWindowLongPtr(hWnd, GWL_STYLE);
            SetWindowLongPtr(hWnd, GWL_STYLE, windowStyle | WS_MAXIMIZEBOX);
            DrawMenuBar(hWnd);
        }


        public static void disableMinimizeButton(Window window)
        {
            WindowInteropHelper wih = new WindowInteropHelper(window);
            IntPtr hWnd = wih.Handle;
            Int32 windowStyle = GetWindowLongPtr(hWnd, GWL_STYLE);
            SetWindowLongPtr(hWnd, GWL_STYLE, windowStyle & ~WS_MINIMIZEBOX);
            DrawMenuBar(hWnd);
        }

        public static void enableMinimizeButton(Window window)
        {
            WindowInteropHelper wih = new WindowInteropHelper(window);
            IntPtr hWnd = wih.Handle;
            Int32 windowStyle = GetWindowLongPtr(hWnd, GWL_STYLE);
            SetWindowLongPtr(hWnd, GWL_STYLE, windowStyle | WS_MINIMIZEBOX);
            DrawMenuBar(hWnd);
        }

        public static void hideSysButtons(Window window)
        {
            WindowInteropHelper wih = new WindowInteropHelper(window);
            IntPtr hWnd = wih.Handle;
            Int32 windowStyle = GetWindowLongPtr(hWnd, GWL_STYLE);
            SetWindowLongPtr(hWnd, GWL_STYLE, windowStyle & ~WS_SYSMENU);
            DrawMenuBar(hWnd);
        }

        public static void showSysButtons(Window window)
        {
            WindowInteropHelper wih = new WindowInteropHelper(window);
            IntPtr hWnd = wih.Handle;
            Int32 windowStyle = GetWindowLongPtr(hWnd, GWL_STYLE);
            SetWindowLongPtr(hWnd, GWL_STYLE, windowStyle | WS_SYSMENU);
            DrawMenuBar(hWnd);
        }

        public static void disableMove(Window window)
        {
            Console.WriteLine("disableCloseButton");
            WindowInteropHelper wih = new WindowInteropHelper(window);
            IntPtr hWnd = wih.Handle;
            IntPtr hMenu = GetSystemMenu(hWnd, false);
            RemoveMenu(hMenu, SC_MOVE, MF_BYCOMMAND);
            //oder
            //RemoveMenu(hMenu, menuItemCount-1 , MF_DISABLED | MF_BYPOSITION);
            // es geht nur -1
            DrawMenuBar(hWnd);  // braucht man, wenn man nach OnSourceInitialized arbeitet
        }

        public static void enableMove(Window window)
        {
            WindowInteropHelper wih = new WindowInteropHelper(window);
            IntPtr hWnd = wih.Handle;
            // Damit wird der Defaultzustand wieder hergestellt
            // für die Veränderungen, die mit RemoveMenu gemacht wurden
            IntPtr hMenu = GetSystemMenu(hWnd, true);  // beachte true
            DrawMenuBar(hWnd);
        }

        public static void disableResizing(Window window)
        {
            Console.WriteLine("disableCloseButton");
            WindowInteropHelper wih = new WindowInteropHelper(window);
            IntPtr hWnd = wih.Handle;
            IntPtr hMenu = GetSystemMenu(hWnd, false);
            RemoveMenu(hMenu, SC_SIZE, MF_BYCOMMAND);
            DrawMenuBar(hWnd);  // braucht man, wenn man nach OnSourceInitialized arbeitet
        }

        public static void enableResizing(Window window)
        {
            WindowInteropHelper wih = new WindowInteropHelper(window);
            IntPtr hWnd = wih.Handle;
            IntPtr hMenu = GetSystemMenu(hWnd, true);  // beachte true
            DrawMenuBar(hWnd);
        }
    }
}Code-Sprache: JavaScript (javascript)

Quellen