MyRadioButton.xaml.vb 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. Imports System.Windows.Markup
  2. <ContentProperty("Inlines")>
  3. Public Class MyRadioButton
  4. '基础
  5. Public Uuid As Integer = GetUuid()
  6. Public Event Check(sender As Object, raiseByMouse As Boolean)
  7. '自定义属性
  8. Public Property Logo As String
  9. Get
  10. Return ShapeLogo.Data.ToString
  11. End Get
  12. Set(value As String)
  13. ShapeLogo.Data = (New GeometryConverter).ConvertFromString(value)
  14. End Set
  15. End Property
  16. Private _LogoScale As Double = 1
  17. Public Property LogoScale() As Double
  18. Get
  19. Return _LogoScale
  20. End Get
  21. Set(value As Double)
  22. _LogoScale = value
  23. If Not IsNothing(ShapeLogo) Then ShapeLogo.RenderTransform = New ScaleTransform With {.ScaleX = LogoScale, .ScaleY = LogoScale}
  24. End Set
  25. End Property
  26. Private _Checked As Boolean = False '是否选中
  27. Public Property Checked As Boolean
  28. Get
  29. Return _Checked
  30. End Get
  31. Set(value As Boolean)
  32. SetChecked(value, False, True)
  33. End Set
  34. End Property
  35. ''' <summary>
  36. ''' 手动设置 Checked 属性。
  37. ''' </summary>
  38. ''' <param name="value">新的 Checked 属性。</param>
  39. ''' <param name="raiseByMouse">是否由用户引发。</param>
  40. ''' <param name="anime">是否执行动画。</param>
  41. Public Sub SetChecked(value As Boolean, raiseByMouse As Boolean, anime As Boolean)
  42. Try
  43. '自定义属性基础
  44. Dim IsChanged As Boolean = False
  45. If _Checked <> value Then
  46. _Checked = value
  47. IsChanged = True
  48. End If
  49. '保证只有一个单选框选中
  50. If Parent Is Nothing Then Return
  51. Dim RadioboxList As New List(Of MyRadioButton)
  52. Dim CheckedCount As Integer = 0
  53. '收集控件列表与选中个数
  54. For Each Control In CType(Parent, Object).Children
  55. If TypeOf Control Is MyRadioButton Then
  56. RadioboxList.Add(Control)
  57. If Control.Checked Then CheckedCount += 1
  58. End If
  59. Next
  60. '判断选中情况
  61. Select Case CheckedCount
  62. Case 0
  63. '没有任何单选框被选中,选择第一个
  64. RadioboxList(0).Checked = True
  65. Case Is > 1
  66. '选中项目多于 1 个
  67. If Me.Checked Then
  68. '如果本控件选中,则取消其他所有控件的选中
  69. For Each Control As MyRadioButton In RadioboxList
  70. If Control.Checked AndAlso Not Control.Equals(Me) Then Control.Checked = False
  71. Next
  72. Else
  73. '如果本控件未选中,则只保留第一个选中的控件
  74. Dim FirstChecked = False
  75. For Each Control As MyRadioButton In RadioboxList
  76. If Control.Checked Then
  77. If FirstChecked Then
  78. Control.Checked = False '修改 Checked 会自动触发 Change 事件,所以不用额外触发
  79. Else
  80. FirstChecked = True
  81. End If
  82. End If
  83. Next
  84. End If
  85. End Select
  86. '更改动画
  87. If Not IsChanged Then Return
  88. RefreshColor(Nothing, anime)
  89. '触发事件
  90. If Checked Then RaiseEvent Check(Me, raiseByMouse)
  91. RaiseCustomEvent()
  92. Catch ex As Exception
  93. Logger.Error(ex, "单选按钮勾选改变错误", LogBehavior.Toast)
  94. End Try
  95. End Sub
  96. Public ReadOnly Property Inlines As InlineCollection
  97. Get
  98. Return LabText.Inlines
  99. End Get
  100. End Property
  101. Public Property Text As String
  102. Get
  103. Return GetValue(TextProperty)
  104. End Get
  105. Set(value As String)
  106. SetValue(TextProperty, value)
  107. End Set
  108. End Property '内容
  109. Public Shared ReadOnly TextProperty As DependencyProperty = DependencyProperty.Register("Text", GetType(String), GetType(MyRadioButton), New PropertyMetadata(New PropertyChangedCallback(
  110. Sub(sender, e) If sender IsNot Nothing Then CType(sender, MyRadioButton).LabText.Text = e.NewValue)))
  111. Public Enum ColorState
  112. White
  113. Highlight
  114. End Enum
  115. Private _ColorType As ColorState = ColorState.White
  116. Public Property ColorType As ColorState
  117. Get
  118. Return _ColorType
  119. End Get
  120. Set(value As ColorState)
  121. _ColorType = value
  122. RefreshColor()
  123. End Set
  124. End Property '颜色类别
  125. '点击事件
  126. Public Event PreviewClick(sender As Object, e As RouteEventArgs)
  127. Private IsMouseDown As Boolean = False
  128. Private Sub Radiobox_MouseUp() Handles Me.MouseLeftButtonUp
  129. If Checked Then Return
  130. If Not IsMouseDown Then Return
  131. Logger.Info($"按下单选按钮:{Text}")
  132. IsMouseDown = False
  133. Dim e As New RouteEventArgs(True)
  134. RaiseEvent PreviewClick(Me, e)
  135. If e.Handled Then Return
  136. SetChecked(True, True, True)
  137. End Sub
  138. Private Sub Radiobox_MouseDown() Handles Me.MouseLeftButtonDown
  139. If Checked Then Return
  140. IsMouseDown = True
  141. RefreshColor()
  142. End Sub
  143. Private Sub Radiobox_MouseLeave() Handles Me.MouseLeave
  144. IsMouseDown = False
  145. End Sub
  146. '动画
  147. Private Const AnimationTimeOfMouseIn As Integer = 90 '鼠标指向动画长度
  148. Private Const AnimationTimeOfMouseOut As Integer = 150 '鼠标移出动画长度
  149. Private Const AnimationTimeOfCheck As Integer = 120 '勾选状态变更动画长度
  150. Private Sub RefreshColor(Optional obj = Nothing, Optional e = Nothing) Handles Me.MouseEnter, Me.MouseLeave, Me.Loaded
  151. Cursor = If(Checked, Nothing, Cursors.Hand)
  152. Try
  153. If IsLoaded AndAlso AniControlEnabled = 0 AndAlso Not False.Equals(e) Then '防止默认属性变更触发动画,若强制不执行动画,则 e 为 False
  154. Select Case ColorType
  155. Case ColorState.White
  156. If Checked Then
  157. '勾选
  158. AniStart({
  159. AaColor(ShapeLogo, Shapes.Path.FillProperty, "ColorBrush3", AnimationTimeOfCheck),
  160. AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrush3", AnimationTimeOfCheck)
  161. }, "MyRadioButton Checked " & Uuid)
  162. AniStart(AaColor(Me, BackgroundProperty, New MyColor(255, 255, 255) - Background, AnimationTimeOfCheck), "MyRadioButton Color " & Uuid)
  163. ElseIf IsMouseDown Then
  164. '按下
  165. AniStart(AaColor(Me, BackgroundProperty, New MyColor(120, Color8) - Background, 60), "MyRadioButton Color " & Uuid)
  166. ElseIf IsMouseOver Then
  167. '指向
  168. AniStart({
  169. AaColor(ShapeLogo, Shapes.Path.FillProperty, New MyColor(255, 255, 255) - ShapeLogo.Fill, AnimationTimeOfMouseIn),
  170. AaColor(LabText, TextBlock.ForegroundProperty, New MyColor(255, 255, 255) - LabText.Foreground, AnimationTimeOfMouseIn)
  171. }, "MyRadioButton Checked " & Uuid)
  172. AniStart(AaColor(Me, BackgroundProperty, New MyColor(50, Color8) - Background, AnimationTimeOfMouseIn), "MyRadioButton Color " & Uuid)
  173. Else
  174. '正常
  175. AniStart({
  176. AaColor(ShapeLogo, Shapes.Path.FillProperty, New MyColor(255, 255, 255) - ShapeLogo.Fill, AnimationTimeOfMouseOut),
  177. AaColor(LabText, TextBlock.ForegroundProperty, New MyColor(255, 255, 255) - LabText.Foreground, AnimationTimeOfMouseOut)
  178. }, "MyRadioButton Checked " & Uuid)
  179. AniStart(AaColor(Me, BackgroundProperty, ColorSemiTransparent - Background, AnimationTimeOfMouseOut), "MyRadioButton Color " & Uuid)
  180. End If
  181. Case ColorState.Highlight
  182. If Checked Then
  183. '勾选
  184. AniStart({
  185. AaColor(ShapeLogo, Shapes.Path.FillProperty, New MyColor(255, 255, 255) - ShapeLogo.Fill, AnimationTimeOfCheck),
  186. AaColor(LabText, TextBlock.ForegroundProperty, New MyColor(255, 255, 255) - LabText.Foreground, AnimationTimeOfCheck)
  187. }, "MyRadioButton Checked " & Uuid)
  188. AniStart(AaColor(Me, BackgroundProperty, "ColorBrush3", AnimationTimeOfCheck), "MyRadioButton Color " & Uuid)
  189. ElseIf IsMouseDown Then
  190. '按下
  191. AniStart(AaColor(Me, BackgroundProperty, "ColorBrush6", AnimationTimeOfMouseIn), "MyRadioButton Color " & Uuid)
  192. ElseIf IsMouseOver Then
  193. '指向
  194. AniStart({
  195. AaColor(ShapeLogo, Shapes.Path.FillProperty, "ColorBrush3", AnimationTimeOfMouseIn),
  196. AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrush3", AnimationTimeOfMouseIn)
  197. }, "MyRadioButton Checked " & Uuid)
  198. AniStart(AaColor(Me, BackgroundProperty, "ColorBrush7", AnimationTimeOfMouseIn), "MyRadioButton Color " & Uuid)
  199. Else
  200. '正常
  201. AniStart({
  202. AaColor(ShapeLogo, Shapes.Path.FillProperty, "ColorBrush3", AnimationTimeOfMouseOut),
  203. AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrush3", AnimationTimeOfMouseOut)
  204. }, "MyRadioButton Checked " & Uuid)
  205. AniStart(AaColor(Me, BackgroundProperty, ColorSemiTransparent - Background, AnimationTimeOfMouseOut), "MyRadioButton Color " & Uuid)
  206. End If
  207. End Select
  208. Else
  209. '不使用动画
  210. AniStop("MyRadioButton Checked " & Uuid)
  211. AniStop("MyRadioButton Color " & Uuid)
  212. Select Case ColorType
  213. Case ColorState.White
  214. If Checked Then
  215. Background = New MyColor(255, 255, 255)
  216. ShapeLogo.SetResourceReference(Shapes.Path.FillProperty, "ColorBrush3")
  217. LabText.SetResourceReference(TextBlock.ForegroundProperty, "ColorBrush3")
  218. Else
  219. Background = ColorSemiTransparent
  220. ShapeLogo.Fill = New MyColor(255, 255, 255)
  221. LabText.Foreground = New MyColor(255, 255, 255)
  222. End If
  223. Case ColorState.Highlight
  224. If Checked Then
  225. SetResourceReference(BackgroundProperty, "ColorBrush3")
  226. ShapeLogo.Fill = New MyColor(255, 255, 255)
  227. LabText.Foreground = New MyColor(255, 255, 255)
  228. Else
  229. Background = ColorSemiTransparent
  230. ShapeLogo.SetResourceReference(Shapes.Path.FillProperty, "ColorBrush3")
  231. LabText.SetResourceReference(TextBlock.ForegroundProperty, "ColorBrush3")
  232. End If
  233. End Select
  234. End If
  235. Catch ex As Exception
  236. Logger.Warn(ex, "刷新单选按钮颜色出错")
  237. End Try
  238. End Sub
  239. End Class