2010年4月19日月曜日

第32回 Windowを透過にする

今回はデザインを大幅に変えてみたいと思います。
こんなかんじ。(アイコンは一応?ぼかしています)
背景が銀色ではなくて、背景は透過でデスクトップの壁紙が見えています。

変更箇所が多すぎて全部網羅して書けないので、要所だけでも。

■Windowを透明にする
Windowのプロパティを、
WindowStyleをNoneにして
AllowsTransparencyをTrueにした上で、
BackgroundをTransparentにします。
直接指定してもいいですが、あとでノーマルな表示との切り替えができる作りにしやすいように、
Styleで指定しておきます。
(Templateはあとで説明します)


 <Style x:Key="WindowStyle" TargetType="{x:Type Window}">
  <Setter Property="Template" Value="{DynamicResource WindowTemplate}"/>
  <Setter Property="WindowStyle" Value="None"/>
  <Setter Property="Background" Value="Transparent"/>
  <Setter Property="AllowsTransparency" Value="True"/>
 </Style>


詳しくはMSDNのWindowのあたりでも。

■タイトルバーを作る
WindowStyleをNoneにしたらタイトルバーまでなくなってしまいます。
ですが、AllowsTransparencyをTrueにしたらタイトルバーを残す方法は無いようです。(たぶん)
というわけで、自力で作ります。



<UserControl x:Class="WTwitter.View.Parts.TitlebarView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:root="clr-namespace:WTwitter"
 xmlns:util="clr-namespace:WTwitter.ViewModel.Utility">
 <DockPanel Background="{DynamicResource TitlebarBackground}">
  <!--左端のアプリのアイコン-->
  <Image Source="{DynamicResource AppImage}" Width="16" Height="16" DockPanel.Dock="Left"/>
  <!--閉じるボタン-->
  <Button DockPanel.Dock="Right" Command="{Binding Path=CloseCommand}" Foreground="White"
    Background="{DynamicResource CloseButtonBackground}"
    Margin="5,0,0,0" Width="25" Height="20" HorizontalContentAlignment="Center" VerticalContentAlignment="Center">
   X</Button>
  <!--オプション画面を開くボタン-->
  <Button Command="{Binding Path=OptionDialogCommand}" DockPanel.Dock="Right"
    Style="{DynamicResource ImageButtonStyle}" Margin="3,1">
   <Image Source="{DynamicResource SettingImage}" Height="16" Width="16"/>
   <Button.ToolTip>設定</Button.ToolTip>
  </Button>
  <!--TwitterのHOMEをブラウザで開くボタン-->
  <Button Command="{x:Static util:CommonCommands.OpenByBrowser}" CommandParameter="http://twitter.com"
    DockPanel.Dock="Right" Style="{DynamicResource ImageButtonStyle}" Margin="3,1">
   <Image Source="{DynamicResource TwitterHomeImage}" Height="16" Width="16"/>
   <Button.ToolTip>TwitterHomeをブラウザで開く</Button.ToolTip>
  </Button>
  <!--タイトルバーのタイトルテキスト-->
  <TextBlock Text="{Binding Path=DisplayName}" Foreground="White" Margin="2"/>
  
  <!--右クリックメニュー-->
  <DockPanel.ContextMenu>
   <ContextMenu>
    <MenuItem Header="最前面に表示(_T)" IsCheckable="True"
        IsChecked="{Binding Source={x:Static root:App.Current}, Path=MainWindow.Topmost, Mode=TwoWay}"/>
   </ContextMenu>
  </DockPanel.ContextMenu>
 </DockPanel>
</UserControl>

ボタンいくつか乗っけたのと、DynamicResourceやらを多用しているので長く見えますが、
基本は横長のバーを表示してタイトル文字列と閉じるボタンをおきたいだけなので、構造は簡単です。



最後にTemplateで作ったタイトルバーとStyleを組み合わせています。
(上のほうで紹介したStyleで指定しています)


 <ControlTemplate x:Key="WindowTemplate" TargetType="{x:Type Window}">
  <DockPanel Background="Transparent">
   <parts:TitlebarView DockPanel.Dock="Top"/>
   <ContentControl Content="{TemplateBinding Property=Content}" Background="Transparent"/>
  </DockPanel>
 </ControlTemplate>



■タイトルバードラッグでのWindowの移動
Windowの枠を無くしちゃったので、
そのままだとWindowの位置を変更する手段がなくなります。
WindowのMouseLeftButtonイベントでDragMove()を呼び出すだけです。
正確にはWindowに書いちゃったので、タイトルバーだけではなく余白領域でも移動します。
(ただ、今の私の実装は余白は透明にしているのでマウスクリックを検知しません。)



  private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
   DragMove();
  }



■Windowのサイズの変更
同様に、枠がなくなるのでそのままではWindowのサイズを変更できなくなります。
これはWindowの上にResizeGripを置くだけで勝手にやってくれるようです。
Gridの上に置いているので、他のコンテンツの上に重ねることができます。
そしてAlignmentでGridの右下に来るようにしています。


  <ResizeGrip HorizontalAlignment="Right" VerticalAlignment="Bottom" Width="3" Height="3" />

あとはMainWindowにResizeMode="CanResizeWithGrip"を設定しておいてください。


■Controlの背景とか
Windowは透明にできたので、あとは上に乗せるものも必要に応じて透明にしていきます。
簡単にあとから変更や調整ができるように、Colors.xamlというファイルに
色の定義をまとめておきます。
以下サンプル。


 <SolidColorBrush x:Key="HitVisibleTransparentBrush">
  <SolidColorBrush.Color>White</SolidColorBrush.Color>
  <SolidColorBrush.Opacity>0.01</SolidColorBrush.Opacity>
 </SolidColorBrush>

 <SolidColorBrush x:Key="MouseOverBackgroundBrush">
  <SolidColorBrush.Color>LightBlue</SolidColorBrush.Color>
  <SolidColorBrush.Opacity>0.5</SolidColorBrush.Opacity>
 </SolidColorBrush>

Opacityで透明度を指定します。

■xamlファイルの配置
プロジェクトに追加されたxamlファイルは
デフォルトではコンパイルされてexeファイルの中にデータが埋め込まれます。
プロパティ(Visual Studio上ソリューションエクスプローラでxamlファイルを右クリック)で
ビルドアクション→コンテンツ、出力ディレクトリ→コピーするを選ぶと
コンパイルされずそのままテキストファイルでbinフォルダのしたに出力されます。
これでxamlファイルをユーザーが修正しても起動時に読み込んで反映されます。
ただし実行時にxamlを解析するためパフォーマンスは落ちます。
あとはApp.xaml.csとかで実行時に読み込みます。

Visual Studioのプロジェクトに取り込んでいないファイルに対しては
動的な読込自体はこれまでも使っていましたが、
Visual Studioに取り込むことにより、DebugビルドとReleaseビルド用に
2回コピーしなくてすみます。(これまで知りませんでした。すみません。)

ここまでのソース
http://wtwitter.codeplex.com/SourceControl/changeset/changes/45389

書いてないことでわからないことがあれば遠慮無く質問を。

注:
Styleとかはファイルの分け方などが安定していないので、
2~3回あとのソースコードを待った方が整理されているかもしれません。

1 件のコメント:

  1. メモ:
    ボタンのStyleのXAMLでのカスタマイズ方法を見つけました
    http://msdn.microsoft.com/ja-jp/library/bb613545.aspx

    返信削除