MySlider.xaml.vb 8.2 KB

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