WPF 標準コントロールデモアプリ › Slider

Slider Inputs

Slider は、トラック上のつまみのドラッグ、トラックのクリック、キーボードで、範囲内の値を選ばせるコントロールです。目盛りの表示と目盛りへの吸着、範囲の強調表示、現在値のツールチップを標準で備えています。

範囲、値、バインドしたソース

Slider は RangeBase を継承しており、ProgressBar と ScrollBar も同じ RangeBase の派生です。Minimum・Maximum・Value・SmallChange・LargeChange は RangeBase のプロパティです。新しく作った Slider の範囲は 0〜10 で、Value は double、既定値は 0 です。

測ったどの場合も、Value は範囲内に収まり、例外は出ませんでした。0〜100 の Slider に 150 を設定すると 100 になりました。その後 Maximum を 200 に上げると、Value は 150 に戻りました。設定した値は保持されているためです。Maximum は Minimum 以上に補正され、Minimum="50" の後に Maximum="10" を設定すると、実際の Maximum は 50 になりました。このため、2 つを変える順序は結果に影響しません。範囲を 0〜10 から 100〜200 に変えた場合、どちらを先に設定しても同じ状態になりました。

補正した値はソースへは書き戻されません。0〜100 の Slider に値 150 のソースを TwoWay でバインドすると、Slider の表示は 100 でしたが、ソースは 150 のままでした。ソースの値は自分で範囲内に収めないと、Slider に表示されていない値が残ります。

Value は既定で TwoWay にバインドされ、既定の UpdateSourceTrigger は PropertyChanged なので、UpdateSourceTrigger の指定は要りません。既定の設定のバインドでも、ドラッグの途中、ボタンを離す前にソースへ値が届きました。ソースのセッターで重い処理をすると、ドラッグの 1 ステップごとにその処理が走ります。

キー、トラックのクリック、向き

SmallChange は矢印キーで変わる量、LargeChange は PageUp / PageDown およびトラックのクリックで変わる量です。既定値は 0.1 と 1 で、既定の 0〜10 の範囲向けです。音量のような 0〜100 には小さすぎます。1 と 10 を設定した値 50 の Slider では、右・上矢印で 51、左矢印で 49、PageUp で 60、PageDown で 40、実際のマウスでのつまみの右側のトラックのクリックで 60 になりました。これは IsMoveToPointEnabled が既定値の False の場合です。True では、同じクリックでつまみがクリックした位置へ移り、値は 86.84 になりました。Home と End では Minimum と Maximum に移りました。

トラック上でマウスボタンを押し続けると、変化が繰り返されます。Delay は繰り返しが始まるまでの待ち時間、Interval は繰り返しの間隔です。既定値は Windows のキーボードの設定から決まります。計測した環境(SystemParameters.KeyboardDelay が 1、KeyboardSpeed が 31)では 500 と 33 で、Delay の既定値は(KeyboardDelay + 1)× 250 と一致しました。Slider はこの値をトラックの 2 つの RepeatButton に渡します。デモアプリの 1000 と 50 では、どちらのボタンも Delay="1000"・Interval="50" になりました。Delay が過ぎる前に離したクリックでは、値は 1 回だけ LargeChange 動きました。

Orientation の既定値は Horizontal です。Value = Maximum のとき、つまみは水平の Slider では右端、垂直の Slider では上端にありました。垂直の Slider は、もともと大きい値が上に来ます。IsDirectionReversed はトラックの向きを反転し、Value = Maximum のとき、つまみは水平の Slider では左端、垂直の Slider では下端に移りました。キー操作もトラックに合わせて反転し、右矢印で値が減りました(50 から 49)。

目盛りへの吸着はユーザーの操作にだけ働く

目盛りを描いても吸着はしません。TickPlacement="BottomRight" だけを設定した状態で 23.4 までドラッグすると、値は 23.4 のままでした。既定値が False の IsSnapToTickEnabled を有効にすると、ユーザーの操作による値が最も近い目盛りに吸着します。23.4 までのドラッグは、TickFrequency="10" で 20、TickFrequency="1" で 23 になりました。吸着はボタンを離したときではなく、ドラッグ中から働きます。キーとトラックの動きも変わり、TickFrequency="10" では右矢印で 50 が 51 ではなく 60 に、LargeChange="7" でのトラックのクリックで 57 ではなく 60 になりました。コードから設定した 23.4 は 23.4 のままでした。

既定値が 1 の TickFrequency は、吸着位置の間隔を決めます。Maximum も吸着位置になり、0〜100 の Slider で TickFrequency="30" とすると、94 までのドラッグは 90 に、97 までのドラッグは 100 に吸着しました。Ticks は位置を個別に指定し、TickFrequency の代わりに使われます。サイズやレベルを段階的に選ばせるなら、ここに並べて吸着を有効にします。0〜10 の Slider に 1,3,5,7,9 を指定すると、5.8 までのドラッグは 5 に、0.2 までのドラッグは 0 になりました。Minimum と Maximum は、Ticks に含めなくても吸着位置になります。

条件 計測値
0..100、23.4 までドラッグ、スナップなし 23.4
TickPlacement=BottomRight だけ 23.4
IsSnapToTickEnabled、TickFrequency=10 20
IsSnapToTickEnabled、TickFrequency=1 23
0..100、TickFrequency=30、スナップあり、94 までドラッグ 90
0..100、TickFrequency=30、スナップあり、97 までドラッグ 100
0..10、Ticks=1,3,5,7,9、スナップあり、5.8 までドラッグ 5
0..10、Ticks=1,3,5,7,9、スナップあり、0.2 までドラッグ 0
コードから Value = 23.4、IsSnapToTickEnabled、TickFrequency=10 23.4
既定の設定で Value をバインド: ドラッグ中(離す前)のソース 40

吸着の有無によるドラッグ後の Value。最後の行だけは、Value にバインドしたソースのドラッグ中の値である。.NET 10 / Windows 11 で計測。

目盛り、選択範囲、ツールチップ

測った場合では、範囲を割り切れない間隔でも、Minimum と Maximum に目盛りが描かれました。0〜100 の Slider で TickFrequency="30" とすると、目盛りは 0・30・60・90・100 に描かれ、0〜10 の Slider の Ticks="1,3,5,7,9" では 0・1・3・5・7・9・10 に描かれました。IsDirectionReversed では目盛りも反転し、0〜10 の Slider に Ticks="1,2" を設定すると、目盛りはトラックの右端側に移りました。手で並べ直す必要があるのは、Slider の横に自分で置いたラベルだけです。TickPlacement の既定値は None で、目盛りの分だけ高さが増えます。水平の Slider の高さは None で 18、BottomRight で 24、Both で 30 になりました。

SelectionStart と SelectionEnd は、トラックの一部を強調表示します。0〜10 の Slider で 2〜8 を指定すると、既定値の IsSelectionRangeEnabled="False" のあいだは表示されず、True にするとトラックの 2 から 8 までを覆いました。選択範囲は Value を制限せず、範囲外の 9.5 も設定できました。

AutoToolTipPlacement は、つまみのドラッグ中に現在値のツールチップを表示します。既定値の None では表示されません。表示されるのは数値だけです。Slider には書式を指定するプロパティがなく、関係するのは AutoToolTipPlacement と AutoToolTipPrecision だけです。数値は現在のカルチャに従い、1234.56 を小数 1 桁で表示すると、en-US では 1,234.6、de-DE では 1.234,6 になりました。既定値が 0 の AutoToolTipPrecision は、切り捨てではなく四捨五入します。0 のとき、33.6 は 34、33.4 は 33 と表示されました。2 のとき、33.456 は 33.46 と表示されました。丸められるのはツールチップの表示だけで、Value は元の精度のままです。「%」などの単位を付けたい場合は、StringFormat を使った別の TextBlock で値を表示します。

条件 計測値
0..100, TickFrequency=30: 目盛り、左から右へ(反転していないトラックの値として) 5: 0, 30, 60, 90, 100
0..10, Ticks=1,3,5,7,9: 目盛り、左から右へ(反転していないトラックの値として) 7: 0, 1, 3, 5, 7, 9, 10
0..10, Ticks=1,2: 目盛り、左から右へ(反転していないトラックの値として) 4: 0, 1, 2, 10
0..10, Ticks=1,2, IsDirectionReversed: 目盛り、左から右へ(反転していないトラックの値として) 4: 0, 8, 9, 10
TickPlacement=None: 高さ 18
TickPlacement=BottomRight: 高さ 24
TickPlacement=Both: 高さ 30
0..10、Selection 2..8、IsSelectionRangeEnabled=False Hidden
0..10、Selection 2..8、IsSelectionRangeEnabled=True Visible、2〜8 の範囲
選択範囲の外の Value = 9.5 9.5
AutoToolTipPlacement=None、Precision=0、Value 33.6 ツールチップなし
AutoToolTipPlacement=TopLeft、Precision=0、Value 33.6 "34", IsOpen=True
AutoToolTipPlacement=TopLeft、Precision=0、Value 33.4 "33", IsOpen=True
AutoToolTipPlacement=TopLeft、Precision=2、Value 33.456 "33.46", IsOpen=True
AutoToolTipPlacement=BottomRight、Precision=1、Value 1234.56 "1,234.6", IsOpen=True
CurrentCulture en-US、Precision=1、Value 1234.56 "1,234.6"
CurrentCulture de-DE、Precision=1、Value 1234.56 "1.234,6"

目盛りの位置(左から順に、値に換算)、高さ、選択範囲、自動ツールチップの文字列。.NET 10 / Windows 11 で計測。

デモアプリで試す

デモアプリの Slider のページ。左にコントロールの一覧、右に最初の節の Minimum(RangeBase) / Maximum(RangeBase) / Value(RangeBase)

デモアプリの Slider のページには、ここまでの各プロパティの欄があります。SmallChange / LargeChange の欄の初期値は 0〜10 の Slider に 1 と 10 なので、PageUp 1 回やトラックのクリック 1 回で端から端まで動きます。Ticks の欄は 1,3,5,7,9、選択範囲の欄は 2〜8、Delay / Interval の欄は 1000 と 50 です。各欄の下の「Show Code」リンクで、その欄の XAML を表示できます。次の XAML は、Minimum / Maximum / Value の欄(SliderUsageControl.xaml)から、スタイルと周囲の GroupBox を省き、名前空間の宣言を加えたものです。behaviors はデモアプリ独自の添付ビヘイビアの接頭辞です。

<StackPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:behaviors="clr-namespace:WPFStandardControlDemoApp.Common.Behaviors">
  <TextBox x:Name="MinTextBox"
           behaviors:TextBoxDoubleInputBehavior.IsEnabled="True"
           Text="0" />
  <TextBox x:Name="MaxTextBox"
           behaviors:TextBoxDoubleInputBehavior.IsEnabled="True"
           Text="100" />
  <TextBox x:Name="ValueTextBox"
           behaviors:TextBoxDoubleInputBehavior.IsEnabled="True"
           Text="{Binding Value, ElementName=MinMaxSlider, UpdateSourceTrigger=PropertyChanged}" />

  <Slider x:Name="MinMaxSlider"
          Maximum="{Binding Text, ElementName=MaxTextBox}"
          Minimum="{Binding Text, ElementName=MinTextBox}" />
</StackPanel>

ここにある UpdateSourceTrigger=PropertyChanged は TextBox.Text 側のバインドの指定で、その既定値は LostFocus です。この指定により、テキストボックスに入力するとすぐに Slider が動きます。Slider.Value をバインドする場合は、既定値がすでに PropertyChanged なので指定は要りません。

関連するコントロールと記事

ソースコードと計測の方法

このページの挙動の記述は、すべて .NET 10 / Windows 11 で実際に動かして確かめたものです。計測には、このサイトのスクリーンショット生成ツールの SliderDemoScene を使いました。つまみのドラッグは、マウスでドラッグしたときにつまみが発生させるのと同じ DragStarted・DragDelta イベントで、キー操作は表示したウィンドウへキー入力イベントを送って再現しています。トラックのクリックは、計測用のウィンドウの上で実際のマウスを使い、トラックの長さの 85% の位置を押して約 0.1 秒後に離して行いました。

GitHub で Slider のソースコードを見る →