이전 포스트들에서 여러가지 방법으로 썸(Thumb)에 말풍선 툴팁(ToolTip)이 따라다니는 슬라이더(Slider)를 만들어 보았습니다. 그런데 뭔가 만족스럽지 않았습니다. 그래서 좀 더 깔끔한 방법이 없을까 한참을 고민하고 태스트하고 찾아보던 끝에 하나의 포스트를 더 이어가기로 했습니다.
예제에 사용된 대부분의 코드는 동일하니 달라진 점만 일부 설명합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <!-- 툴팁 팝업 --> <Popup x:Name="PART_ToolTipPopup" PlacementTarget="{Binding ElementName=Thumb}" Placement="Center" VerticalOffset="-30" AllowsTransparency="True"> <StackPanel> <Border CornerRadius="5" Background="SkyBlue"> <TextBlock Text="{Binding Value, ElementName=PART_Track, StringFormat=N0}" Foreground="Black" HorizontalAlignment="Center" Margin="10,5" /> </Border> <ed:RegularPolygon Fill="SkyBlue" Margin="0,-8,0,0" Panel.ZIndex="-1" PointCount="4" Width="10" Height="15" /> </StackPanel> </Popup> | cs |
XAML 코드에서 사용된 Popup은 그대로 사용됩니다. 추가로 이전 예제에서 불필요하게 사용되었던 VerticalOffset 프로퍼티는 -30으로 고정 시켰습니다. 팝업의 세로 위치는 변하지 않으므로 미리 고정되어도 될 것 같습니다.
1 2 3 4 5 6 7 8 9 | <!-- New Behavior --> <Slider Value="5" Minimum="0" Maximum="100" IsSnapToTickEnabled="True" TickFrequency="1" TickPlacement="Both" VerticalAlignment="Center" Margin="10,0" Style="{DynamicResource Style_Slider}"> <i:Interaction.Behaviors> <bhv:ToolTipToPopupSliderBehavior /> </i:Interaction.Behaviors> </Slider> | cs |
슬라이더의 XAML 코드입니다. 달라진 점은 IsSnapToTickEnabled 프로퍼티를 True로 활성화하여 Tick에 스냅이 걸리도록 한 점입니다. 썸이 이동할 때 1 단위로 스냅된다는 시나리오를 추가했습니다. TickFrequency, TickPlacement 등의 프로퍼티는 Tick이 디자인 화면에 노출되도록 하는 프로퍼티들입니다.
아래부터는 새로운 방식으로 만든 비헤이비어(Behavior)입니다.
ToolTipToPopupSliderBehavior.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | private void AssociatedObject_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { _popup.HorizontalOffset = 0; _popup.IsOpen = true; var xMoveOffset = AssociatedObject.ActualWidth / (AssociatedObject.Maximum - AssociatedObject.Minimum); if (e.NewValue > e.OldValue && e.NewValue != AssociatedObject.Maximum) { _popup.HorizontalOffset += xMoveOffset; } else if (e.NewValue < e.OldValue && e.OldValue != AssociatedObject.Maximum) { _popup.HorizontalOffset -= xMoveOffset; } } | cs |
이번 새로운 비헤이비어에서는 마우스와 키보드 이벤트를 각각 따로 이용하지 않고 동시에 적용되는 ValueChanged 이벤트를 이용했습니다. 이전에는 각각에 해당하는 이벤트를 핸들링했기 때문에 조금 중복되는 느낌을 받았는데 공통으로 발생하는 ValueChanged 이벤트를 이용함으로서 좀 더 깔끔해진 느낌이 나는 듯 합니다.
그리고 이번에는 슬라이더의 Minimum, Maximum 프로퍼티의 값과 실제 ActualWidth의 크기를 이용해 썸이 움직였을때 팝업이 움직여야하는 HorizontalOffset 값을 매번 계산하여 초기화하고 다시 넣어주도록 하였습니다. 슬라이더의 크기가 고정이 아니라 윈도우 리사이징 등 어떤 이유로 변경이 가능하다는 가정된 시나리오 아래에 그렇게 되도록 했습니다.
그리고 기존에 Key.Left와 Key.Right의 판단은 OldValue와 NewValue를 비교하는 것으로 대체했습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #region Event handler < Mouse private void _thumb_MouseLeave(object sender, MouseEventArgs e) { _popup.IsOpen = false; } #endregion #region Event handler < Keyboard private void Slider_PreviewKeyUp(object sender, KeyEventArgs e) { _popup.IsOpen = false; } #endregion | cs |
팝업이 닫히는 동작의 경우는 이전 방법 그대로 각각의 이벤트 핸들러를 이용하도록 했습니다.
제가 사용했던 여러 방식들이 정답이 아니거나 옳지 못할 수도 있습니다. 하지만 제 나름대로는 몇일, 몇시간을 투자해서 얻은 결론이라 흥미로웠습니다. 나중에라도 더 나은 방법을 알게 된다면 기쁜 마음으로 다시 공유하게 될 것 같습니다.
마지막으로 아래 링크는 이번 예제에서는 직접적으로 사용되진 않았지만 예제 프로젝트 안에 일부 주석과 FollowingPopup.cs 파일 등에 남겨 두었습니다. 키보드도 함께 지원해야 한다는 저의 시나리오에 부합되지 않아 사용하지 않았습니다만 괜찮은 참고자료인 것 같아 남겨둡니다. 간단한 내용이지만 다른 시선으로 눈을 뜨게 해준 stackoverflow에서 찾은 질문과 답변입니다. 저에게는 QueryCursor라는 이벤트를 이렇게도 사용할 수 있구나 하는 새로운 발견이었습니다.
참고 : Make Tooltip of WPF slider stay on screen while dragging
'XAML 뽀개기' 카테고리의 다른 글
031. 데이터템플릿 & 셀렉터(DataTemplate & Selector) #2 (0) | 2018.04.16 |
---|---|
030. 데이타템플릿 & 컨버터(DataTemplate & Converter) #1 (0) | 2018.04.11 |
029. 툴팁 말풍선 슬라이더(ToolTip Balloon Slider) #3 (0) | 2018.04.09 |
028. 툴팁 말풍선 슬라이더(ToolTip Balloon Slider) #2 (0) | 2018.03.22 |
027. 툴팁 말풍선 슬라이더(ToolTip Balloon Slider) #1 (0) | 2018.03.20 |
026. 툴팁 말풍선(ToolTip Balloon) (0) | 2018.03.15 |