MyCheckBox.xaml.vb 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. Imports System.Windows.Markup
  2. <ContentProperty("Inlines")>
  3. Public Class MyCheckBox
  4. '基础
  5. Public Uuid As Integer = GetUuid()
  6. ''' <summary>
  7. ''' 复选框勾选状态改变。
  8. ''' </summary>
  9. ''' <param name="user">是否为用户手动改变的勾选状态。</param>
  10. Public Event Change(sender As Object, user As Boolean)
  11. Public Event PreviewChange(sender As Object, e As RouteEventArgs)
  12. '自定义属性
  13. Public Property Checked As Boolean
  14. Get
  15. Return GetValue(CheckedProperty)
  16. End Get
  17. Set(value As Boolean)
  18. SetChecked(value, False)
  19. End Set
  20. End Property
  21. Public Shared ReadOnly CheckedProperty As DependencyProperty =
  22. DependencyProperty.Register("Checked", GetType(Boolean), GetType(MyCheckBox), New PropertyMetadata(False,
  23. Sub(d As MyCheckBox, e As DependencyPropertyChangedEventArgs)
  24. '在使用 XAML 设置 Checked 属性时,不会触发 Checked_Set 方法,所以需要在这里手动触发 UI 改变
  25. If Not d.IsLoaded Then d.SyncUI()
  26. End Sub))
  27. Private Const AnimationTimeOfCheck As Integer = 150 '勾选状态变更动画长度
  28. ''' <summary>
  29. ''' 手动设置 Checked 属性。
  30. ''' </summary>
  31. ''' <param name="value">新的 Checked 属性。</param>
  32. ''' <param name="user">是否由用户引发。</param>
  33. Public Sub SetChecked(value As Boolean, user As Boolean)
  34. Try
  35. If value = Checked Then Return
  36. 'Preview 事件
  37. If value AndAlso user Then
  38. Dim e = New RouteEventArgs(user)
  39. RaiseEvent PreviewChange(Me, e)
  40. If e.Handled Then
  41. MouseDowned = True
  42. Checkbox_MouseLeave()
  43. MouseDowned = False
  44. Return
  45. End If
  46. End If
  47. SetValue(CheckedProperty, value)
  48. If IsLoaded Then RaiseEvent Change(Me, user)
  49. '更改动画
  50. SyncUI()
  51. RaiseCustomEvent()
  52. Catch ex As Exception
  53. Log(ex, "设置 Checked 失败")
  54. End Try
  55. End Sub
  56. Private Sub SyncUI()
  57. If AniControlEnabled = 0 AndAlso IsLoaded Then '防止默认属性变更触发动画
  58. AllowMouseDown = False
  59. If Checked Then
  60. '由无变有
  61. AniStart({
  62. AaScale(ShapeBorder, 12 - ShapeBorder.Width, AnimationTimeOfCheck, , New AniEaseOutFluent, , True),
  63. AaScaleTransform(ShapeCheck, 1 - CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleX, AnimationTimeOfCheck * 2, AnimationTimeOfCheck * 0.7, New AniEaseOutBack(AniEasePower.Weak)),
  64. AaScale(ShapeBorder, 6, AnimationTimeOfCheck * 2, AnimationTimeOfCheck * 0.7, New AniEaseOutBack, , True)
  65. }, "MyCheckBox Scale " & Uuid)
  66. AniStart({
  67. AaColor(ShapeBorder, Border.BorderBrushProperty, If(IsEnabled, If(IsMouseOver, "ColorBrush3", "ColorBrush2"), "ColorBrushGray4"), AnimationTimeOfCheck)
  68. }, "MyCheckBox BorderColor " & Uuid)
  69. AniStart({
  70. AaCode(Sub() AllowMouseDown = True, AnimationTimeOfCheck * 2)
  71. }, "MyCheckBox AllowMouseDown " & Uuid)
  72. Else
  73. '由有变无
  74. AniStart({
  75. AaScale(ShapeBorder, 12 - ShapeBorder.Width, AnimationTimeOfCheck, , New AniEaseOutFluent, , True),
  76. AaScaleTransform(ShapeCheck, -CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleX, AnimationTimeOfCheck * 0.9, , New AniEaseInFluent(AniEasePower.Weak)),
  77. AaScale(ShapeBorder, 6, AnimationTimeOfCheck * 2, AnimationTimeOfCheck * 0.7, New AniEaseOutBack, , True)
  78. }, "MyCheckBox Scale " & Uuid)
  79. AniStart({
  80. AaColor(ShapeBorder, Border.BorderBrushProperty, If(IsEnabled, If(IsMouseOver, "ColorBrush3", "ColorBrush1"), "ColorBrushGray4"), AnimationTimeOfCheck)
  81. }, "MyCheckBox BorderColor " & Uuid)
  82. AniStart({
  83. AaCode(Sub() AllowMouseDown = True, AnimationTimeOfCheck * 2)
  84. }, "MyCheckBox AllowMouseDown " & Uuid)
  85. End If
  86. Else
  87. '不使用动画
  88. AniStop("MyCheckBox Scale " & Uuid)
  89. AniStop("MyCheckBox BorderColor " & Uuid)
  90. AniStop("MyCheckBox AllowMouseDown " & Uuid)
  91. If Checked Then
  92. CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleX = 1
  93. CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleY = 1
  94. ShapeBorder.SetResourceReference(Border.BorderBrushProperty, If(IsEnabled, "ColorBrush2", "ColorBrushGray4"))
  95. Else
  96. CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleX = 0
  97. CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleY = 0
  98. ShapeBorder.SetResourceReference(Border.BorderBrushProperty, If(IsEnabled, "ColorBrush1", "ColorBrushGray4"))
  99. End If
  100. End If
  101. End Sub
  102. Public ReadOnly Property Inlines As InlineCollection
  103. Get
  104. Return LabText.Inlines
  105. End Get
  106. End Property
  107. Public Property Text As String
  108. Get
  109. Return GetValue(TextProperty)
  110. End Get
  111. Set(value As String)
  112. SetValue(TextProperty, value)
  113. End Set
  114. End Property '内容
  115. Public Shared ReadOnly TextProperty As DependencyProperty = DependencyProperty.Register("Text", GetType(String), GetType(MyCheckBox), New PropertyMetadata(New PropertyChangedCallback(
  116. Sub(sender As DependencyObject, e As DependencyPropertyChangedEventArgs)
  117. If Not IsNothing(sender) Then CType(sender, MyCheckBox).LabText.Text = e.NewValue
  118. End Sub)))
  119. '点击事件
  120. Private MouseDowned As Boolean = False
  121. Private AllowMouseDown As Boolean = True
  122. Private Sub Checkbox_MouseUp() Handles Me.MouseLeftButtonUp
  123. If Not MouseDowned Then Return
  124. Log("[Control] 按下复选框(" & (Not Checked).ToString & "):" & Text)
  125. MouseDowned = False
  126. SetChecked(Not Checked, True)
  127. AniStart(AaColor(ShapeBorder, Border.BackgroundProperty, "ColorBrushHalfWhite", 100), "MyCheckBox Background " & Uuid)
  128. End Sub
  129. Private Sub Checkbox_MouseDown() Handles Me.MouseLeftButtonDown
  130. If Not AllowMouseDown Then Return
  131. MouseDowned = True
  132. Focus()
  133. AniStart(AaColor(ShapeBorder, Border.BackgroundProperty, "ColorBrushBg1", 100), "MyCheckBox Background " & Uuid)
  134. If Checked Then
  135. AniStart({
  136. AaScale(ShapeBorder, 16.5 - ShapeBorder.Width, 1000, , New AniEaseOutFluent(AniEasePower.Strong), Absolute:=True),
  137. AaScaleTransform(ShapeCheck, 0.9 - CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleX, 1000, , New AniEaseOutFluent(AniEasePower.Strong))
  138. }, "MyCheckBox Scale " & Uuid)
  139. Else
  140. AniStart(AaScale(ShapeBorder, 16.5 - ShapeBorder.Width, 1000, , New AniEaseOutFluent(AniEasePower.Strong), Absolute:=True), "MyCheckBox Scale " & Uuid)
  141. End If
  142. End Sub
  143. Private Sub Checkbox_MouseLeave() Handles Me.MouseLeave
  144. If Not MouseDowned Then Return
  145. MouseDowned = False
  146. AniStart(AaColor(ShapeBorder, Border.BackgroundProperty, "ColorBrushHalfWhite", 100), "MyCheckBox Background " & Uuid)
  147. If Checked Then
  148. AniStart({
  149. AaScale(ShapeBorder, 18 - ShapeBorder.Width, 400, , New AniEaseOutFluent(AniEasePower.Strong), Absolute:=True),
  150. AaScaleTransform(ShapeCheck, 1 - CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleX, 500, , New AniEaseOutFluent(AniEasePower.Strong))
  151. }, "MyCheckBox Scale " & Uuid)
  152. Else
  153. AniStart(AaScale(ShapeBorder, 18 - ShapeBorder.Width, 400, , New AniEaseOutFluent(AniEasePower.Strong), Absolute:=True), "MyCheckBox Scale " & Uuid)
  154. End If
  155. End Sub
  156. '指向动画
  157. Private Const AnimationTimeOfMouseIn As Integer = 100
  158. Private Const AnimationTimeOfMouseOut As Integer = 200
  159. Private Sub Checkbox_IsEnabledChanged() Handles Me.IsEnabledChanged
  160. If IsLoaded AndAlso AniControlEnabled = 0 Then '防止默认属性变更触发动画
  161. '有动画
  162. If IsEnabled Then
  163. '可用
  164. Checkbox_MouseLeaveAnimation()
  165. Else
  166. '不可用
  167. AniStart({
  168. AaColor(ShapeBorder, Border.BorderBrushProperty, ColorGray4 - ShapeBorder.BorderBrush, AnimationTimeOfMouseOut)
  169. }, "MyCheckBox BorderColor " & Uuid)
  170. AniStart({
  171. AaColor(LabText, TextBlock.ForegroundProperty, ColorGray4 - LabText.Foreground, AnimationTimeOfMouseOut)
  172. }, "MyCheckBox TextColor " & Uuid)
  173. End If
  174. Else
  175. '无动画
  176. AniStop("MyCheckBox TextColor " & Uuid)
  177. AniStop("MyCheckBox BorderColor " & Uuid)
  178. LabText.SetResourceReference(TextBlock.ForegroundProperty, If(Me.IsEnabled, "ColorBrush1", "ColorBrushGray4"))
  179. ShapeBorder.SetResourceReference(Border.BorderBrushProperty, If(Me.IsEnabled, If(Checked, "ColorBrush2", "ColorBrush1"), "ColorBrushGray4"))
  180. End If
  181. End Sub
  182. Private Sub Checkbox_MouseEnterAnimation() Handles Me.MouseEnter
  183. AniStart({
  184. AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrush3", AnimationTimeOfMouseIn)
  185. }, "MyCheckBox TextColor " & Uuid)
  186. AniStart({
  187. AaColor(ShapeBorder, Border.BorderBrushProperty, "ColorBrush3", AnimationTimeOfMouseIn)
  188. }, "MyCheckBox BorderColor " & Uuid)
  189. End Sub
  190. Private Sub Checkbox_MouseLeaveAnimation() Handles Me.MouseLeave
  191. If Not IsEnabled Then Return 'MouseLeave 比 IsEnabledChanged 后执行,所以如果自定义事件修改了 IsEnabled,将导致显示错误
  192. AniStart({
  193. AaColor(LabText, TextBlock.ForegroundProperty, If(Me.IsEnabled, "ColorBrush1", "ColorBrushGray4"), AnimationTimeOfMouseOut)
  194. }, "MyCheckBox TextColor " & Uuid)
  195. AniStart({
  196. AaColor(ShapeBorder, Border.BorderBrushProperty, If(Me.IsEnabled, If(Checked, "ColorBrush2", "ColorBrush1"), "ColorBrushGray4"), AnimationTimeOfMouseOut)
  197. }, "MyCheckBox BorderColor " & Uuid)
  198. End Sub
  199. End Class