MyRadioBox.xaml.vb 12 KB

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