MyRadioBox.xaml.vb 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. Public Class MyRadioBox
  2. Implements IMyRadio
  3. '基础
  4. Public Uuid As Integer = GetUuid()
  5. Public Event PreviewCheck(sender As Object, e As RouteEventArgs)
  6. Public Event PreviewChange(sender As Object, e As RouteEventArgs)
  7. Public Event Check(sender As Object, e As RouteEventArgs) Implements IMyRadio.Check
  8. Public Event Changed(sender As Object, e As RouteEventArgs) Implements IMyRadio.Changed
  9. '自定义属性
  10. Private _Checked As Boolean = False '是否选中
  11. Public Property Checked As Boolean
  12. Get
  13. Return _Checked
  14. End Get
  15. Set(value As Boolean)
  16. SetChecked(value, False, True)
  17. End Set
  18. End Property
  19. ''' <summary>
  20. ''' 手动设置 Checked 属性。
  21. ''' </summary>
  22. ''' <param name="value">新的 Checked 属性。</param>
  23. ''' <param name="user">是否由用户引发。</param>
  24. ''' <param name="anime">是否执行动画。</param>
  25. Public Sub SetChecked(value As Boolean, user As Boolean, anime As Boolean)
  26. Try
  27. 'Preview 事件
  28. If value AndAlso user Then
  29. Dim e = New RouteEventArgs(user)
  30. RaiseEvent PreviewCheck(Me, e)
  31. If e.Handled Then
  32. Radiobox_MouseLeave()
  33. Exit Sub
  34. End If
  35. End If
  36. '自定义属性基础
  37. Dim IsChanged As Boolean = False
  38. If IsLoaded AndAlso Not value = _Checked Then RaiseEvent PreviewChange(Me, New RouteEventArgs(user))
  39. If Not value = _Checked Then
  40. _Checked = value
  41. IsChanged = True
  42. End If
  43. '保证只有一个单选框选中
  44. If Parent Is Nothing Then Exit Sub
  45. Dim RadioboxList As New List(Of MyRadioBox)
  46. Dim CheckedCount As Integer = 0
  47. '收集控件列表与选中个数
  48. For Each Control In CType(Parent, Object).Children
  49. If TypeOf Control Is MyRadioBox Then
  50. RadioboxList.Add(Control)
  51. If Control.Checked Then CheckedCount += 1
  52. End If
  53. Next
  54. '判断选中情况
  55. Select Case CheckedCount
  56. Case 0
  57. '没有任何单选框被选中,选择第一个
  58. RadioboxList(0).Checked = True
  59. Case Is > 1
  60. '选中项目多于 1 个
  61. If Checked Then
  62. '如果本控件选中,则取消其他所有控件的选中
  63. For Each Control As MyRadioBox In RadioboxList
  64. If Control.Checked AndAlso Not Control.Equals(Me) Then Control.Checked = False
  65. Next
  66. Else
  67. '如果本控件未选中,则只保留第一个选中的控件
  68. Dim FirstChecked = False
  69. For Each Control As MyRadioBox In RadioboxList
  70. If Control.Checked Then
  71. If FirstChecked Then
  72. Control.Checked = False '修改 Checked 会自动触发 Change 事件,所以不用额外触发
  73. Else
  74. FirstChecked = True
  75. End If
  76. End If
  77. Next
  78. End If
  79. End Select
  80. 'End If
  81. '更改动画
  82. If Not IsChanged Then Exit Sub
  83. If IsLoaded AndAlso AniControlEnabled = 0 AndAlso anime Then '防止默认属性变更触发动画
  84. If Checked Then
  85. '由无变有
  86. If ShapeDot.Opacity < 0.01 Then ShapeDot.Opacity = 1
  87. AniStart({
  88. AaScale(ShapeBorder, 10 - ShapeBorder.Width, AnimationTimeOfCheck, , New AniEaseOutFluent(AniEasePower.Weak), , True),
  89. AaScale(ShapeBorder, 8, AnimationTimeOfCheck * 2, AnimationTimeOfCheck * 0.6, New AniEaseOutBack, , True)
  90. }, "MyRadioBox Border " & Uuid)
  91. AniStart({
  92. AaScale(ShapeDot, 9 - ShapeDot.Width, AnimationTimeOfCheck * 2.6,, New AniEaseOutBack(AniEasePower.Weak), , True),
  93. AaOpacity(ShapeDot, 1 - ShapeDot.Opacity, AnimationTimeOfCheck * 0.5, AnimationTimeOfCheck * 0.6)
  94. }, "MyRadioBox Dot " & Uuid)
  95. AniStart({
  96. AaColor(ShapeBorder, Ellipse.StrokeProperty, If(IsMouseOver, "ColorBrush3", If(IsEnabled, "ColorBrush2", "ColorBrushGray4")), AnimationTimeOfCheck)
  97. }, "MyRadioBox BorderColor " & Uuid)
  98. Else
  99. '由有变无
  100. AniStart({
  101. AaScale(ShapeBorder, 18 - ShapeBorder.Width, AnimationTimeOfCheck, , New AniEaseOutFluent, , True)
  102. }, "MyRadioBox Border " & Uuid)
  103. AniStart({
  104. AaScale(ShapeDot, -ShapeDot.Width, AnimationTimeOfCheck, , New AniEaseInFluent, , True),
  105. AaOpacity(ShapeDot, -ShapeDot.Opacity, AnimationTimeOfCheck * 0.5, AnimationTimeOfCheck * 0.2)
  106. }, "MyRadioBox Dot " & Uuid)
  107. AniStart({
  108. AaColor(ShapeBorder, Ellipse.StrokeProperty, If(IsMouseOver, "ColorBrush3", If(IsEnabled, "ColorBrush1", "ColorBrushGray4")), AnimationTimeOfCheck)
  109. }, "MyRadioBox BorderColor " & Uuid)
  110. End If
  111. Else
  112. '不使用动画
  113. AniStop("MyRadioBox Border " & Uuid)
  114. AniStop("MyRadioBox Dot " & Uuid)
  115. AniStop("MyRadioBox BorderColor " & Uuid)
  116. If Checked Then
  117. ShapeDot.Width = 9
  118. ShapeDot.Height = 9
  119. ShapeDot.Opacity = 1
  120. ShapeDot.Margin = New Thickness(5.5, 0, 0, 0)
  121. ShapeBorder.SetResourceReference(Ellipse.StrokeProperty, If(IsEnabled, "ColorBrush2", "ColorBrushGray4"))
  122. Else
  123. ShapeDot.Width = 0
  124. ShapeDot.Height = 0
  125. ShapeDot.Opacity = 0
  126. ShapeDot.Margin = New Thickness(10, 0, 0, 0)
  127. ShapeBorder.SetResourceReference(Ellipse.StrokeProperty, If(IsEnabled, "ColorBrush1", "ColorBrushGray4"))
  128. End If
  129. End If
  130. '触发事件
  131. If Checked Then RaiseEvent Check(Me, New RouteEventArgs(user))
  132. RaiseEvent Changed(Me, New RouteEventArgs(user))
  133. Catch ex As Exception
  134. Log(ex, "单选框勾选改变错误", LogLevel.Hint)
  135. End Try
  136. End Sub
  137. Public Property Text As String
  138. Get
  139. Return GetValue(TextProperty)
  140. End Get
  141. Set(value As String)
  142. SetValue(TextProperty, value)
  143. End Set
  144. End Property '内容
  145. Public Shared ReadOnly TextProperty As DependencyProperty = DependencyProperty.Register("Text", GetType(String), GetType(MyRadioBox), New PropertyMetadata(New PropertyChangedCallback(
  146. Sub(sender As DependencyObject, e As DependencyPropertyChangedEventArgs)
  147. If Not IsNothing(sender) Then CType(sender, MyRadioBox).LabText.Text = e.NewValue
  148. End Sub)))
  149. '点击事件
  150. Private MouseDowned As Boolean = False
  151. Private AllowMouseDown As Boolean = True
  152. Private Sub Radiobox_MouseUp() Handles Me.MouseLeftButtonUp
  153. If Not MouseDowned Then Exit Sub
  154. MouseDowned = False
  155. Log("[Control] 按下单选框:" & Text)
  156. SetChecked(True, True, True)
  157. AniStart(AaColor(ShapeBorder, Ellipse.FillProperty, "ColorBrushBg2", 100), "MyRadioBox Background " & Uuid)
  158. End Sub
  159. Private Sub Radiobox_MouseDown() Handles Me.MouseLeftButtonDown
  160. MouseDowned = True
  161. Focus()
  162. AniStart(AaColor(ShapeBorder, Ellipse.FillProperty, "ColorBrushBg1", 100), "MyRadioBox Background " & Uuid)
  163. If Not Checked Then
  164. AniStart(AaScale(ShapeBorder, 16.5 - ShapeBorder.Width, 1000, , New AniEaseOutFluent(AniEasePower.Strong), Absolute:=True), "MyRadioBox Border " & Uuid)
  165. End If
  166. End Sub
  167. Private Sub Radiobox_MouseLeave() Handles Me.MouseLeave
  168. If Not MouseDowned Then Exit Sub
  169. MouseDowned = False
  170. AniStart(AaColor(ShapeBorder, Ellipse.FillProperty, "ColorBrushBg2", 100), "MyRadioBox Background " & Uuid)
  171. If Not Checked Then
  172. AniStart(AaScale(ShapeBorder, 18 - ShapeBorder.Width, 400, , New AniEaseOutFluent(AniEasePower.Strong), Absolute:=True), "MyRadioBox Border " & Uuid)
  173. End If
  174. End Sub
  175. '指向动画
  176. Private Const AnimationTimeOfMouseIn As Integer = 100 '鼠标指向动画长度
  177. Private Const AnimationTimeOfMouseOut As Integer = 200 '鼠标指向动画长度
  178. Private Const AnimationTimeOfCheck As Integer = 150 '勾选状态变更动画长度
  179. Private Sub Radiobox_IsEnabledChanged() Handles Me.IsEnabledChanged
  180. If Me.IsLoaded AndAlso AniControlEnabled = 0 Then '防止默认属性变更触发动画
  181. '有动画
  182. If Me.IsEnabled Then
  183. '可用
  184. Radiobox_MouseLeaveAnimation()
  185. Else
  186. '不可用
  187. AniStart(AaColor(ShapeBorder, Ellipse.StrokeProperty, ColorGray4 - ShapeBorder.Stroke, AnimationTimeOfMouseOut), "MyRadioBox BorderColor " & Uuid)
  188. AniStart(AaColor(LabText, TextBlock.ForegroundProperty, ColorGray4 - LabText.Foreground, AnimationTimeOfMouseOut), "MyRadioBox TextColor " & Uuid)
  189. End If
  190. Else
  191. '无动画
  192. AniStop("MyRadioBox BorderColor " & Uuid)
  193. AniStop("MyRadioBox TextColor " & Uuid)
  194. LabText.SetResourceReference(TextBlock.ForegroundProperty, If(Me.IsEnabled, "ColorBrush1", "ColorBrushGray4"))
  195. ShapeBorder.SetResourceReference(Ellipse.StrokeProperty, If(Me.IsEnabled, If(Checked, "ColorBrush2", "ColorBrush1"), "ColorBrushGray4"))
  196. End If
  197. End Sub
  198. Private Sub Radiobox_MouseEnterAnimation() Handles Me.MouseEnter
  199. AniStart(AaColor(ShapeBorder, Ellipse.StrokeProperty, "ColorBrush3", AnimationTimeOfMouseIn), "MyRadioBox BorderColor " & Uuid)
  200. AniStart(AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrush3", AnimationTimeOfMouseIn), "MyRadioBox TextColor " & Uuid)
  201. End Sub
  202. Private Sub Radiobox_MouseLeaveAnimation() Handles Me.MouseLeave
  203. If Not Me.IsEnabled Then Exit Sub 'MouseLeave 比 IsEnabledChanged 后执行,所以如果自定义事件修改了 IsEnabled,将导致显示错误
  204. If IsLoaded AndAlso AniControlEnabled = 0 Then
  205. AniStart(AaColor(ShapeBorder, Ellipse.StrokeProperty, If(IsEnabled, If(Checked, "ColorBrush2", "ColorBrush1"), "ColorBrushGray4"), AnimationTimeOfMouseOut), "MyRadioBox BorderColor " & Uuid)
  206. AniStart(AaColor(LabText, TextBlock.ForegroundProperty, If(IsEnabled, "ColorBrush1", "ColorBrushGray4"), AnimationTimeOfMouseOut), "MyRadioBox TextColor " & Uuid)
  207. Else
  208. ShapeBorder.SetResourceReference(Ellipse.StrokeProperty, If(IsEnabled, If(Checked, "ColorBrush2", "ColorBrush1"), "ColorBrushGray4"))
  209. LabText.SetResourceReference(TextBlock.ForegroundProperty, If(IsEnabled, "ColorBrush1", "ColorBrushGray4"))
  210. End If
  211. End Sub
  212. End Class