XAMLでウィンドウの最大化・最小化・閉じるボタン群を制御する Attached Property

Attached Property の便利さに目覚めたので、最近はこういうのは全部、Attached Properyです。

<Window x:Class="AcpAcroHook.SettingsDialog"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    ...
    xmlns:cbh="clr-namespace:CaptionBoxesHelper"
    cbh:CaptionBoxesHelper.ControlBoxes="Control">
...
</Window>

ControlBoxes はフラグになっているので、 Control, Maximize, Minimize をカンマ区切りで指定できます。なので、

cbh:CaptionBoxesHelper.ControlBoxes="Control,Minimize"

みたいな感じで指定できます。

以下、ソース:

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

namespace CaptionBoxesHelper
{
  public static class CaptionBoxesHelper
  {
    public static readonly DependencyProperty ControlBoxesProperty =
      DependencyProperty.RegisterAttached(
        "ControlBoxes",
        typeof(ControlBoxes), typeof(CaptionBoxesHelper),
        new PropertyMetadata(ControlBoxes.None, controlBoxesChanged));

    public static void SetControlBoxes(DependencyObject dp, ControlBoxes value)
    {
      dp.SetValue(ControlBoxesProperty, value);
    }

    public static ControlBoxes GetControlBoxes(DependencyObject dp)
    {
      return (ControlBoxes)dp.GetValue(ControlBoxesProperty);
    }

    static void controlBoxesChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
    {
      var window = o as Window;
      if (window == null)
        return;

      var cb = (ControlBoxes)e.NewValue;

      if (!window.IsLoaded)
        window.Loaded += (sender, ea) => updateStyleOfWindow(cb, window);
      else
        updateStyleOfWindow(cb, window);
    }

    static void updateStyleOfWindow(ControlBoxes cb, Window window)
    {
      var hwndSrc = PresentationSource.FromVisual(window) as HwndSource;
      var hwnd = hwndSrc.Handle;
      var flags = GetWindowLong(hwnd, GWL_STYLE);
      var newFlags = updateFlags(cb, flags);
      if (flags != newFlags)
        SetWindowLong(hwnd, GWL_STYLE, newFlags);
    }

    static uint updateFlags(ControlBoxes cb, uint flags)
    {
      if (cb.HasFlag(ControlBoxes.Minimize))
        flags |= WS_MINIMIZEBOX;
      else
        flags &= ~WS_MINIMIZEBOX;

      if (cb.HasFlag(ControlBoxes.Maximize))
        flags |= WS_MAXIMIZEBOX;
      else
        flags &= ~WS_MAXIMIZEBOX;

      if (cb.HasFlag(ControlBoxes.Control))
        flags |= WS_SYSMENU;
      else
        flags &= ~WS_SYSMENU;

      return flags;
    }

    const uint WS_SYSMENU = 0x00080000;
    const uint WS_MINIMIZEBOX = 0x00020000;
    const uint WS_MAXIMIZEBOX = 0x00010000;

    const int GWL_STYLE = -16;

    [DllImport("user32")]
    private static extern uint GetWindowLong(IntPtr hWnd, int index);

    [DllImport("user32")]
    private static extern uint SetWindowLong(IntPtr hWnd, int index, uint dwLong);
  }

  [Flags]
  public enum ControlBoxes
  {
    None = 0,
    Maximize = 1,
    Minimize = 2,
    Control = 4
  }
}