Q048. Window の最小化・最大化ボタンを無効にするには?

A. SetWindowLong で Window スタイルを設定します。
(2011/07/25 追記)リサイズ不可で最大化だけ無効にしたいなら ResizeMode を CanMinimize に設定するといいです。


関連記事Windowの最小化、最大化ボタン


実は私も id:akiramei さんと同じく、ユーザーさんから最大化だけ無効にしたいと要求合ったため Window のプロパティ調べていたら、どこにもないのにマジ愕然・・・。そこで、散々ぐぐって見つけた id:akiramei さんの記事を参考に対処させて頂きました。しかしこれだと Window を継承せねばならぬため、少し美しくないのも事実。そこで添付ビヘイビアに魔改造し、さらに VB の人も使えるよう VB に移植してみました。以下コードです。(でもこの程度のことは標準対応してほしいもんですね)

Option Explicit On
Option Strict On

Imports System.Runtime.InteropServices
Imports System.Windows
Imports System.Windows.Interop

<Flags()>
Public Enum WindowStyleFlag As UInteger
    WS_SYSMENU = &H80000
    WS_MINIMIZEBOX = &H20000
    WS_MAXIMIZEBOX = &H10000
End Enum

Public Class WindowMenuBehaviors

    Const GWL_STYLE As Integer = -16

    <DllImport("user32")>
    Private Shared Function GetWindowLong(hWnd As IntPtr, index As Integer) As UInteger
    End Function

    <DllImport("user32")>
    Private Shared Function SetWindowLong(hWnd As IntPtr, index As Integer, dwLong As WindowStyleFlag) As UInteger
    End Function

    Public Shared ReadOnly MinimizeBoxProperty As DependencyProperty =
        DependencyProperty.RegisterAttached("MinimizeBox", GetType(Boolean), GetType(WindowMenuBehaviors), New UIPropertyMetadata(True, AddressOf SourceInitialized))

    Public Shared ReadOnly MaximizeBoxProperty As DependencyProperty =
        DependencyProperty.RegisterAttached("MaximizeBox", GetType(Boolean), GetType(WindowMenuBehaviors), New UIPropertyMetadata(True, AddressOf SourceInitialized))

    Public Shared ReadOnly ControlBoxProperty As DependencyProperty =
        DependencyProperty.RegisterAttached("ControlBox", GetType(Boolean), GetType(WindowMenuBehaviors), New UIPropertyMetadata(True, AddressOf SourceInitialized))

    ''' <summary>
    ''' 最小化ボタン。
    ''' </summary>
    <AttachedPropertyBrowsableForType(GetType(WindowMenuBehaviors))>
    Public Shared Function GetMinimizeBox(obj As DependencyObject) As Boolean
        Return CBool(obj.GetValue(MinimizeBoxProperty))
    End Function

    <AttachedPropertyBrowsableForType(GetType(WindowMenuBehaviors))>
    Public Shared Sub SetMinimizeBox(obj As DependencyObject, value As Boolean)
        obj.SetValue(MinimizeBoxProperty, value)
    End Sub

    ''' <summary>
    ''' 最大化ボタン。
    ''' </summary>
    <AttachedPropertyBrowsableForType(GetType(WindowMenuBehaviors))>
    Public Shared Function GetMaximizeBox(obj As DependencyObject) As Boolean
        Return CBool(obj.GetValue(MaximizeBoxProperty))
    End Function

    <AttachedPropertyBrowsableForType(GetType(WindowMenuBehaviors))>
    Public Shared Sub SetMaximizeBox(obj As DependencyObject, value As Boolean)
        obj.SetValue(MaximizeBoxProperty, value)
    End Sub

    ''' <summary>
    ''' システムメニュー。
    ''' </summary>
    <AttachedPropertyBrowsableForType(GetType(WindowMenuBehaviors))>
    Public Shared Function GetControlBox(obj As DependencyObject) As Boolean
        Return CBool(obj.GetValue(ControlBoxProperty))
    End Function

    <AttachedPropertyBrowsableForType(GetType(WindowMenuBehaviors))>
    Public Shared Sub SetControlBox(obj As DependencyObject, value As Boolean)
        obj.SetValue(ControlBoxProperty, value)
    End Sub

    Private Shared Sub SourceInitialized(sender As DependencyObject, e As DependencyPropertyChangedEventArgs)
        Dim window = TryCast(sender, Window)
        If (window Is Nothing) Then Return

        AddHandler window.SourceInitialized,
            Sub(obj, args)
                Dim w = TryCast(obj, Window)
                If (w Is Nothing) Then Return

                Dim handle As IntPtr = (New WindowInteropHelper(w)).Handle

                Dim original = CType(GetWindowLong(handle, GWL_STYLE), WindowStyleFlag)
                Dim current = GetWindowStyle(w, original, e)
                If (original <> current) Then
                    SetWindowLong(handle, GWL_STYLE, current)
                End If
            End Sub
    End Sub

    Private Shared Function GetWindowStyle(obj As DependencyObject,
                                           windowStyle As WindowStyleFlag, ex As DependencyPropertyChangedEventArgs) As WindowStyleFlag
        Dim style = windowStyle

        Select Case ex.Property.Name
            Case "MinimizeBox"
                If CBool(obj.GetValue(MinimizeBoxProperty)) Then
                    style = style Or WindowStyleFlag.WS_MINIMIZEBOX
                Else
                    style = style Xor WindowStyleFlag.WS_MINIMIZEBOX
                End If
            Case "MaximizeBox"
                If CBool(obj.GetValue(MaximizeBoxProperty)) Then
                    style = style Or WindowStyleFlag.WS_MAXIMIZEBOX
                Else
                    style = style Xor WindowStyleFlag.WS_MAXIMIZEBOX
                End If
            Case "ControlBox"
                If CBool(obj.GetValue(ControlBoxProperty)) Then
                    style = style Or WindowStyleFlag.WS_SYSMENU
                Else
                    style = style Xor WindowStyleFlag.WS_SYSMENU
                End If
        End Select

        Return style

    End Function

End Class


VB2010 から Sub キーワードもラムダ式使えるようになったので便利です。後はビヘイビアの添付プロパティを使えばおk。

<Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:LivetWPFApplication1"
        local:WindowMenuBehaviors.MinimizeBox="True"
        local:WindowMenuBehaviors.MaximizeBox="False"
        local:WindowMenuBehaviors.ControlBox="False"> 
    <Grid>
    </Grid>
</Window>


WindowMenuBehaviors.ControlBox を False にした場合、コントロールボックスが非表示になります。


最大化ボタンだけ無効にしたければ、WindowMenuBehaviors.MaximizeBox="False" と書くだけでオッケー。下の図だと判りにくいかも知れませんが、最大化ボタンのみ無効になってます。

<Window x:Class="MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:LivetWPFApplication1"
        local:WindowMenuBehaviors.MaximizeBox="False">
    <Grid>
    </Grid>
</Window>



WPF FAQ の目次に戻る