[WPF] WPF でスクロールバーのデザインをカスタマイズ

 先日、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&#x0a;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="テキストボックスのサンプルです。&#x0a;このようにテキストボックスのスクロールバーも&#x0a;変更できます。&#x0a;テスト"/>             </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="通常のテキストボックス&スクロールバーです。&#x0a;========================&#x0a;テスト"/>         </Grid>     </Grid> </Window>

 微妙に長くてすみません。あと、あれこれ試しながら書いたので、どこかに余計な記述が残っていたら申し訳ないです。

 ちなみに、テキストボックス等、自動的にスクロールバーが表示される系の要素に対して、ScrollViewer で囲まずに直接 ScrollBar のスタイルだけを強引に上書きすると、以下のように右下に不透明な余白が残ってしまい、背景色によっては見た目が悪いので、ご注意ください。

  • 直接 ScrollBar のスタイルだけ置き換えると
    右下に不透明な余白が残る

おわりに

 さて、次回はどうしましょうか。

 もしかしたら、WPF については一旦終了して、他のことを書くかも知れません。

この記事をシェア
  • このエントリーをはてなブックマークに追加
  • Share on Google+
  • この記事についてツイート
  • この記事を Facebook でシェア