MyRadioBox.xaml.vb 12 KB

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