WindowChrome クラス

Last Updated 2011/09/21


"WPF Shell Integration Library" が公開されています。このページではこのライブラリに含まれる WindowChrome クラスについて解説します。なお、クラスの個々のプロパティやメソッドの解説はしませんが、そのかわり私が公開中の WPF クラスライブラリリファレンスをご覧ください。


"WPF Shell Integration Library" とは何か

.Net Framework の機能の中で欠けているものの一つは、Windows シェル関係の機能です。Microsoft がなかなか公開したがらない理由は分かりませんが、小出しにはしています。

Note Windows シェル機能の中でほしいものとして、「ゴミ箱」やショートカットリンクの作成などがあります。Windows API 関数を直接呼び出せば可能なものはありますが、.Net Framework の中に入れて欲しいですね。

Windows 7 のシェル機能のタスクバー関係およびジャンプリスト関係は .Net Framework 4.0 に追加されました。しかし、Windows Chrome 関係がまだ追加されていません。つまり、このライブラリは WindowChrome クラスを中心とする機能を含むものです。

"WPF Shell Integration Library" は、.Net Framework 3.5 対応ですので、Visual Studio 2008 で使うことができます。.Net Framework 4.0 SP1 には追加されることを望みたいと思います。

"WPF Shell Integration Library" の入手方法

次のサイトに入って、[Downloads] のページからダウンロードできます。ソースファイルも含みます。

http://code.msdn.microsoft.com/WPFShell

WindowChrome クラスのリファレンスマニュアル

上記のライブラリにはマニュアルが含まれていませんが、Microsoft のサイトでは公開されています。以下のサイトのタイトルは "Microsoft Ribbon for WPF リファレンス" となっていますが、Microsoft.Windows.Shell 名前空間の中にあります。ただし、解説文の質はよくありません。

http://msdn.microsoft.com/ja-jp/library/ff806375.aspx

日本語版のリファレンスマニュアルは私が公開している WPF クラスライブラリリファレンスを参照してください。

WindowChrome クラスの役割

"chrome" の英語としての意味は、「クロームメッキ」のそれしかありません。しかし、Windows 用語としては、「非クライアント領域」をさす言葉として使うようです。どうも納得できかねますが。

下図は標準のウインドウ(フォーム)ですが、「クライアント領域」と表記した範囲以外が非クライアント領域ということになります。

StandardWindow

アプリケーション側から操作できるのは「クライアント領域」の範囲内のみです。したがって、クライアント "client" とはアプリケーションまたはアプリケーション作成者と考えていいでしょう。非クライアント領域は OS としての Windows だけが操作可能で以下にリストアップする機能を提供します。

非クライアント領域をアプリケーションから直接操作するためには特別なテクニックを駆使しなければなりませんが、WindowChrome クラスを使えば比較的簡単に実現することができます。

グラスフレーム "Glass Frame"

Windows Vista または 7 を使っている人にはおなじみですが、ウインドウのタイトルバーのあたりが半透明になっていて背景が少し透けて見えるはずです。これがガラスのように見えるので、グラスフレーム "glass frame" と呼びます。

Microsoft はグラスフレームを使う効果として、ユーザーにとって重要でない部分をぼんやりさせることで集中すべき部分(クライアント領域)への集中が高まる効果があるとしています。本当にそうかどうかは分かりませんが。

さて、ウインドウ(フォーム)全体をグラス風にするには WindowChrome クラスの GlassFrameThickness プロパティに負数を設定します。以下のコードの実行結果は下図を見てのとおりですが、最小化、最大化、閉じるボタンなどは通常のウインドウと同様に使えますし、タイトルバー上をマウスでドラッグするとウインドウを移動することができます。アプリケーションアイコンを表示するためにはアプリケーション側で対処しなければなりませんが、これを否定的に解釈すべきではありません。つまり、アプリケーション側で自由に設定できると理解すべきです。このあたりをカスタマイズする手順は次の項目で取り上げます。

GlassFrame1

<Window x:Class="WindowChromeTest.GlassFrame1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:shell="http://schemas.microsoft.com/winfx/2006/xaml/presentation/shell"
    xmlns:local="clr-namespace:WindowChromeTest"
    Title="GlassFrame1" Height="200" Width="200">
  <Window.Style>
    <Style TargetType="Window">
      <Setter Property="shell:WindowChrome.WindowChrome">
        <Setter.Value>
          <shell:WindowChrome GlassFrameThickness="-1" /> <!-- 注目 -->
        </Setter.Value>
      </Setter>
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="{x:Type local:GlassFrame1}">
            <Grid>
              <ContentPresenter Margin="{Binding Source={x:Static shell:SystemParameters2.Current},
                                                 Path=WindowNonClientFrameThickness}"
                                Content="{TemplateBinding Content}" />
            </Grid>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
  </Window.Style>
</Window>

前の例では、ウインドウ(フォーム)全体をグラス風にしましたが、次はグラスフレーム上にコントロールを配置する例を示します。ウインドウの Background プロパティに Beige を設定しているにもかかわらずクライアント領域の背景色が黒色になっている点に留意してください。

GlassFrame2

<Window x:Class="WindowChromeTest.GlassFrame1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:shell="http://schemas.microsoft.com/winfx/2006/xaml/presentation/shell"
    xmlns:local="clr-namespace:WindowChromeTest"
    Title="GlassFrame1" Height="200" Width="200" Background="Beige"> ← 注意
  <Window.Style>
    <Style TargetType="Window">
      <Setter Property="shell:WindowChrome.WindowChrome">
        <Setter.Value>
          <shell:WindowChrome GlassFrameThickness="10,60,10,40" />
        </Setter.Value>
      </Setter>
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="{x:Type local:GlassFrame1}">
            <Grid>
              <ContentPresenter Margin="{Binding Source={x:Static shell:SystemParameters2.Current},
                                                 Path=WindowNonClientFrameThickness}"
                                Content="{TemplateBinding Content}" />
            </Grid>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
  </Window.Style>

  <DockPanel>
    <Button Width="80" Height="26" DockPanel.Dock="Top" HorizontalAlignment="Left">button1</Button>
    <TextBlock DockPanel.Dock="Bottom">TextBlock</TextBlock>
    <Grid Margin="4"></Grid>
  </DockPanel>
</Window>

WindowChrome クラスが内部的に何をやっているのかが分かりませんので、確信はありませんが、GlassFrameThickness プロパティは通常のウインドウ(フォーム)の境界線の太さを設定するということではないと想像します。 WindowChrome クラスの機能は、「ウインドウの非クライアント領域をカスタマイズするためのクラス」と理解していますが、実際の動作はそうではないのかもしれません。

Note WindowChrome クラスのソースコードは公開されていますが、内部的には Windows の機能を呼び出しているので、結局、何をやっているかは不明ということになります。

要するに、WindowChrome クラスはウインドウ(フォーム)全体をクライアント領域化し、どこにでも自由にコントロールを配置できるようにするが、 GlassFrameThickness プロパティの設定に応じてグラス風に背景色を描画する、と考えるほうが理解しやすいと思います。つまり、GlassFrameThickness プロパティには常に負数(-1)を設定し、あとは通常のウインドウ(フォーム)のときと同じ手順でコントロールを配置するということです。

非クライアント領域のカスタマイズ

下図は、よくある Windows アプリケーションの例です、これを好まない人は多いですね。つまり、お決まりの形と薄いグレーのコントロールが Windows くさくていやだというわけです。アメリカ映画などでパソコンの画面が出てくる場面を見ると、OS は Windows にもかかわらず、Windows らしくない画面にしていることがあります。見ただけで Windows と思われたくないのでしょう。Microsoft は WPF を次世代の Windows アプリケーションの標準ツールにすると発表しているところをみると、Microsoft も同じ思いなのでしょう。そこで、非クライアント領域を自由にカスタマイズできる手段を提供することになりました。それが WindowChrome クラスです。

GlassFrame3

実用的な WPF アプリケーションはいまだ(2010 年 中頃)公開されていませんが、サンプルアプリケーションの多くは基調の色として黒を採用しています。 Windows Vista に付属の Windows ムービーメーカーやフォトギャラリーなどもそうです。そこでまねをしてみました。なお、境界線の色などにおかしな色を使っていますが、コードの内容を分かりやすくするための工夫です。ご了承ください

GlassFrame4

さて、プロジェクトは Visual Studio 2008 で作成し、WindowChrome クラスだけでなく、以下のクラスも使っています。つまり、これらのクラスは WindowChrome クラスのために用意されたものと考えられるからです。

なお、ここではコードを示しませんが、キャプションボタン(最小化、最大化、閉じるボタン)はカスタムコントロールとして作成しました。

<Window x:Class="WindowChromeTest.GlassFrame2"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:shell="http://schemas.microsoft.com/winfx/2006/xaml/presentation/shell"
    xmlns:local="clr-namespace:WindowChromeTest"
    Name="glassFrame2" Title="GlassFrame2" Height="200" Width="300" Icon="images/Computer.ico">

  <!-- コマンドは分離コードから呼び出す -->
  <Window.CommandBindings>
    <CommandBinding Command="{x:Static shell:SystemCommands.CloseWindowCommand}"
                    Executed="closeCommand_Executed"/>
    <CommandBinding Command="{x:Static shell:SystemCommands.MaximizeWindowCommand}"
                    Executed="maximizeWindow_Executed"/>
    <CommandBinding Command="{x:Static shell:SystemCommands.MinimizeWindowCommand}"
                    Executed="minimizeWindow_Executed"/>
    <CommandBinding Command="{x:Static shell:SystemCommands.RestoreWindowCommand}"
                    Executed="restoreWindow_Executed"/>
  </Window.CommandBindings>

  <Window.Style>
    <Style TargetType="{x:Type local:GlassFrame2}">
      <Setter Property="shell:WindowChrome.WindowChrome">
        <Setter.Value>
          <shell:WindowChrome GlassFrameThickness="1" /> ← 注意(0 にすると、ウインドウの周囲の影が描画されない)
        </Setter.Value>
      </Setter>

      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="{x:Type local:GlassFrame2}">
            <Grid>
              <Border BorderThickness="6" BorderBrush="Red">
                <Border.Background>
                  <LinearGradientBrush StartPoint="0,0" EndPoint="0,50" MappingMode="Absolute">
                    <GradientStop Offset="0" Color="DimGray"/>
                    <GradientStop Offset="1" Color="Black"/>
                  </LinearGradientBrush>
                </Border.Background>
                <ContentPresenter Margin="0" Content="{TemplateBinding Content}"/>
              </Border>
              <!-- ウインドウのアイコン(システムメニューを表示する) -->
              <Image Name="image1" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="6,6,0,0"
                     Source="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Icon}"
                     Width="24" Height="24" MouseLeftButtonDown="image1_MouseDown"
                     shell:WindowChrome.IsHitTestVisibleInChrome="True" />

              <!-- Title プロパティを表示する -->
              <TextBlock HorizontalAlignment="Left" VerticalAlignment="Top" Margin="34,8,0,0" Foreground="White"
                         Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Title}" />

              <!-- 最小化、最大化、閉じるボタン -->
              <StackPanel Orientation="Horizontal" Margin="0,6,6,0" HorizontalAlignment="Right" VerticalAlignment="Top">
                <Button Style="{StaticResource BlackButtonStyle}" shell:WindowChrome.IsHitTestVisibleInChrome="True"
                        Command="{x:Static shell:SystemCommands.MinimizeWindowCommand}"
                        CommandParameter="{Binding ElementName=glassFrame2}">
                  <Image Source="images/IconMinMark.png" Stretch="None" HorizontalAlignment="Center" VerticalAlignment="Bottom" />
                </Button>
                <Button Style="{StaticResource BlackButtonStyle}"
                        shell:WindowChrome.IsHitTestVisibleInChrome="True"
                        Command="{x:Static shell:SystemCommands.MaximizeWindowCommand}"
                        CommandParameter="{Binding ElementName=glassFrame2}">
                  <Image Source="images/IconMaxMark.png" Stretch="None" />
                </Button>
                <Button Style="{StaticResource BlackButtonStyle}" shell:WindowChrome.IsHitTestVisibleInChrome="True"
                        Command="{x:Static shell:SystemCommands.CloseWindowCommand}"
                        CommandParameter="{Binding ElementName=glassFrame2}">
                  <Image Source="images/IconCloseMark.png" Stretch="None" />
                </Button>
              </StackPanel>
            </Grid>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
  </Window.Style>

  <DockPanel Margin="{Binding Source={x:Static shell:SystemParameters2.Current},
                              Path=WindowNonClientFrameThickness}">
    <Button Name="btnClose" Width="80" Height="26" DockPanel.Dock="Top" HorizontalAlignment="Left" Click="btnClose_Click" >閉じる</Button>
    <TextBlock DockPanel.Dock="Bottom" Foreground="White">TextBlock</TextBlock>
    <Grid Margin="4" Background="Aquamarine"></Grid>
  </DockPanel>
</Window>

WindowChromeTest.lzh (132,629 bytes)

−以上−