1
0

MySlider.xaml.vb 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. Imports System.Windows.Shapes
  2. Public Class MySlider
  3. Implements ISettingControl
  4. '基础
  5. Public Uuid As Integer = GetUuid()
  6. Public Event Change(sender As Object, user As Boolean)
  7. Public Event PreviewChange(sender As Object, e As RouteEventArgs)
  8. '自定义属性
  9. Private _MaxValue As Integer = 100
  10. Public Property MaxValue As Integer
  11. Get
  12. Return _MaxValue
  13. End Get
  14. Set(value As Integer)
  15. If value = _MaxValue Then Return
  16. _MaxValue = value
  17. RefreshWidth(Nothing, Nothing)
  18. End Set
  19. End Property
  20. Private ChangeByKey As Boolean = False
  21. Private _Value As Integer = 0
  22. Public Property Value As Integer
  23. Get
  24. Return _Value
  25. End Get
  26. Set(newValue As Integer)
  27. Try
  28. newValue = newValue.Clamp(0, MaxValue)
  29. If _Value = newValue Then Return
  30. '触发 Preview 事件,修改新值
  31. Dim OldValue = _Value
  32. _Value = newValue
  33. If AniControlEnabled = 0 Then
  34. Dim e = New RouteEventArgs(False)
  35. RaiseEvent PreviewChange(Me, e)
  36. If e.Handled Then
  37. _Value = OldValue
  38. DragStop()
  39. Return
  40. End If
  41. End If
  42. If IsLoaded AndAlso AniControlEnabled = 0 Then
  43. If ActualWidth < ShapeDot.Width Then Return
  44. Dim NewWidth As Double = _Value / MaxValue * (ActualWidth - ShapeDot.Width)
  45. Dim DeltaProcess As Double = Math.Abs(LineFore.Width / (ActualWidth - ShapeDot.Width) - _Value / MaxValue)
  46. Dim Time As Double = (1 - Math.Pow(1 - DeltaProcess, 3)) * 300 + If(ChangeByKey, 100, 0)
  47. AniStart({
  48. AaWidth(LineFore, Math.Max(0, NewWidth + If(NewWidth < 0.5, 0, 0.5)) - LineFore.Width, Time,, If(Time > 50, New AniEaseOutFluent, New AniEaseLinear)),
  49. AaWidth(LineBack, Math.Max(0, ActualWidth - ShapeDot.Width - NewWidth + If(ActualWidth - ShapeDot.Width - NewWidth < 0.5, 0, 0.5)) - LineBack.Width, Time,, If(Time > 50, New AniEaseOutFluent, New AniEaseLinear)),
  50. AaX(ShapeDot, NewWidth - ShapeDot.Margin.Left, Time,, If(Time > 50, New AniEaseOutFluent, New AniEaseLinear))
  51. }, "MySlider Progress " & Uuid)
  52. Else
  53. RefreshWidth(Nothing, Nothing)
  54. End If
  55. If AniControlEnabled = 0 Then RaiseEvent Change(Me, False)
  56. Catch ex As Exception
  57. Logger.Error(ex, "滑动条进度改变出错", LogBehavior.Toast)
  58. End Try
  59. End Set
  60. End Property
  61. Private Sub RefreshWidth(sender As Object, e As SizeChangedEventArgs) Handles Me.SizeChanged
  62. If Not IsNothing(e) Then PanMain.Width = e.NewSize.Width
  63. AniStop("MySlider Progress " & Uuid)
  64. Dim NewWidth As Double = _Value / MaxValue * (ActualWidth - ShapeDot.Width)
  65. LineFore.Width = Math.Max(0, NewWidth + If(NewWidth < 0.5, 0, 0.5))
  66. LineBack.Width = Math.Max(0, ActualWidth - ShapeDot.Width - NewWidth + If(ActualWidth - ShapeDot.Width - NewWidth < 0.5, 0, 0.5))
  67. ShapeDot.Margin = New Thickness(NewWidth, ShapeDot.Margin.Top, ShapeDot.Margin.Right, ShapeDot.Margin.Bottom)
  68. End Sub
  69. '拖动
  70. Public GetHintText As [Delegate]
  71. Private Sub DragStart(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonDown
  72. e.Handled = True '防止 ScrollViewer 失焦问题
  73. DragControl = Me
  74. RefreshColor()
  75. FrmMain.DragDoing()
  76. AniStart({
  77. AaScaleTransform(ShapeDot, 1.3 - CType(ShapeDot.RenderTransform, ScaleTransform).ScaleX, 40,, New AniEaseOutFluent)
  78. }, "MySlider Scale " & Uuid)
  79. RefreshPopup()
  80. AniStop("MySlider KeyPopup " & Uuid)
  81. End Sub
  82. Public Sub DragDoing()
  83. Dim Percent As Double = ((Mouse.GetPosition(PanMain).X - ShapeDot.Width / 2) / (ActualWidth - ShapeDot.Width)).Clamp(0, 1)
  84. Dim NewValue As Integer = Percent * MaxValue
  85. If Not NewValue = Value Then
  86. Value = NewValue
  87. End If
  88. RefreshPopup()
  89. End Sub
  90. Public Sub DragStop()
  91. RefreshColor()
  92. AniStart({
  93. AaScaleTransform(ShapeDot, 1 - CType(ShapeDot.RenderTransform, ScaleTransform).ScaleX, 200,, New AniEaseOutFluent)
  94. }, "MySlider Scale " & Uuid)
  95. Popup.IsOpen = False
  96. End Sub
  97. Public Sub RefreshPopup()
  98. If GetHintText Is Nothing Then Return
  99. Popup.IsOpen = True
  100. TextHint.Text = GetHintText.DynamicInvoke(Value)
  101. Dim typeface As New Typeface(TextHint.FontFamily, TextHint.FontStyle, TextHint.FontWeight, TextHint.FontStretch)
  102. Dim formattedText As New FormattedText(TextHint.Text, Thread.CurrentThread.CurrentCulture, TextHint.FlowDirection, typeface, TextHint.FontSize, TextHint.Foreground, DPI)
  103. TextHint.Width = formattedText.Width '使用手动测量的宽度修复 #1057
  104. End Sub
  105. '指向动画
  106. Private Sub RefreshColor() Handles Me.IsEnabledChanged, Me.MouseEnter, Me.MouseLeave
  107. Try
  108. '判断当前颜色
  109. Dim ForegroundName As String, DotFillName As String
  110. Dim AnimationTime As Integer
  111. If IsEnabled Then
  112. If Not IsNothing(DragControl) AndAlso DragControl.Equals(Me) Then
  113. ForegroundName = "ColorBrush3"
  114. DotFillName = "ColorBrush3"
  115. AnimationTime = 40
  116. ElseIf IsMouseOver Then
  117. ForegroundName = "ColorBrush3"
  118. DotFillName = "ColorBrush3"
  119. AnimationTime = 40
  120. Else
  121. ForegroundName = "ColorBrushBg0"
  122. DotFillName = "ColorBrushBg0"
  123. AnimationTime = 100
  124. End If
  125. Else
  126. ForegroundName = "ColorBrushGray5"
  127. DotFillName = "ColorBrushGray5"
  128. AnimationTime = 200
  129. End If
  130. '触发颜色动画
  131. If IsLoaded AndAlso AniControlEnabled = 0 Then '防止默认属性变更触发动画
  132. '有动画
  133. AniStart({
  134. AaColor(Me, BorderBrushProperty, ForegroundName, AnimationTime),
  135. AaColor(ShapeDot, Ellipse.FillProperty, DotFillName, AnimationTime)
  136. }, "MySlider Color " & Uuid)
  137. Else
  138. '无动画
  139. AniStop("MySlider Color " & Uuid)
  140. SetResourceReference(BorderBrushProperty, ForegroundName)
  141. ShapeDot.SetResourceReference(Ellipse.FillProperty, DotFillName)
  142. End If
  143. Catch ex As Exception
  144. Logger.Warn(ex, "滑动条颜色改变出错")
  145. End Try
  146. End Sub
  147. '按键改变
  148. Public Property ValueByKey As UInteger = 1
  149. Private Sub MySlider_MouseEnter() Handles Me.MouseEnter
  150. Focus() '确保按键能改变值
  151. End Sub
  152. Private Sub MySlider_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
  153. '拒绝一边拖动一边用按键改变
  154. If ReferenceEquals(Me, DragControl) Then Return
  155. '改变值
  156. If e.Key = Key.Left Then
  157. ChangeByKey = True
  158. Value -= ValueByKey
  159. ChangeByKey = False
  160. e.Handled = True
  161. ElseIf e.Key = Key.Right Then
  162. ChangeByKey = True
  163. Value += ValueByKey
  164. ChangeByKey = False
  165. e.Handled = True
  166. Else
  167. Return
  168. End If
  169. '更新 Popup
  170. If GetHintText IsNot Nothing Then
  171. RefreshPopup()
  172. AniStop("MySlider KeyPopup " & Uuid)
  173. AniStart(AaCode(Sub() Popup.IsOpen = False, 700 * AniSpeed), "MySlider KeyPopup " & Uuid)
  174. End If
  175. End Sub
  176. #Region "设置"
  177. Private Sub RefreshSetting(NewValue As String) Implements ISettingControl.RefreshSetting
  178. Value = Val(NewValue)
  179. End Sub
  180. Private Function GetCurrentSetting() As String Implements ISettingControl.GetCurrentSetting
  181. Return Value
  182. End Function
  183. Private Sub SaveSetting() Handles Me.Change
  184. SettingService.SaveSetting(Me)
  185. End Sub
  186. #End Region
  187. End Class