読者です 読者をやめる 読者になる 読者になる

開発備忘録

WPF(Xaml + C#)の話題を中心に.Net関連についてのブログです。

WindowChromeを使用した独自ウィンドウの作成

WPFでウィンドウを独自に作成したい場合は、自分でWindowのControlTemplateをゴリゴリ作るのも楽しいのですが、もう少し簡単に実現したい時、WindowChromeを使用するといいと思います。

WindowChromeとは?

WindowChromeは、Windowの非クライアント領域にWindowのContentを拡張するための仕組みです。

MDSN : WindowChrome クラス (System.Windows.Shell)

 

通常、Windowにはタイトルバーや閉じるボタンが配置されている非クライアント領域と、その内側のクライアント領域があります。

Windowにコントロールを配置するときは、このクライアント領域に配置しますよね。

で、WindowChromeはこのクライアント領域を拡大してくれる仕組みを持っています。

 

説明ばかりではわかりにくいので実際に作ってみましょう。

 

WindowChromeを使う

まずは通常のWindowを用意

<Window x:Name="window" x:Class="WindowChromeSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
    	<Grid.RowDefinitions>
    		<RowDefinition Height="Auto"/>
    		<RowDefinition/>
    	</Grid.RowDefinitions>
    	<DockPanel>
    		<TextBlock Text="{Binding Title, ElementName=window, Mode=OneWay}" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="6,3,12,3" FontSize="14.667" />
    		<Button Content="✕" Width="24" Height="24" HorizontalAlignment="Right" Background="Red" BorderThickness="0" Foreground="White"/> 
    	</DockPanel>
        
    </Grid>
</Window>

 これを実行すると以下の様なウィンドウが表示されます。

f:id:iyemon018:20150913214225p:plain

 このウィンドウにStyleを追加し、プロパティ"WindowChrome.WindowChrome"を設定します。

< Generic.xaml >

<ResourceDictionary
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:System="clr-namespace:System;assembly=mscorlib">
    <!-- リソース ディクショナリのエントリはここで定義します。-->
    <System:Double x:Key="CaptionHeight">26</System:Double>
    <Style TargetType="{x:Type Window}" x:Key="DefaultWindowStyle">
        <Setter Property="WindowChrome.WindowChrome">
            <Setter.Value>
                <WindowChrome CornerRadius="3" GlassFrameThickness="1" ResizeBorderThickness="8" UseAeroCaptionButtons="False" CaptionHeight="{DynamicResource CaptionHeight}" />
            </Setter.Value>
        </Setter>
        <Setter Property="SnapsToDevicePixels" Value="True"/>
        <Setter Property="UseLayoutRounding" Value="True"/>
        <Setter Property="Background" Value="#FF494949"/>
        <Setter Property="BorderBrush" Value="#FF14A9FF"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="Foreground" Value="White"/>
    </Style>
</ResourceDictionary>

 

< MainWindow.xaml >

<Window x:Name="window" x:Class="WindowChromeSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525" Style="{DynamicResource DefaultWindowStyle}">
    <Grid>
    	<Grid.RowDefinitions>
    		<RowDefinition Height="Auto"/>
    		<RowDefinition/>
    	</Grid.RowDefinitions>
    	<DockPanel>
    		<TextBlock Text="{Binding Title, ElementName=window, Mode=OneWay}" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="6,3,12,3" FontSize="14.667" />
    		<Button Content="✕" Width="24" Height="24" HorizontalAlignment="Right" Background="Red" BorderThickness="0" Foreground="White" WindowChrome.IsHitTestVisibleInChrome="True"/> 
    	</DockPanel>
        
    </Grid>
</Window>

 

これを実行した結果がこちら

f:id:iyemon018:20150913214600p:plain

 あとはタイトルバーに最大化ボタンや最小化ボタンを配置すると独自ウィンドウの完成です。

仕事で時々閉じるボタンを非表示にしてくれと言われることがあるので、そんな時は便利そうですね。

CaptionHeight を設定しておけばウィンドウのドラッグ移動や最大化もできます。

また、これを利用するとWindows10ライクなWindowも作成できそうです。

 

ちなみに、キャプションエリアにコントロールを配置した場合、そのままではコントロールをクリックすることはできません。

今回の場合、WindowChrome.CaptionHeight を26に設定しています。

この問題を解決するには、キャプションエリアに配置したコントロールにWindowChromeの添付プロパティ"WindowChrome.IsHitTestVisibleInChrome"にtrueを設定することで対応できます。

上記の場合、

<Button Content="✕" Width="24" Height="24" HorizontalAlignment="Right" Background="Red" BorderThickness="0" Foreground="White" WindowChrome.IsHitTestVisibleInChrome="True"/>

です。

 

WindowChromeの問題点

一見便利そうなWindowChromeにも問題点はあります。

 

・最大化した時にデスクトップのクライアント領域を超える。

・SizeToContent=WidthAndHeight にすると現れる謎の黒い領域

 

次回はこの辺りの対策を紹介したいと思います。

 

 サンプルはこちらから

github.com