Livetを使ったC#のWindowChromeプログラミング

高い表現力のWindowChromeを使うための準備を紹介します


1.DashboardSampleの移植


DashboardSample

WPFのサンプルは、Googleで、「WPF Sample Download」と入力して検索するいろいろと表示されます。
その中で見つけたのが、下記のサイトのDashboardSampleです。

「Building Dashboards With WPF Elements Part 3: Getting Started」

DashboardSample (クリックすると拡大)

下の方のYou can download the Visual Studio 2010 solution of where we are at so far from here.をクリックしますとDashboardSample_Part3.zipのダウンロードが開始されます。
解凍するとDashboardSampleというファイル(ソリューション)が出来ます。


移植

Caliburnという開発者のライブラリ(dll)を使用しますが、これはDashboardView.xamlというZAMLのみが使用可能になっています。
これを汎用化する為に、1.WindowCromeのプロジェクトにWindow3.xamlを作って、DashboardView.xamlのコードを一部修正してコピーしました。
又、DashboardViewModel.csとPropertyChangedBase.csはコピーしました。


Window3.xamlは下記の通りです。116~304行がCopyです。但し、129行目のtxtTitleへの変更や296~299のtxt本日の追加は修正箇所です。


View
<ccl:CustomChromeWindow 
 x:Class="LivetWPFApplicationChrome1.Views.Window3"
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
 xmlns:shell="http://schemas.microsoft.com/winfx/2006/xaml/presentation/shell"   
 xmlns:ccl="clr-namespace:CustomChromeLibrary;assembly=CustomChromeLibrary"                        
 xmlns:local="clr-namespace:LivetWPFApplicationChrome1"               
 xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
 xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
 xmlns:l="http://schemas.livet-mvvm.net/2011/wpf"
 xmlns:core="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=
	Microsoft.Expression.Interactions"      
 xmlns:v="clr-namespace:LivetWPFApplicationChrome1.Views"
 xmlns:vm="clr-namespace:LivetWPFApplicationChrome1.ViewModels"
 WindowStartupLocation="CenterScreen"
 mc:Ignorable="d" 
 d:DesignHeight="714" d:DesignWidth="1035" Background="Black"
 Height="714" Width="1035"
 Title="Window3" >

    <Window.DataContext>
        <vm:ViewModel3/>
    </Window.DataContext>

    <shell:WindowChrome.WindowChrome>
        <shell:WindowChrome
            ResizeBorderThickness="6"
            CaptionHeight="43"
            CornerRadius="0,0,0,0"
            GlassFrameThickness="0">
        </shell:WindowChrome>
    </shell:WindowChrome.WindowChrome>

    <Window.Resources>
        <ResourceDictionary>
            <vm:CaptionButtonRectToMarginConverter x:Key=
            	"CaptionButtonMarginConverter"/>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="../Resources\GlassButton.xaml"/>
                <ResourceDictionary Source="../Resources\GlassIcon.xaml"/>
                <ResourceDictionary Source="/Resources/Styles.xaml"/>
                <ResourceDictionary Source="/Resources/Styles2.xaml"/>
                <ResourceDictionary Source="/Resources/StylesBG.xaml"/>
                <ResourceDictionary Source="/Resources/FilterButtonStyle.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>

    <i:Interaction.Triggers>
        <!--WindowのContentRenderedイベントのタイミングでViewModelのInitialize
        	呼ばれます-->
        <i:EventTrigger EventName="ContentRendered">
            <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName=
            	"Initialize"/>
        </i:EventTrigger>

        <l:InteractionMessageTrigger 
            MessageKey="MessageKey2" Messenger="{Binding Messenger}">
            <l:TransitionInteractionMessageAction
                WindowType="{x:Type v:Window2}" Mode="Modal"/>
        </l:InteractionMessageTrigger>

        <!-- 下記がないと、タスクバーが1つにならない -->
        <i:EventTrigger EventName="Loaded">
            <i:InvokeCommandAction Command="{Binding Path=Loaded}" 
                                   CommandParameter="{Binding Mode=OneTime,
                                   RelativeSource={RelativeSource Mode=
                                   FindAncestor,AncestorType={x:Type Window}}}"/>
        </i:EventTrigger>

        <i:EventTrigger EventName="Closing">
            <i:InvokeCommandAction Command="{Binding Path=Closing}"
                                   CommandParameter="{Binding Mode=OneTime,
                                   RelativeSource={RelativeSource Mode=
                                   FindAncestor,AncestorType={x:Type Window}}}"/>
        </i:EventTrigger>

        <l:InteractionMessageTrigger MessageKey="Close" Messenger=
        	"{Binding Messenger}">
            <l:WindowInteractionMessageAction/>
        </l:InteractionMessageTrigger>
    </i:Interaction.Triggers>

    <Grid>
        <!-- WindowChrome Start  -->
        <Border  Grid.RowSpan="2" BorderThickness="3" BorderBrush="Black">
            <Border.Background>
                <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                    <GradientStop Color="Black" Offset="0" />
                    <GradientStop Color="Black" Offset="1" />
                </LinearGradientBrush>
            </Border.Background>
        </Border>

        <!--title bar-->
        <Border  BorderThickness="3,3,3,1" BorderBrush="Black" Margin=
        	"{Binding Path=CaptionButtonMargin}">
            <Border.Background>
                <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                    <GradientStop Color="Black" Offset="0" />
                    <GradientStop Color="Black" Offset="1" />
                </LinearGradientBrush>
            </Border.Background>

            <!--Window Icon and Title-->
           <StackPanel Orientation="Horizontal" Margin="0" VerticalAlignment="Top">
             <TextBlock Text="" FontFamily="Calibri" FontWeight="Bold" 
             	FontSize="26" Foreground="Blue" />
           </StackPanel>
        </Border>
        <ccl:CaptionButtons />
        <!-- WindowChrome End  -->

        <Grid Margin="20,0,20,20">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="1*" />
                <RowDefinition Height="2*" />
                <RowDefinition Height="3*" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="649*" />
                <ColumnDefinition Width="92*" />
                <ColumnDefinition Width="232*" />
            </Grid.ColumnDefinitions>
            <StackPanel Orientation="Horizontal" Grid.ColumnSpan="3">
                <TextBlock Text="{Binding Path=txtTitle}"  
                	Style="{StaticResource MainTitleStyle}" 
                		HorizontalAlignment="Left" Margin="0,0,0,8" />
                    <Button Style="{StaticResource FilterButtonStyle}" 
                    	Margin="40,0,0,5">
                    <StackPanel Orientation="Horizontal">
                        <Border Width="20" Height="20" Background=
                        	"{StaticResource ProductColor1}" 
                        		VerticalAlignment="Center" />
                  <TextBlock Text="{x:Static vm:DashboardViewModel.ProductName1}"  
                  	Style="{StaticResource LegendTextStyle}" 
                  		VerticalAlignment="Center" Margin="10,0,0,0" />
                    </StackPanel>
                </Button>

              <Button Style="{StaticResource FilterButtonStyle}" Margin="40,0,0,5">
                    <StackPanel Orientation="Horizontal">
                        <Border Width="20" Height="20" Background=
                        	"{StaticResource ProductColor2}" 
                        		VerticalAlignment="Center" />

                   <TextBlock Text="{x:Static vm:DashboardViewModel.ProductName2}" 
                   	Style="{StaticResource LegendTextStyle}" VerticalAlignment=
                   		"Center" Margin="10,0,0,0" />
                        
                    </StackPanel>
                </Button>

                <Button Style="{StaticResource FilterButtonStyle}" 
                	Margin="40,0,0,5">
                    <StackPanel Orientation="Horizontal">
                        <Border Width="20" Height="20" Background=
                        	"{StaticResource ProductColor3}" 
                        		VerticalAlignment="Center" />
                        <TextBlock Text=
                        	"{x:Static vm:DashboardViewModel.ProductName3}" 
                        		Style="{StaticResource LegendTextStyle}" 
                        		VerticalAlignment="Center" 
                        		Margin="10,0,0,0" />
                    </StackPanel>
                </Button>
                
            </StackPanel>

            <Border Grid.Row="1" Grid.ColumnSpan="3" Background="#0F6FC6">
                <TextBlock Text="Time Explorer" VerticalAlignment="Center" 
                HorizontalAlignment="Center" />
            </Border>

            <Grid Grid.Row="2" SnapsToDevicePixels="True" Margin="0,10,0,10">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="*" />
                </Grid.RowDefinitions>
                <ContentPresenter ContentTemplate=
                "{StaticResource GroupBoxHeaderTemplate}" 
                Content="Product Sales Breakdown" />
                <Border CornerRadius="0,0,10,10" Background=
                "{StaticResource GroupBoxBackground}" Grid.Row="1">
                    <Border Margin="10" Background="#009DD9">
                        <TextBlock Text="Product Breakdown Chart" 
                        VerticalAlignment="Center" HorizontalAlignment="Center" />
                    </Border>
                </Border>
            </Grid>

            <Border Grid.Row="3" Background="#10CF9B">
                <TextBlock Text="Data Grid" VerticalAlignment="Center" 
                HorizontalAlignment="Center" />
            </Border>

            <Border Background="{StaticResource GroupBoxBackground}" 
            CornerRadius="10,10,0,0" Grid.Column="1" Grid.Row="2" 
            Margin="10,10,0,0" SnapsToDevicePixels="True" Grid.ColumnSpan="2">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="*" />
                    </Grid.RowDefinitions>
                    <ContentPresenter ContentTemplate="{StaticResource 
                    GroupBoxHeaderTemplate}" Content="Statistics" />
                    <Border Grid.Row="1" Margin="10,10,10,20" Background="#0BD0D9">
                        <TextBlock Text="Country chart" VerticalAlignment="Center" 
                        HorizontalAlignment="Center" />
                    </Border>
                </Grid>
            </Border>

          <Grid Grid.Column="1" Grid.Row="3" Margin="10,0,0,0" Grid.ColumnSpan="2">
                <Grid.RowDefinitions>
                    <RowDefinition Height="*" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>
                <Border Background="{StaticResource GroupBoxBackground}" 
                CornerRadius="0,0,10,10" SnapsToDevicePixels="True">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="*" />
                        </Grid.RowDefinitions>

                        <StackPanel Orientation="Horizontal">
                            <TextBlock Text="Total Sales" Style=
                            "{StaticResource MainTitleStyle}"  
                            Margin="10,0,20,0" Grid.RowSpan="2" />
                            <TextBlock Text="From" 
                            Style="{StaticResource SecondaryTitleStyle}" 
                            VerticalAlignment="Bottom" Grid.Column="1" 
                            Margin="0,0,0,2" />
                           <TextBlock Style="{StaticResource SecondaryTitleStyle}" 
                            VerticalAlignment="Bottom" Grid.Column="2" 
                            Margin="10,0,20,2" />
                            <TextBlock Text="To" Style=
                            "{StaticResource SecondaryTitleStyle}" 
                            VerticalAlignment="Bottom" Grid.Row="1" Grid.Column="1"
                             Margin="0,0,0,2" />
                            <TextBlock Style="{StaticResource SecondaryTitleStyle}" 
                            VerticalAlignment="Bottom" Grid.Row="1" Grid.Column="2" 
                            Margin="10,0,10,2" />
                        </StackPanel>

                        <Border Grid.Row="1" Margin="10" Height="40" Background=
                        "#0B9B74">
                            <TextBlock Text="Total Sales Display" 
                         VerticalAlignment="Center" HorizontalAlignment="Center" />
                        </Border>

                        <Grid Grid.Row="2" Margin="10">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto" />
                                <RowDefinition Height="*" />
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*" />
                                <ColumnDefinition Width="*" />
                            </Grid.ColumnDefinitions>
                            <TextBlock Text="Year on Year" 
                            Style="{StaticResource SecondaryTitleStyle}" 
                            HorizontalAlignment="Center" />
                            <TextBlock Text="Budgeted" 
                            Style="{StaticResource SecondaryTitleStyle}" 
                            Grid.Column="1" HorizontalAlignment="Center" />
                            <Border Grid.Row="1" Margin="0,0,5,0" 
                            Background="#7CCA62">
                                <TextBlock Text="Radial Gauge" 
                                VerticalAlignment="Center" 
                                HorizontalAlignment="Center" />
                            </Border>
                            <Border Grid.Row="1" Grid.Column="1" 
                            Margin="5,0,0,0" Background="#A5C249">
                                <TextBlock Text="Radial Gauge" 
                                VerticalAlignment="Center" 
                                HorizontalAlignment="Center" />
                            </Border>
                        </Grid>
                    </Grid>
                </Border>
                <Button Name="VisitWebsite" Grid.Row="1" 
                Style="{StaticResource LinkButtonStyle}" 
                HorizontalAlignment="Left" ToolTip="Visit the Mindscape website">
                    <TextBlock Text="Built with Mindscape WPF" FontSize="16" 
                    FontFamily="Segoe UI" Foreground="DarkGray" Height="21" 
                    Width="203" />
                </Button>

                <TextBox Grid.Row="1" Text="{Binding Path=txt本日}" 
                TextAlignment="Center" 
                    Foreground="White" Background="Black"
                    Height="17" HorizontalAlignment="Center"  Name="txt本日2" 
                    VerticalAlignment="Top" Width="81" Margin="226,4,6,0" />
            </Grid>
        </Grid>
    </Grid>
</ccl:CustomChromeWindow>

PropertyChangedBase.csはLivet用に変更しました。具体的には、8行目のusing Livet;の追加ト19行目を、20行目にの変更しています。


PropertyChangedBase.cs
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

using Livet;
//using Livet.Commands;
//using Livet.Messaging;
//CloseCommand
//using Livet.Messaging.Windows;

using LivetWPFApplicationChrome1.ViewModels;
using LivetWPFApplicationChrome1.Views;

namespace LivetWPFApplicationChrome1.ViewModels
{
  // public class PropertyChangedBase : INotifyPropertyChanged
    public class PropertyChangedBase  : ViewModel
    {
        #region RaisePropertyChanged
        internal void RaisePropertyChanged(string prop)
        {
            if (PropertyChanged != null) 
            { 
            	PropertyChanged(this, new PropertyChangedEventArgs(prop)); 
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        #endregion 
    }
}