XamNumericSlider のつまみに XamSliderNumericThumb.ToolTipTemplate でツールチップを設定しても、つまみをドラッグしている間は消えてしまいます。ドラッグ中も値を表示し続けるには、ツールチップの代わりに WPF の Popup を使い、PreviewMouseMove イベントでつまみの上に表示します。

XamNumericSlider の設定

XamNumericSlider に、つまみの上でマウスが動いたことを検知する PreviewMouseMove イベントと、スライダーからマウスが離れたことを検知する MouseLeave イベントのハンドラーを設定します。

<ig:XamNumericSlider x:Name="xamNumericSlider1" ...
                     MinValue="0" MaxValue="100" TrackClickAction="MoveToPoint"
                     PreviewMouseMove="xamNumericSlider1_PreviewMouseMove"
                     MouseLeave="xamNumericSlider1_MouseLeave">
</ig:XamNumericSlider>

次に、ツールチップとして表示する Popup を定義します。Placement="Custom" と CustomPopupPlacementCallback で表示位置をコードから決められるようにします。TextBlock は XamNumericSlider の Value にバインドしているので、ドラッグに合わせて表示値が更新されます(このサンプルでは IValueConverter で値を整数に丸めています)。IsHitTestVisible="False" を指定し、Popup がマウス操作を妨げないようにします。

<Popup Name="floatingTip"
       AllowsTransparency="True"
       Placement="Custom"
       CustomPopupPlacementCallback="FloatingTip_CustomPopupPlacementCallback"
       IsHitTestVisible="False">
    <StackPanel Orientation="Vertical">
        <Border ...>
            <TextBlock Text="{Binding ElementName=xamNumericSlider1, Path=Value, Converter={StaticResource MyConverter}}" ... />
        </Border>
        <Polygon Points="0,0 10,0 5,6" Fill="#FF2B2B2B" HorizontalAlignment="Center" ... />
    </StackPanel>
</Popup>

PreviewMouseMove イベントでの Popup の表示

PreviewMouseMove イベントで、マウス カーソルの下にある要素(Mouse.DirectlyOver)から Utilities.GetAncestorFromType(Infragistics.Windows 名前空間)を使って親をたどり、つまみの XamSliderNumericThumb を取得します。つまみが見つかった場合は、それを Popup の PlacementTarget に設定して IsOpen = true で表示します。見つからない場合は Popup を閉じます。PreviewMouseMove はドラッグ中も発生するため、ToolTip と違ってドラッグ中も表示が消えません。

private void xamNumericSlider1_PreviewMouseMove(object sender, MouseEventArgs e)
{
    var thumb = Utilities.GetAncestorFromType(Mouse.DirectlyOver as DependencyObject, typeof(XamSliderNumericThumb), false) as XamSliderNumericThumb;
    var activeThumb = thumb ?? Mouse.DirectlyOver as XamSliderNumericThumb;

    if (activeThumb != null)
    {
        if (!ReferenceEquals(floatingTip.PlacementTarget, activeThumb))
        {
            floatingTip.PlacementTarget = activeThumb;
        }

        if (!floatingTip.IsOpen)
        {
            floatingTip.IsOpen = true;
        }
    }
    else
    {
        floatingTip.IsOpen = false;
    }
}

CustomPopupPlacementCallback では、Popup がつまみの中央真上に来るように表示位置を計算して返します。また、MouseLeave イベントで、マウスがスライダーから離れたら Popup を閉じます。

private CustomPopupPlacement[] FloatingTip_CustomPopupPlacementCallback(Size popupSize, Size targetSize, Point offset)
{
    var placementPoint = new Point(
        (targetSize.Width - popupSize.Width) / 2d,
        -popupSize.Height - 2d);

    return [new CustomPopupPlacement(placementPoint, PopupPrimaryAxis.None)];
}

private void xamNumericSlider1_MouseLeave(object sender, MouseEventArgs e)
{
    floatingTip.IsOpen = false;
}

実行結果

つまみにマウスを乗せると、つまみの上に現在の値が表示されます。つまみをドラッグしている間も表示は消えず、値がリアルタイムに更新されます。

製品について

Ultimate UI for WPF