先日、Windows のタスクバーに小さいスタートメニューみたいなサブメニューを追加するランチャーアプリケーションを WPF で作りまして。
で、作っている最中に、そのものズバリの日本語情報がネット検索で「簡単に」見つからなかったケースがいくつかありましたので、それらを4~5回に渡って記事化して放流しておこうと思います。
さて、前回の予告通りに、今回はスクロールバーのカスタマイズについてです。
読み込み中です。少々お待ち下さい
まえおき
普通に ScrollViewer を使う場合はもちろん、自動的にスクロールバーが表示される要素についても、基本的にカスタマイズできます。
サンプルコード
以下のコードは、Visual Studio (2015) の「ファイル」メニュー>「新規作成」>「WPF アプリケーション」から「WpfCustomScrollbar」という名前で新しいプロジェクトを作成し、自動的に生成される MainWindow に上書きすれば、そのまま動作します。
今回は「MainWindow.xaml.cs」の方は一切いじっていないので、「MainWindow.xaml」だけ貼り付けておきます(青字が、こちらで追加・変更した部分になります)。
あまり凝るとパッと見で分かり難くなってしまうので、あくまでサンプルとして、できるだけ簡潔に記述しています。
そのため、見た目がやや地味ですが、各パーツ毎に色やボーダーを変更して、お好きなようにカスタマイズしてください。
MainWindow.xaml
<Window x:Class="WpfCustomScrollbar.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfCustomScrollbar"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
Title="MainWindow" Height="480" Width="494">
<Window.Resources>
<!-- サイズと色の定義。簡潔に記述する為に半透明の白で指定しているので、親の背景色が白の場合は白以外の色を指定してください -->
<!-- スクロールバーの幅 -->
<sys:Double x:Key="ScrollBarSize">12</sys:Double>
<!-- ボタンの長さ -->
<sys:Double x:Key="ScrollBarRepeatButtonSize">16</sys:Double>
<!-- スクロールバーのマージン -->
<sys:Double x:Key="ScrollBarMarginSize">5</sys:Double>
<!-- スクロールバーの色-->
<SolidColorBrush x:Key="ScrollBarColorBrush" Color="#66ffffff" />
<!-- ボーダーの色 -->
<SolidColorBrush x:Key="ScrollBarBorderBrush" Color="#66ffffff" />
<!-- トラック(レーン)の色 -->
<SolidColorBrush x:Key="ScrollBarTrackBrush" Color="#33ffffff" />
<!-- 三角の色 -->
<SolidColorBrush x:Key="ScrollBarHilightBrush" Color="#ccffffff" />
<!-- ボタンを押した時の色 -->
<SolidColorBrush x:Key="ScrollBarPressedBrush" Color="#99ffffff" />
<!-- 使用不可の色 -->
<SolidColorBrush x:Key="ScrollBarDisabledBrush" Color="#44ffffff" />
<!-- 終端の三角ボタンのスタイル -->
<Style x:Key="ScrollBarRepeatButtonStyle" TargetType="{x:Type RepeatButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RepeatButton}">
<Border x:Name="Border" Margin="0" CornerRadius="0" Background="{StaticResource ScrollBarColorBrush}" BorderBrush="{StaticResource ScrollBarBorderBrush}" BorderThickness="1">
<Path HorizontalAlignment="Center" VerticalAlignment="Center" Fill="{StaticResource ScrollBarHilightBrush}" Data="{Binding Content, RelativeSource={RelativeSource TemplatedParent}}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="true">
<Setter TargetName="Border" Property="Background" Value="{StaticResource ScrollBarPressedBrush}" />
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{StaticResource ScrollBarDisabledBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- トラック(レーン)のスタイル -->
<Style x:Key="ScrollBarTrackStyle" TargetType="{x:Type RepeatButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type RepeatButton}">
<Border Background="Transparent"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- つまみのスタイル -->
<Style x:Key="ScrollBarThumbStyle" TargetType="{x:Type Thumb}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Border CornerRadius="0" Background="{StaticResource ScrollBarColorBrush}" BorderBrush="{StaticResource ScrollBarBorderBrush}" BorderThickness="1" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- カスタムスクロールバーのスタイル -->
<Style x:Key="CustomScrollBarStyle" TargetType="{x:Type ScrollBar}">
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Style.Triggers>
<!-- 縦向きのスクロールバー -->
<Trigger Property="Orientation" Value="Vertical">
<Setter Property="Width" Value="{StaticResource ScrollBarSize}"/>
<Setter Property="Height" Value="Auto" />
<Setter Property="Margin">
<Setter.Value>
<Thickness Left="0" Top="{StaticResource ScrollBarMarginSize}" Right="{StaticResource ScrollBarMarginSize}" Bottom="{StaticResource ScrollBarMarginSize}" />
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition MaxHeight="{StaticResource ScrollBarRepeatButtonSize}"/>
<RowDefinition/>
<RowDefinition MaxHeight="{StaticResource ScrollBarRepeatButtonSize}"/>
</Grid.RowDefinitions>
<Border Grid.RowSpan="3" CornerRadius="0" Background="{StaticResource ScrollBarTrackBrush}" />
<RepeatButton Grid.Row="0" Style="{StaticResource ScrollBarRepeatButtonStyle}" Height="{StaticResource ScrollBarRepeatButtonSize}" Command="ScrollBar.LineUpCommand" Content="M 0 4 L 8 4 L 4 0 Z" />
<Track x:Name="PART_Track" Grid.Row="1" IsDirectionReversed="true">
<Track.DecreaseRepeatButton>
<RepeatButton Style="{StaticResource ScrollBarTrackStyle}" Command="ScrollBar.PageUpCommand" />
</Track.DecreaseRepeatButton>
<Track.Thumb>
<Thumb Style="{StaticResource ScrollBarThumbStyle}" Margin="0,1,0,1"/>
</Track.Thumb>
<Track.IncreaseRepeatButton>
<RepeatButton Style="{StaticResource ScrollBarTrackStyle}" Command="ScrollBar.PageDownCommand" />
</Track.IncreaseRepeatButton>
</Track>
<RepeatButton Grid.Row="2" Style="{StaticResource ScrollBarRepeatButtonStyle}" Height="{StaticResource ScrollBarRepeatButtonSize}" Command="ScrollBar.LineDownCommand" Content="M 0 0 L 4 4 L 8 0 Z"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
<!-- 横向きのスクロールバー -->
<Trigger Property="Orientation" Value="Horizontal">
<Setter Property="Width" Value="Auto"/>
<Setter Property="Height" Value="{StaticResource ScrollBarSize}" />
<Setter Property="Margin">
<Setter.Value>
<Thickness Left="{StaticResource ScrollBarMarginSize}" Top="0" Right="{StaticResource ScrollBarMarginSize}" Bottom="{StaticResource ScrollBarMarginSize}" />
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MaxWidth="{StaticResource ScrollBarRepeatButtonSize}"/>
<ColumnDefinition/>
<ColumnDefinition MaxWidth="{StaticResource ScrollBarRepeatButtonSize}"/>
</Grid.ColumnDefinitions>
<Border Grid.ColumnSpan="3" CornerRadius="0" Background="{StaticResource ScrollBarTrackBrush}" />
<RepeatButton Grid.Column="0" Style="{StaticResource ScrollBarRepeatButtonStyle}" Width="{StaticResource ScrollBarRepeatButtonSize}" Command="ScrollBar.LineLeftCommand" Content="M 4 0 L 4 8 L 0 4 Z" />
<Track x:Name="PART_Track" Grid.Column="1" IsDirectionReversed="false">
<Track.DecreaseRepeatButton>
<RepeatButton Style="{StaticResource ScrollBarTrackStyle}" Command="ScrollBar.PageLeftCommand" />
</Track.DecreaseRepeatButton>
<Track.Thumb>
<Thumb Style="{StaticResource ScrollBarThumbStyle}" Margin="1,0,1,0"/>
</Track.Thumb>
<Track.IncreaseRepeatButton>
<RepeatButton Style="{StaticResource ScrollBarTrackStyle}" Command="ScrollBar.PageRightCommand" />
</Track.IncreaseRepeatButton>
</Track>
<RepeatButton Grid.Column="2" Style="{StaticResource ScrollBarRepeatButtonStyle}" Width="{StaticResource ScrollBarRepeatButtonSize}" Command="ScrollBar.LineRightCommand" Content="M 0 0 L 4 4 L 0 8 Z"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
<!-- カスタム ScrollViewer のスタイル -->
<Style x:Key="CustomScrollViewerStyle" TargetType="{x:Type ScrollViewer}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ScrollContentPresenter Grid.Column="0" Grid.Row="0">
<ScrollContentPresenter.Margin>
<Thickness Left="{StaticResource ScrollBarMarginSize}" Top="{StaticResource ScrollBarMarginSize}" Right="{StaticResource ScrollBarMarginSize}" Bottom="{StaticResource ScrollBarMarginSize}" />
</ScrollContentPresenter.Margin>
</ScrollContentPresenter>
<ScrollBar x:Name="PART_VerticalScrollBar" Grid.Column="1" Grid.Row="0" Orientation="Vertical" Value="{TemplateBinding VerticalOffset}" Maximum="{TemplateBinding ScrollableHeight}" ViewportSize="{TemplateBinding ViewportHeight}" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Style="{StaticResource CustomScrollBarStyle}"/>
<ScrollBar x:Name="PART_HorizontalScrollBar" Grid.Column="0" Grid.Row="1" Orientation="Horizontal" Value="{TemplateBinding HorizontalOffset}" Maximum="{TemplateBinding ScrollableWidth}" ViewportSize="{TemplateBinding ViewportWidth}" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Style="{StaticResource CustomScrollBarStyle}"/>
<Border Grid.Column="1" Grid.Row="1" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- 選択されたリストボックスの背景色をデフォルトから変更。今回の内容には直接関係ないので、無視してください -->
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border x:Name="Border" BorderThickness="0">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="Border" Property="Background" Value="{StaticResource ScrollBarTrackBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="#00BCD4">
<ScrollViewer Style="{StaticResource CustomScrollViewerStyle}" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Visible">
<TextBlock x:Name="textBlock" TextWrapping="Wrap" Width="1024" Height="1024" Foreground="#fff" FontSize="24" Text="Width = 1024 / Height = 1024
ScrollViewer のサンプルです"/>
</ScrollViewer>
</Grid>
<Grid Grid.Row="1" Background="#DB167C">
<ScrollViewer Style="{StaticResource CustomScrollViewerStyle}" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<TextBox Name="test" AcceptsReturn="True" Background="Transparent" Foreground="White" CaretBrush="White" FontSize="24" BorderThickness="0" SelectionBrush="{StaticResource ScrollBarHilightBrush}" Text="テキストボックスのサンプルです。
このようにテキストボックスのスクロールバーも
変更できます。
テスト"/>
</ScrollViewer>
</Grid>
<Grid Grid.Row="2" Background="#5d5d5d">
<ScrollViewer Style="{StaticResource CustomScrollViewerStyle}" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<ListBox Background="Transparent" BorderThickness="0" FontSize="20" Foreground="White">
<ListBoxItem>これはリストボックスのサンプルです</ListBoxItem>
<ListBoxItem>テキストボックスだけでなく、他の自動的にスクロールバーが</ListBoxItem>
<ListBoxItem>表示される要素についても、基本的にカスタマイズできます。 </ListBoxItem>
</ListBox>
</ScrollViewer>
</Grid>
<Grid Grid.Row="3">
<TextBox FontSize="24" AcceptsReturn="True" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Visible" Text="通常のテキストボックス&スクロールバーです。
========================
テスト"/>
</Grid>
</Grid>
</Window>
微妙に長くてすみません。あと、あれこれ試しながら書いたので、どこかに余計な記述が残っていたら申し訳ないです。
ちなみに、テキストボックス等、自動的にスクロールバーが表示される系の要素に対して、ScrollViewer で囲まずに直接 ScrollBar のスタイルだけを強引に上書きすると、以下のように右下に不透明な余白が残ってしまい、背景色によっては見た目が悪いので、ご注意ください。
おわりに
さて、次回はどうしましょうか。
もしかしたら、WPF については一旦終了して、他のことを書くかも知れません。