先日、Windows のタスクバーに小さいスタートメニューみたいなサブメニューを追加するランチャーアプリケーションを WPF で作りまして。
で、作っている最中に、そのものズバリの日本語情報がネット検索で「簡単に」見つからなかったケースがいくつかありましたので、それらを4~5回に渡って記事化して放流しておこうと思います。
ということで、今回はスライダーのカスタマイズです。
読み込み中です。少々お待ち下さい
まえおき
スライダーのデザインを、レトロなデフォルトスタイルから、今風のものに変えたい場合も多いかと思います。
WPF なら、かなり自由に外観を変えられますので、その方法についてサンプルコードで見ていきましょう。
サンプルコード
以下のコードは、Visual Studio (2015) の「ファイル」メニュー>「新規作成」>「WPF アプリケーション」から「WpfCustomSlider」という名前で新しいプロジェクトを作成し、自動的に生成される MainWindow に上書きすれば、そのまま動きます。
今回は「MainWindow.xaml.cs」の方は一切いじっていないので、「MainWindow.xaml」だけ貼り付けておきます。
あまり凝るとパッと見で分かり難くなってしまうので、あくまでサンプルとして、できるだけ簡潔に記述しています。
そのため、見た目がやや地味ですが、各パーツ毎に色を個別に指定したり、つまみに画像を使ったりと、後はお好きなようにカスタマイズしていただければ。
MainWindow.xaml
<Window x:Class="WpfCustomSlider.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:WpfCustomSlider"
mc:Ignorable="d"
Title="MainWindow" Height="247" Width="494">
<Window.Resources>
<SolidColorBrush x:Key="CyanBrush" Color="#00BCD4" />
<SolidColorBrush x:Key="PinkBrush" Color="#DB167C" />
<SolidColorBrush x:Key="LimeBrush" Color="#0BE182" />
<!-- つまみのデザイン。ここでは円(Ellipse)を描いていますが、他の図形や画像など、お好きにデザインしてください -->
<Style x:Key="SliderThumbStyle" TargetType="{x:Type Thumb}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Thumb}">
<Ellipse Fill="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type Slider}, Mode=FindAncestor}}" Width="25" Height="25"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- このサンプルでは、簡潔に記述する為に全て Foreground を基準に色を決定しています。個別に指定する場合は、適宜書き換えてください -->
<Style x:Key="CustomSliderStyle" TargetType="{x:Type Slider}">
<Style.Triggers>
<Trigger Property="Orientation" Value="Horizontal">
<!-- 横置きの場合 -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="25" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- 上の目盛り -->
<TickBar Grid.Row="0" x:Name="TopTick" Placement="Top" Visibility="Collapsed" Fill="{TemplateBinding Foreground}" Height="8" Opacity="0.64" Margin="0,0,0,2" />
<!-- 下の目盛り -->
<TickBar Grid.Row="2" x:Name="BottomTick" Placement="Bottom" Visibility="Collapsed" Fill="{TemplateBinding Foreground}" Height="8" Opacity="0.64" Margin="0,2,0,0" />
<Track Grid.Row="1" x:Name="PART_Track">
<!-- 減少側のトラック(レール) -->
<Track.DecreaseRepeatButton>
<RepeatButton Command="Slider.DecreaseLarge" Background="{TemplateBinding Foreground}" Height="5" BorderBrush="{x:Null}" Opacity="0.2"/>
</Track.DecreaseRepeatButton>
<!-- 増加側のトラック(レール) -->
<Track.IncreaseRepeatButton>
<RepeatButton Command="Slider.IncreaseLarge" Background="{TemplateBinding Foreground}" Height="5" BorderBrush="{x:Null}" Opacity="0.5"/>
</Track.IncreaseRepeatButton>
<!-- つまみ -->
<Track.Thumb>
<Thumb Style="{StaticResource SliderThumbStyle}"/>
</Track.Thumb>
</Track>
</Grid>
<!-- TickPlacement の設定によって目盛りの表示を切り替え -->
<ControlTemplate.Triggers>
<Trigger Property="Slider.TickPlacement" Value="TopLeft">
<Setter TargetName="TopTick" Property="Visibility" Value="Visible" />
</Trigger>
<Trigger Property="Slider.TickPlacement" Value="BottomRight">
<Setter TargetName="BottomTick" Property="Visibility" Value="Visible" />
</Trigger>
<Trigger Property="Slider.TickPlacement" Value="Both">
<Setter TargetName="TopTick" Property="Visibility" Value="Visible" />
<Setter TargetName="BottomTick" Property="Visibility" Value="Visible" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="Orientation" Value="Vertical">
<!-- 縦置きの場合 -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="25" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<!-- 左の目盛り -->
<TickBar Grid.Column="0" x:Name="LeftTick" Placement="Left" Visibility="Collapsed" Fill="{TemplateBinding Foreground}" Width="8" Opacity="0.64" Margin="0,0,2,0" />
<!-- 右の目盛り -->
<TickBar Grid.Column="2" x:Name="RightTick" Placement="Right" Visibility="Collapsed" Fill="{TemplateBinding Foreground}" Width="8" Opacity="0.64" Margin="2,0,0,0" />
<Track Grid.Column="1" x:Name="PART_Track" IsDirectionReversed="true">
<!-- 減少側のトラック(レール) -->
<Track.DecreaseRepeatButton>
<RepeatButton Command="Slider.DecreaseLarge" Background="{TemplateBinding Foreground}" Width="5" BorderBrush="{x:Null}" Opacity="0.2"/>
</Track.DecreaseRepeatButton>
<!-- 増加側のトラック(レール) -->
<Track.IncreaseRepeatButton>
<RepeatButton Command="Slider.IncreaseLarge" Background="{TemplateBinding Foreground}" Width="5" BorderBrush="{x:Null}" Opacity="0.5"/>
</Track.IncreaseRepeatButton>
<!-- つまみ -->
<Track.Thumb>
<Thumb Style="{StaticResource SliderThumbStyle}"/>
</Track.Thumb>
</Track>
</Grid>
<!-- TickPlacement の設定によって目盛りの表示を切り替え -->
<ControlTemplate.Triggers>
<Trigger Property="Slider.TickPlacement" Value="TopLeft">
<Setter TargetName="LeftTick" Property="Visibility" Value="Visible" />
</Trigger>
<Trigger Property="Slider.TickPlacement" Value="BottomRight">
<Setter TargetName="RightTick" Property="Visibility" Value="Visible" />
</Trigger>
<Trigger Property="Slider.TickPlacement" Value="Both">
<Setter TargetName="LeftTick" Property="Visibility" Value="Visible" />
<Setter TargetName="RightTick" Property="Visibility" Value="Visible" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="40"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<WrapPanel Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock TextWrapping="Wrap" Text="通常のスライダー" FontSize="14" Width="100" VerticalAlignment="Center"/>
<Slider x:Name="NormalSlider" Width="240" Margin="10,0" Maximum="100" SmallChange="1" LargeChange="10" TickPlacement="TopLeft" TickFrequency="10"/>
<TextBox x:Name="textBox_NormalSlider" Height="23" Width="50" Text="{Binding Value, ElementName=NormalSlider}" HorizontalContentAlignment="Center"/>
</WrapPanel>
<WrapPanel Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock TextWrapping="Wrap" Text="カスタムスライダー" FontSize="14" Width="100" VerticalAlignment="Center" Foreground="{DynamicResource CyanBrush}"/>
<Slider x:Name="CustomSlider" Width="240" Margin="10,0" Maximum="100" SmallChange="1" LargeChange="10" Style="{StaticResource CustomSliderStyle}" Foreground="{DynamicResource CyanBrush}"/>
<TextBox x:Name="textBox_CumstomSlider" Height="23" Width="50" Text="{Binding Value, ElementName=CustomSlider}" HorizontalContentAlignment="Center" Foreground="{DynamicResource CyanBrush}" BorderBrush="{DynamicResource CyanBrush}"/>
</WrapPanel>
<WrapPanel Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock TextWrapping="Wrap" Text="目盛りアリ" FontSize="14" Width="100" VerticalAlignment="Center" Foreground="{DynamicResource PinkBrush}"/>
<Slider x:Name="CustomSliderWithTick" Width="240" Margin="10,0" Maximum="100" SmallChange="1" LargeChange="10" TickPlacement="BottomRight" TickFrequency="10" Style="{StaticResource CustomSliderStyle}" Foreground="{DynamicResource PinkBrush}"/>
<TextBox x:Name="textBox_CumstomSliderWithTick" Height="23" Width="50" Text="{Binding Value, ElementName=CustomSliderWithTick}" HorizontalContentAlignment="Center" Foreground="{DynamicResource PinkBrush}" BorderBrush="{DynamicResource PinkBrush}"/>
</WrapPanel>
</Grid>
<Grid Grid.Column="1">
<Slider x:Name="CustomSliderVertical" Height="Auto" Margin="0,10" Maximum="100" SmallChange="1" LargeChange="10" TickPlacement="BottomRight" TickFrequency="10" Style="{StaticResource CustomSliderStyle}" Foreground="{DynamicResource LimeBrush}" ToolTip="{Binding RelativeSource={RelativeSource Self}, Path=Value}" Orientation="Vertical" HorizontalAlignment="Right"/>
</Grid>
</Grid>
</Window>
※横置きでも縦置きでも、どちらでも対応できるように修正しました(2016/06/22)
気になる点
さて、実行すると直ぐに気がつくのですが、上のコードだとスライダーをドラッグで動かした時に、テキストボックスの値が小数になってしまいます。
Slider の Value が double なので当たり前といえば当たり前なのですが、これを常に整数に保ちたい場合も多いですよね。
今回は焦点をデザインに絞っていますので、そちらについては次回を参照して下さい。