MyCheckBox.xaml.vb 10 KB

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