MySlider.xaml.vb 7.6 KB

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