[WPF] WPF でスライダーにバインドしたテキストボックスの値を常に整数に保つ方法

 先日、Windows のタスクバーに小さいスタートメニューみたいなサブメニューを追加するランチャーアプリケーションを WPF で作りまして。

 で、作っている最中に、そのものズバリの日本語情報がネット検索で「簡単に」見つからなかったケースがいくつかありましたので、それらを4~5回に渡って記事化して放流しておこうと思います。

 さて、今回の内容は前回の続きになりますので、なるべく先にそちらに目を通しておいてください。

スポンサーリンク

読み込み中です。少々お待ち下さい

前回の問題点

 スライダーをドラッグで動かした時に、バインドしているテキストボックスの値が小数になってしまうのを、常に整数に保ちたいというのが、前回気になった点でした。

 まぁ、ジツはこれは特に探し難い情報という訳でもないのですが、いちおう一緒に触れておいた方がいいかなーと思いますので、前回のコードを少しだけ変更して、この問題に対応してみましょう。

  • こんな風に少数になってしまうのを、常に整数にしたいという話です

サンプルコード

 まず、前回作成した「WpfCustomSlider」プロジェクトに、右クリック等から「追加」>「新しい項目」で「DoubleToIntConverter.cs」という「クラス」を追加します。

 加えて、前回のコード(「MainWindow.xaml」のみ)に、少しだけ手を加えます。

DoubleToIntConverter.cs(今回、新規追加)

using System; using System.Globalization; using System.Windows.Data; namespace WpfCustomSlider {     class DoubleToIntConverter : IValueConverter     {         public object Convert(object value, Type targetType, object parameter, CultureInfo culture)         {             return System.Convert.ToInt32(value);         }         public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)         {             double d;             return double.TryParse(value.ToString(), out d) ? d : 0;         }     } }
※ IValueConverter インターフェイスについては、こちらを参照してください。

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>         <local:DoubleToIntConverter x:Key="DoubleToInt" />                  <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, Converter={StaticResource DoubleToInt}}" 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, Converter={StaticResource DoubleToInt}}" 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, Converter={StaticResource DoubleToInt}}" 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, Converter={StaticResource DoubleToInt}}" Orientation="Vertical" HorizontalAlignment="Right"/>         </Grid>     </Grid> </Window>

※横置きでも縦置きでも、どちらでも対応できるように修正しました(2016/06/22)

 要するに、テキストボックスそれぞれに Converter を追加しただけですね。

 これで目出度く、スライダーをドラッグしようが、テキストボックスに何を入力しようが、値は常に整数に保たれるようになりました。

  • 画像で見ても意味はありませんが、こんな感じ

おわりに

 次回は、スクロールバーのカスタマイズについてです。お楽しみに(誰も待ってない)

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