まずコントロール内部のレイアウトを決めます
Sleipnir 3 Alpha の LocationBar を Spy++ で調べてみたところ、ComboBox と Button がくっついてるみたいでした。作成するコントロールの内部レイアウトはこれに倣います。
ファビコンを表示する部分も ComboBox の一部なので、通常の ComboBox の Template を差し替える方法ではなく、カスタム ComboBox を作成する方法をとります。
コントロールで使うブラシをまとめて定義します
Vista のときに適用されるスキンと、できるだけ近い外観になるように色を調整。
Brush.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <!--LocationBarの境界線--> <SolidColorBrush x:Key="LocationBarBorderBrush" Color="#A9ACB3"/> <!--標準時のボタンの背景色--> <LinearGradientBrush x:Key="ButtonDefaultBrush" StartPoint="0,0" EndPoint="0,1"> <GradientStop Color="#F5F8FF" Offset="0"/> <GradientStop Color="#EBEDF9" Offset="0.5"/> <GradientStop Color="#DCE0EF" Offset="0.5"/> <GradientStop Color="#EEF3F7" Offset="1"/> </LinearGradientBrush> <!--マウスオーバー時のボタンの背景色--> <LinearGradientBrush x:Key="ButtonActiveBrush" StartPoint="0,0" EndPoint="0,1"> <GradientStop Color="#F0F2FB" Offset="0"/> <GradientStop Color="#D8DEF3" Offset="0.5"/> <GradientStop Color="#B2BFE8" Offset="0.5"/> <GradientStop Color="#E4E9F7" Offset="1"/> </LinearGradientBrush> <!--ボタン押下時の背景色--> <LinearGradientBrush x:Key="ButtonPressedBrush" StartPoint="0,0" EndPoint="0,1"> <GradientStop Color="#D6DBE9" Offset="0"/> <GradientStop Color="#D4DBF2" Offset="0.5"/> <GradientStop Color="#ABB9E6" Offset="0.5"/> <GradientStop Color="#D7DEF3" Offset="1"/> </LinearGradientBrush> <!--移動ボタンの矢印の背景色--> <LinearGradientBrush x:Key="GoButtonForegroundBrush" StartPoint="0,0" EndPoint="0,1"> <GradientStop Color="#57575C" Offset="0"/> <GradientStop Color="#525258" Offset="1"/> </LinearGradientBrush> </ResourceDictionary>
色は Web に張り付けてあるスクリーンショットをもとに、ColorZilla を使って調べました。
カスタム ComboBox のスタイルを記述します
CustomComboBox.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:LocationBarSample"> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="/LocationBarSample;component/Common/Brush.xaml"/> </ResourceDictionary.MergedDictionaries> <!--ファビコンを表示するボタンのスタイル--> <Style x:Key="FaviconButtonStyle" TargetType="Button"> <Setter Property="IsTabStop" Value="False"/> <Setter Property="Focusable" Value="False"/> <Setter Property="Width" Value="32"/> <Setter Property="Background" Value="{StaticResource ButtonDefaultBrush}"/> <Setter Property="BorderBrush" Value="{StaticResource LocationBarBorderBrush}"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Button"> <Border x:Name="Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0,0,1,0" CornerRadius="2,0,0,2"> <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center"/> </Border> </ControlTemplate> </Setter.Value> </Setter> <Style.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="Background" Value="{StaticResource ButtonActiveBrush}"/> </Trigger> <Trigger Property="IsPressed" Value="True"> <Setter Property="Background" Value="{StaticResource ButtonPressedBrush}"/> </Trigger> </Style.Triggers> </Style> <!--ComboBox 内の TextBox に適用するスタイル--> <Style x:Key="TextBoxStyle" TargetType="TextBox"> <Setter Property="VerticalContentAlignment" Value="Center"/> <Setter Property="BorderBrush" Value="Transparent"/> <Setter Property="BorderThickness" Value="0"/> </Style> <!--▼ボタンのスタイル--> <Style x:Key="DropDownButtonStyle" TargetType="ToggleButton"> <Setter Property="IsTabStop" Value="False"/> <Setter Property="Focusable" Value="False"/> <Setter Property="Width" Value="16"/> <Setter Property="BorderBrush" Value="{StaticResource LocationBarBorderBrush}"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ToggleButton"> <Border x:Name="Border" Background="Transparent" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0,0,0,0"> <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center"/> </Border> <ControlTemplate.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter TargetName="Border" Property="BorderThickness" Value="1,0,0,0"/> <Setter TargetName="Border" Property="Background" Value="{StaticResource ButtonActiveBrush}"/> </Trigger> <Trigger Property="IsChecked" Value="True"> <Setter TargetName="Border" Property="BorderThickness" Value="1,0,0,0"/> <Setter TargetName="Border" Property="Background" Value="{StaticResource ButtonPressedBrush}"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> <!--カスタム ComboBox のスタイル--> <Style TargetType="{x:Type local:CustomComboBox}"> <Setter Property="IsEditable" Value="True"/> <Setter Property="BorderBrush" Value="{StaticResource LocationBarBorderBrush}"/> <Setter Property="BorderThickness" Value="1"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type local:CustomComboBox}"> <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="2,0,0,2"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <Button x:Name="PART_FaviconButton" Style="{StaticResource FaviconButtonStyle}" Grid.Column="0"> <!--アイコンは今回は固定--> <Image Source="../Images/page.png" Stretch="None"/> </Button> <TextBox x:Name="PART_TextBox" Style="{StaticResource TextBoxStyle}" Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=SelectedValue}" Grid.Column="1"/> <ToggleButton x:Name="PART_DropDownButton" Style="{StaticResource DropDownButtonStyle}" IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsDropDownOpen}" ClickMode="Press" Grid.Column="2"> <!--▼は Path を使って自力描画--> <Path VerticalAlignment="Center" HorizontalAlignment="Center" Data="M 0 0 L 4 4 L 8 0 Z"> <Path.Fill> <SolidColorBrush Color="#FF333333"/> </Path.Fill> </Path> </ToggleButton> <Popup x:Name="PART_Popup" Height="160" Focusable="False" PopupAnimation="Slide" Placement="Bottom" PlacementTarget="{Binding ElementName=PART_FaviconButton}" IsOpen="{TemplateBinding IsDropDownOpen}"> <Border BorderThickness="1" BorderBrush="{TemplateBinding BorderBrush}"> <ScrollViewer VerticalScrollBarVisibility="Visible"> <StackPanel Background="{x:Static SystemColors.WindowBrush}" IsItemsHost="True"/> </ScrollViewer> </Border> </Popup> </Grid> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> </ResourceDictionary>
ファビコンを表示するボタンは、今回、画像を固定しています。
▼ボタンのチェック状態と Popup の表示/非表示が連動するようにしています。
ComboBox のテンプレートは MSDN のサンプルを参考にしました。
LocationBar のスタイルを記述します
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:LocationBarSample"> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="/LocationBarSample;component/Common/Brush.xaml"/> </ResourceDictionary.MergedDictionaries> <!--移動ボタンのスタイル--> <Style x:Key="GoButtonStyle" TargetType="Button"> <Setter Property="IsTabStop" Value="False"/> <Setter Property="Focusable" Value="False"/> <Setter Property="Width" Value="32"/> <Setter Property="Background" Value="{StaticResource ButtonDefaultBrush}"/> <Setter Property="BorderBrush" Value="{StaticResource LocationBarBorderBrush}"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Button"> <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0,1,1,1" CornerRadius="0,2,2,0"> <ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Center"/> </Border> </ControlTemplate> </Setter.Value> </Setter> <Style.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="Background" Value="{StaticResource ButtonActiveBrush}"/> </Trigger> <Trigger Property="IsPressed" Value="True"> <Setter Property="Background" Value="{StaticResource ButtonPressedBrush}"/> </Trigger> </Style.Triggers> </Style> <!-- LocationBar のスタイル --> <Style TargetType="{x:Type local:LocationBar}"> <Setter Property="BorderBrush" Value="{StaticResource LocationBarBorderBrush}"/> <Setter Property="BorderThickness" Value="1"/> <Setter Property="MinHeight" Value="24"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type local:LocationBar}"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <local:CustomComboBox x:Name="PART_ComboBox" Grid.Column="0"/> <Button x:Name="PART_GoButton" Style="{StaticResource GoButtonStyle}" Grid.Column="1"> <!--矢印は Path を使って自力描画--> <Path HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Stretch="Uniform" Fill="{StaticResource GoButtonForegroundBrush}"> <Path.Data> <PathGeometry> <PathFigure StartPoint="0,10" IsClosed="True" IsFilled="True"> <PathFigure.Segments> <LineSegment Point="0,5"/> <LineSegment Point="5,5"/> <LineSegment Point="5,0"/> <LineSegment Point="12.5,7.5"/> <LineSegment Point="5,15"/> <LineSegment Point="5,10"/> <LineSegment Point="0,10"/> </PathFigure.Segments> </PathFigure> </PathGeometry> </Path.Data> </Path> </Button> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </ResourceDictionary>
カスタム ComboBox と Button を並べています。2つを Border で囲ってはいません。
移動ボタンに表示する画像は、良いものがなかったので、自力で描画しました。
Generic.xaml に上記の XAML をマージします
Generic.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:LocationBarSample"> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="/LocationBarSample;component/CustomComboBox/CustomComboBox.xaml"/> <ResourceDictionary Source="/LocationBarSample;component/LocationBar/LocationBar.xaml"/> </ResourceDictionary.MergedDictionaries> </ResourceDictionary>
MergedDictionaryies を使えば、XAML を分割できるので、管理しやすくなります。
次回に続く
結構な量の XAML を記述したので疲れました。今回はここまで。
次回はコントロールの内部動作を実装します。作成したプロジェクトも公開予定です。