Imports System.Windows.Markup Public Class MyRadioButton '基础 Public Uuid As Integer = GetUuid() Public Event Check(sender As Object, raiseByMouse As Boolean) '自定义属性 Public Property Logo As String Get Return ShapeLogo.Data.ToString End Get Set(value As String) ShapeLogo.Data = (New GeometryConverter).ConvertFromString(value) End Set End Property Private _LogoScale As Double = 1 Public Property LogoScale() As Double Get Return _LogoScale End Get Set(value As Double) _LogoScale = value If Not IsNothing(ShapeLogo) Then ShapeLogo.RenderTransform = New ScaleTransform With {.ScaleX = LogoScale, .ScaleY = LogoScale} End Set End Property Private _Checked As Boolean = False '是否选中 Public Property Checked As Boolean Get Return _Checked End Get Set(value As Boolean) SetChecked(value, False, True) End Set End Property ''' ''' 手动设置 Checked 属性。 ''' ''' 新的 Checked 属性。 ''' 是否由用户引发。 ''' 是否执行动画。 Public Sub SetChecked(value As Boolean, raiseByMouse As Boolean, anime As Boolean) Try '自定义属性基础 Dim IsChanged As Boolean = False If _Checked <> value Then _Checked = value IsChanged = True End If '保证只有一个单选框选中 If Parent Is Nothing Then Return Dim RadioboxList As New List(Of MyRadioButton) Dim CheckedCount As Integer = 0 '收集控件列表与选中个数 For Each Control In CType(Parent, Object).Children If TypeOf Control Is MyRadioButton Then RadioboxList.Add(Control) If Control.Checked Then CheckedCount += 1 End If Next '判断选中情况 Select Case CheckedCount Case 0 '没有任何单选框被选中,选择第一个 RadioboxList(0).Checked = True Case Is > 1 '选中项目多于 1 个 If Me.Checked Then '如果本控件选中,则取消其他所有控件的选中 For Each Control As MyRadioButton In RadioboxList If Control.Checked AndAlso Not Control.Equals(Me) Then Control.Checked = False Next Else '如果本控件未选中,则只保留第一个选中的控件 Dim FirstChecked = False For Each Control As MyRadioButton In RadioboxList If Control.Checked Then If FirstChecked Then Control.Checked = False '修改 Checked 会自动触发 Change 事件,所以不用额外触发 Else FirstChecked = True End If End If Next End If End Select '更改动画 If Not IsChanged Then Return RefreshColor(Nothing, anime) '触发事件 If Checked Then RaiseEvent Check(Me, raiseByMouse) RaiseCustomEvent() Catch ex As Exception Log(ex, "单选按钮勾选改变错误", LogLevel.Hint) End Try End Sub Public ReadOnly Property Inlines As InlineCollection Get Return LabText.Inlines End Get End Property Public Property Text As String Get Return GetValue(TextProperty) End Get Set(value As String) SetValue(TextProperty, value) End Set End Property '内容 Public Shared ReadOnly TextProperty As DependencyProperty = DependencyProperty.Register("Text", GetType(String), GetType(MyRadioButton), New PropertyMetadata(New PropertyChangedCallback( Sub(sender, e) If sender IsNot Nothing Then CType(sender, MyRadioButton).LabText.Text = e.NewValue))) Public Enum ColorState White Highlight End Enum Private _ColorType As ColorState = ColorState.White Public Property ColorType As ColorState Get Return _ColorType End Get Set(value As ColorState) _ColorType = value RefreshColor() End Set End Property '颜色类别 '点击事件 Public Event PreviewClick(sender As Object, e As RouteEventArgs) Private IsMouseDown As Boolean = False Private Sub Radiobox_MouseUp() Handles Me.MouseLeftButtonUp If Checked Then Return If Not IsMouseDown Then Return Log("[Control] 按下单选按钮:" & Text) IsMouseDown = False Dim e As New RouteEventArgs(True) RaiseEvent PreviewClick(Me, e) If e.Handled Then Return SetChecked(True, True, True) End Sub Private Sub Radiobox_MouseDown() Handles Me.MouseLeftButtonDown If Checked Then Return IsMouseDown = True RefreshColor() End Sub Private Sub Radiobox_MouseLeave() Handles Me.MouseLeave IsMouseDown = False End Sub '动画 Private Const AnimationTimeOfMouseIn As Integer = 90 '鼠标指向动画长度 Private Const AnimationTimeOfMouseOut As Integer = 150 '鼠标移出动画长度 Private Const AnimationTimeOfCheck As Integer = 120 '勾选状态变更动画长度 Private Sub RefreshColor(Optional obj = Nothing, Optional e = Nothing) Handles Me.MouseEnter, Me.MouseLeave, Me.Loaded Try If IsLoaded AndAlso AniControlEnabled = 0 AndAlso Not False.Equals(e) Then '防止默认属性变更触发动画,若强制不执行动画,则 e 为 False Select Case ColorType Case ColorState.White If Checked Then '勾选 AniStart({ AaColor(ShapeLogo, Shapes.Path.FillProperty, "ColorBrush3", AnimationTimeOfCheck), AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrush3", AnimationTimeOfCheck) }, "MyRadioButton Checked " & Uuid) AniStart(AaColor(Me, BackgroundProperty, New MyColor(255, 255, 255) - Background, AnimationTimeOfCheck), "MyRadioButton Color " & Uuid) ElseIf IsMouseDown Then '按下 AniStart(AaColor(Me, BackgroundProperty, New MyColor(120, Color8) - Background, 60), "MyRadioButton Color " & Uuid) ElseIf IsMouseOver Then '指向 AniStart({ AaColor(ShapeLogo, Shapes.Path.FillProperty, New MyColor(255, 255, 255) - ShapeLogo.Fill, AnimationTimeOfMouseIn), AaColor(LabText, TextBlock.ForegroundProperty, New MyColor(255, 255, 255) - LabText.Foreground, AnimationTimeOfMouseIn) }, "MyRadioButton Checked " & Uuid) AniStart(AaColor(Me, BackgroundProperty, New MyColor(50, Color8) - Background, AnimationTimeOfMouseIn), "MyRadioButton Color " & Uuid) Else '正常 AniStart({ AaColor(ShapeLogo, Shapes.Path.FillProperty, New MyColor(255, 255, 255) - ShapeLogo.Fill, AnimationTimeOfMouseOut), AaColor(LabText, TextBlock.ForegroundProperty, New MyColor(255, 255, 255) - LabText.Foreground, AnimationTimeOfMouseOut) }, "MyRadioButton Checked " & Uuid) AniStart(AaColor(Me, BackgroundProperty, ColorSemiTransparent - Background, AnimationTimeOfMouseOut), "MyRadioButton Color " & Uuid) End If Case ColorState.Highlight If Checked Then '勾选 AniStart({ AaColor(ShapeLogo, Shapes.Path.FillProperty, New MyColor(255, 255, 255) - ShapeLogo.Fill, AnimationTimeOfCheck), AaColor(LabText, TextBlock.ForegroundProperty, New MyColor(255, 255, 255) - LabText.Foreground, AnimationTimeOfCheck) }, "MyRadioButton Checked " & Uuid) AniStart(AaColor(Me, BackgroundProperty, "ColorBrush3", AnimationTimeOfCheck), "MyRadioButton Color " & Uuid) ElseIf IsMouseDown Then '按下 AniStart(AaColor(Me, BackgroundProperty, "ColorBrush6", AnimationTimeOfMouseIn), "MyRadioButton Color " & Uuid) ElseIf IsMouseOver Then '指向 AniStart({ AaColor(ShapeLogo, Shapes.Path.FillProperty, "ColorBrush3", AnimationTimeOfMouseIn), AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrush3", AnimationTimeOfMouseIn) }, "MyRadioButton Checked " & Uuid) AniStart(AaColor(Me, BackgroundProperty, "ColorBrush7", AnimationTimeOfMouseIn), "MyRadioButton Color " & Uuid) Else '正常 AniStart({ AaColor(ShapeLogo, Shapes.Path.FillProperty, "ColorBrush3", AnimationTimeOfMouseOut), AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrush3", AnimationTimeOfMouseOut) }, "MyRadioButton Checked " & Uuid) AniStart(AaColor(Me, BackgroundProperty, ColorSemiTransparent - Background, AnimationTimeOfMouseOut), "MyRadioButton Color " & Uuid) End If End Select Else '不使用动画 AniStop("MyRadioButton Checked " & Uuid) AniStop("MyRadioButton Color " & Uuid) Select Case ColorType Case ColorState.White If Checked Then Background = New MyColor(255, 255, 255) ShapeLogo.SetResourceReference(Shapes.Path.FillProperty, "ColorBrush3") LabText.SetResourceReference(TextBlock.ForegroundProperty, "ColorBrush3") Else Background = ColorSemiTransparent ShapeLogo.Fill = New MyColor(255, 255, 255) LabText.Foreground = New MyColor(255, 255, 255) End If Case ColorState.Highlight If Checked Then SetResourceReference(BackgroundProperty, "ColorBrush3") ShapeLogo.Fill = New MyColor(255, 255, 255) LabText.Foreground = New MyColor(255, 255, 255) Else Background = ColorSemiTransparent ShapeLogo.SetResourceReference(Shapes.Path.FillProperty, "ColorBrush3") LabText.SetResourceReference(TextBlock.ForegroundProperty, "ColorBrush3") End If End Select End If Catch ex As Exception Log(ex, "刷新单选按钮颜色出错") End Try End Sub End Class