Imports System.Windows.Markup Public Class MyCheckBox Implements ISettingControl '基础 Public Uuid As Integer = GetUuid() ''' ''' 复选框勾选状态改变。 ''' ''' 是否为用户手动改变的勾选状态。 Public Event Change(sender As Object, user As Boolean) Public Event PreviewChange(sender As Object, e As RouteEventArgs) '自定义属性 Public Property Checked As Boolean Get Return GetValue(CheckedProperty) End Get Set(value As Boolean) SetChecked(value, False) End Set End Property Public Shared ReadOnly CheckedProperty As DependencyProperty = DependencyProperty.Register("Checked", GetType(Boolean), GetType(MyCheckBox), New PropertyMetadata(False, Sub(d As MyCheckBox, e As DependencyPropertyChangedEventArgs) '在使用 XAML 设置 Checked 属性时,不会触发 Checked_Set 方法,所以需要在这里手动触发 UI 改变 If Not d.IsLoaded Then d.SyncUI() End Sub)) Private Const AnimationTimeOfCheck As Integer = 150 '勾选状态变更动画长度 ''' ''' 手动设置 Checked 属性。 ''' ''' 新的 Checked 属性。 ''' 是否由用户引发。 Public Sub SetChecked(value As Boolean, user As Boolean) Try If value = Checked Then Return 'Preview 事件 If value AndAlso user Then Dim e = New RouteEventArgs(user) RaiseEvent PreviewChange(Me, e) If e.Handled Then MouseDowned = True Checkbox_MouseLeave() MouseDowned = False Return End If End If SetValue(CheckedProperty, value) If IsLoaded Then RaiseEvent Change(Me, user) '更改动画 SyncUI() RaiseCustomEvent() Catch ex As Exception Logger.Warn(ex, "设置 Checked 失败") End Try End Sub Private Sub SyncUI() If AniControlEnabled = 0 AndAlso IsLoaded Then '防止默认属性变更触发动画 AllowMouseDown = False If Checked Then '由无变有 AniStart({ AaScale(ShapeBorder, 12 - ShapeBorder.Width, AnimationTimeOfCheck, , New AniEaseOutFluent, , True), AaScaleTransform(ShapeCheck, 1 - CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleX, AnimationTimeOfCheck * 2, AnimationTimeOfCheck * 0.7, New AniEaseOutBack(AniEasePower.Weak)), AaScale(ShapeBorder, 6, AnimationTimeOfCheck * 2, AnimationTimeOfCheck * 0.7, New AniEaseOutBack, , True) }, "MyCheckBox Scale " & Uuid) AniStart({ AaColor(ShapeBorder, Border.BorderBrushProperty, If(IsEnabled, If(IsMouseOver, "ColorBrush3", "ColorBrush2"), "ColorBrushGray5"), AnimationTimeOfCheck) }, "MyCheckBox BorderColor " & Uuid) AniStart({ AaCode(Sub() AllowMouseDown = True, AnimationTimeOfCheck * 2) }, "MyCheckBox AllowMouseDown " & Uuid) Else '由有变无 AniStart({ AaScale(ShapeBorder, 12 - ShapeBorder.Width, AnimationTimeOfCheck, , New AniEaseOutFluent, , True), AaScaleTransform(ShapeCheck, -CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleX, AnimationTimeOfCheck * 0.9, , New AniEaseInFluent(AniEasePower.Weak)), AaScale(ShapeBorder, 6, AnimationTimeOfCheck * 2, AnimationTimeOfCheck * 0.7, New AniEaseOutBack, , True) }, "MyCheckBox Scale " & Uuid) AniStart({ AaColor(ShapeBorder, Border.BorderBrushProperty, If(IsEnabled, If(IsMouseOver, "ColorBrush3", "ColorBrush1"), "ColorBrushGray5"), AnimationTimeOfCheck) }, "MyCheckBox BorderColor " & Uuid) AniStart({ AaCode(Sub() AllowMouseDown = True, AnimationTimeOfCheck * 2) }, "MyCheckBox AllowMouseDown " & Uuid) End If Else '不使用动画 AniStop("MyCheckBox Scale " & Uuid) AniStop("MyCheckBox BorderColor " & Uuid) AniStop("MyCheckBox AllowMouseDown " & Uuid) If Checked Then CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleX = 1 CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleY = 1 ShapeBorder.SetResourceReference(Border.BorderBrushProperty, If(IsEnabled, "ColorBrush2", "ColorBrushGray5")) Else CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleX = 0 CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleY = 0 ShapeBorder.SetResourceReference(Border.BorderBrushProperty, If(IsEnabled, "ColorBrush1", "ColorBrushGray5")) End If End If 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(MyCheckBox), New PropertyMetadata(New PropertyChangedCallback( Sub(sender As DependencyObject, e As DependencyPropertyChangedEventArgs) If Not IsNothing(sender) Then CType(sender, MyCheckBox).LabText.Text = e.NewValue End Sub))) '点击事件 Private MouseDowned As Boolean = False Private AllowMouseDown As Boolean = True Private Sub Checkbox_MouseUp() Handles Me.MouseLeftButtonUp If Not MouseDowned Then Return Logger.Info($"按下复选框({(Not Checked)}):{Text}") MouseDowned = False SetChecked(Not Checked, True) AniStart(AaColor(ShapeBorder, Border.BackgroundProperty, "ColorBrushHalfWhite", 100), "MyCheckBox Background " & Uuid) End Sub Private Sub Checkbox_MouseDown() Handles Me.MouseLeftButtonDown If Not AllowMouseDown Then Return MouseDowned = True Focus() AniStart(AaColor(ShapeBorder, Border.BackgroundProperty, "ColorBrushBg1", 100), "MyCheckBox Background " & Uuid) If Checked Then AniStart({ AaScale(ShapeBorder, 16.5 - ShapeBorder.Width, 1000, , New AniEaseOutFluent(AniEasePower.Strong), Absolute:=True), AaScaleTransform(ShapeCheck, 0.9 - CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleX, 1000, , New AniEaseOutFluent(AniEasePower.Strong)) }, "MyCheckBox Scale " & Uuid) Else AniStart(AaScale(ShapeBorder, 16.5 - ShapeBorder.Width, 1000, , New AniEaseOutFluent(AniEasePower.Strong), Absolute:=True), "MyCheckBox Scale " & Uuid) End If End Sub Private Sub Checkbox_MouseLeave() Handles Me.MouseLeave If Not MouseDowned Then Return MouseDowned = False AniStart(AaColor(ShapeBorder, Border.BackgroundProperty, "ColorBrushHalfWhite", 100), "MyCheckBox Background " & Uuid) If Checked Then AniStart({ AaScale(ShapeBorder, 18 - ShapeBorder.Width, 400, , New AniEaseOutFluent(AniEasePower.Strong), Absolute:=True), AaScaleTransform(ShapeCheck, 1 - CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleX, 500, , New AniEaseOutFluent(AniEasePower.Strong)) }, "MyCheckBox Scale " & Uuid) Else AniStart(AaScale(ShapeBorder, 18 - ShapeBorder.Width, 400, , New AniEaseOutFluent(AniEasePower.Strong), Absolute:=True), "MyCheckBox Scale " & Uuid) End If End Sub '指向动画 Private Const AnimationTimeOfMouseIn As Integer = 100 Private Const AnimationTimeOfMouseOut As Integer = 200 Private Sub Checkbox_IsEnabledChanged() Handles Me.IsEnabledChanged If IsLoaded AndAlso AniControlEnabled = 0 Then '防止默认属性变更触发动画 '有动画 If IsEnabled Then '可用 Checkbox_MouseLeaveAnimation() Else '不可用 AniStart({ AaColor(ShapeBorder, Border.BorderBrushProperty, ColorGray5 - ShapeBorder.BorderBrush, AnimationTimeOfMouseOut) }, "MyCheckBox BorderColor " & Uuid) AniStart({ AaColor(LabText, TextBlock.ForegroundProperty, ColorGray5 - LabText.Foreground, AnimationTimeOfMouseOut) }, "MyCheckBox TextColor " & Uuid) End If Else '无动画 AniStop("MyCheckBox TextColor " & Uuid) AniStop("MyCheckBox BorderColor " & Uuid) LabText.SetResourceReference(TextBlock.ForegroundProperty, If(Me.IsEnabled, "ColorBrush1", "ColorBrushGray5")) ShapeBorder.SetResourceReference(Border.BorderBrushProperty, If(Me.IsEnabled, If(Checked, "ColorBrush2", "ColorBrush1"), "ColorBrushGray5")) End If End Sub Private Sub Checkbox_MouseEnterAnimation() Handles Me.MouseEnter AniStart({ AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrush3", AnimationTimeOfMouseIn) }, "MyCheckBox TextColor " & Uuid) AniStart({ AaColor(ShapeBorder, Border.BorderBrushProperty, "ColorBrush3", AnimationTimeOfMouseIn) }, "MyCheckBox BorderColor " & Uuid) End Sub Private Sub Checkbox_MouseLeaveAnimation() Handles Me.MouseLeave If Not IsEnabled Then Return 'MouseLeave 比 IsEnabledChanged 后执行,所以如果自定义事件修改了 IsEnabled,将导致显示错误 AniStart({ AaColor(LabText, TextBlock.ForegroundProperty, If(Me.IsEnabled, "ColorBrush1", "ColorBrushGray5"), AnimationTimeOfMouseOut) }, "MyCheckBox TextColor " & Uuid) AniStart({ AaColor(ShapeBorder, Border.BorderBrushProperty, If(Me.IsEnabled, If(Checked, "ColorBrush2", "ColorBrush1"), "ColorBrushGray5"), AnimationTimeOfMouseOut) }, "MyCheckBox BorderColor " & Uuid) End Sub #Region "设置" Private Sub RefreshSetting(NewValue As String) Implements ISettingControl.RefreshSetting Checked = Boolean.Parse(NewValue) End Sub Private Function GetCurrentSetting() As String Implements ISettingControl.GetCurrentSetting Return Checked.ToString End Function Private Sub SaveSetting() Handles Me.Change SettingService.SaveSetting(Me) End Sub #End Region End Class