Help us understand the problem. What is going on with this article?

[C# / WPF] WindowChromeを利用したカスタムウィンドウで、Window.ResizeModeと連動するキャプションボタンを作ってみよう

More than 3 years have passed since last update.

ニアです、こんにちはー!

今回は、Window.Chromeクラスを利用したカスタムウィンドウ用のキャプションボタン(最小化・最大化・閉じるボタン)を、WindowクラスにあるResizeModeプロパティと連動させる方法を紹介していきます。

cc-00.png

1. Window.ResizeModeとは

WindowクラスにあるResizeModeプロパティは、ウィンドウのサイズ変更の可否を設定するものであり、4種類のオプションがあります。

ResizeMode ウィンドウのサイズ変更 最小化・最大化ボタン
NoResize 不可 非表示 cc-02.PNG
CanMinimize 不可 表示(但し、最大化ボタンは無効) cc-03.PNG
CanResize 表示 cc-04.PNG
CanResizeWithGrip 可(右下にリサイズグリップが表示) 表示 cc-05.PNG

2. Window.ResizeModeとデータバインディング

ボタンの表示・非表示はVisibilityプロパティで、有効・無効はIsEnabledプロパティで設定することができます。すなわち、ResizeModeがNoResizeの時は、最小化・最大化ボタンのVisibilityをCollapsedに、CanMinimizeの時は、最大化ボタンのIsEnabledをfalseにすればよいのです。

ということで、ボタンのVisibility及びIsEnabledをウィンドウのResizeModeとデータバインディングをする方法で実装していきます。

cc-06.png

2.1. Converterクラスの作成

まず、ResizeModeの値からVisibility及びIsEnabledの値に変換するConverterクラスを作成します。

Converterクラス名 ターゲット 変換後の値
ResizeCaptionButtonVisibilityConverter Button.Visibility ResizeModeがNoResizeの時はCollapsed、それ以外の時はVisible
MaximizeCaptionButtonEnableConverter Button.IsEnabled ResizeModeがCanMinimizeの時はfalse、それ以外の時はtrue
CaptionButtonConverter.cs
using System;
using System.Windows;
using System.Windows.Data;
using System.Globalization;

namespace CustomCaption {

    /// <summary>
    ///     ウィンドウのリサイズモードに応じて最大化・最小化ボタンの表示・非表示を設定します。
    /// </summary>
    public sealed class ResizeCaptionButtonVisibilityConverter : IValueConverter {
        public object Convert( object value, Type targetType, object parameter, CultureInfo culture ) =>
            // ResizeModeがNoResizeの時はVisibility.Collapsedに、それ以外の時はVisibility.Visibleにします。
            value is ResizeMode && ( ResizeMode )value != ResizeMode.NoResize ? Visibility.Visible : Visibility.Collapsed;

        public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture ) => null;
    }

    /// <summary>
    ///     ウィンドウのリサイズモードに応じて最大化ボタンの有効・無効を設定します。
    /// </summary>
    public sealed class MaximizeCaptionButtonEnableConverter : IValueConverter {
        public object Convert( object value, Type targetType, object parameter, CultureInfo culture ) =>
            // ResizeModeがCanMinimizeの時はfalseに、それ以外の時はtrueにします。
            value is ResizeMode && ( ResizeMode )value != ResizeMode.CanMinimize;

        public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture ) => null;
    }

    // ...

}

※ボタンからWindow.ResizeModeへの設定はしないので、ConvertBackは使用しません。

2.2. 最小化・最大化ボタンにデータバインディング

次に、XAMLで最小化・最大化ボタンとWindow.ResizeModeを先ほど作成したConverterクラスを使ってバインディングします。

先ほど作成したConverterクラスをWindow.Resoursesに登録します。

Window.Resources
<!-- Windowに名前空間 xmlns:local="clr-namespace:CustomCaption" が定義されているとします。 -->
<Window.Resources>
        <!-- Converter -->
        <local:MaximizeCaptionButtonEnableConverter x:Key="MaximizeCaptionButtonEnableConverterKey"/>
        <local:ResizeCaptionButtonVisibilityConverter x:Key="ResizeCaptionButtonVisibilityConverterKey"/>
</Window.Resources>

最小化ボタンのVisibilityをResizeModeとバインディングし、ConverterにはResizeCaptionButtonVisibilityConverterを、ElementNameにはウィンドウの名前(MainWindow1)を設定します。

最小化ボタン
<!-- Windowの名前(x:Name)が MainWindow1 であるとします。 -->
<Button Content="0"
        Style="{StaticResource CustomCaptionButtonKey}"
        Visibility="{Binding ResizeMode, Converter={StaticResource ResizeCaptionButtonVisibilityConverterKey}, ElementName=MainWindow1}"
        ToolTip="最小化"
        Command="{x:Static SystemCommands.MinimizeWindowCommand}" />

最小化ボタンでは、Visibility及びResizeModeとバインディングし、ElementNameにはウィンドウの名前(MainWindow1)を設定します。Converterには、Visibility側はResizeCaptionButtonVisibilityConverterを、IsEnabled側はMaximizeCaptionButtonEnableConverterを設定します。

最大化ボタン
<!-- Windowの名前(x:Name)が MainWindow1 であるとします。 -->
<Button Content="{Binding WindowState,Converter={StaticResource MaximizeCaptionButtonContentConverterKey}, ElementName=MainWindow1}"
        Style="{StaticResource CustomCaptionButtonKey}"
        IsEnabled="{Binding ResizeMode, Converter={StaticResource MaximizeCaptionButtonEnableConverterKey}, ElementName=MainWindow1}"
        Visibility="{Binding ResizeMode, Converter={StaticResource ResizeCaptionButtonVisibilityConverterKey}, ElementName=MainWindow1}"
        ToolTip="{Binding WindowState, Converter={StaticResource MaximizeCaptionButtonTooltipConverter}, ElementName=MainWindow1}"
        Command="{x:Static SystemCommands.MaximizeWindowCommand}"/>

これで、Window.ResizeModeと連動するキャプションボタンの出来上がりです。

Window.ResizeMode 通常のウィンドウ カスタムウィンドウ
NoResize cc-02.PNG cc-07.PNG
CanMinimize cc-03.PNG cc-08.PNG
CanResize cc-04.PNG cc-09.PNG
CanResizeWithGrip cc-05.PNG cc-10.PNG

3. おわりに

今回作成したカスタムウィンドウのプログラムは、Gistにアップしておきます。
https://gist.github.com/Nia-TN1012/e9207e7fe02d046b3d4d

そのプログラムでは、今回扱った「キャプションボタンをWindow.ResizeModeと連動させる方法」の他に、最大化ボタンの表示文字列とツールチップをウィンドウの最大化状態と連動させたり、タイトルバーの色をウィンドウのアクティブ状態と連動させたりしています。いずれも、Converterクラスを使ったデータバインディングで実装することができます。

それでは、See you next time!

追記(2016/03/25)

Gistにアップしていたプログラムですが、キャプションボタンのスタイルを設定しているリソースディクショナリーのファイルをアップし忘れていましたので、追加しました。
ご不便をおかけしたことをお詫び申し上げます。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away