314 lines
12 KiB
VB.net
314 lines
12 KiB
VB.net
Imports PCL.MyLoading
|
|
|
|
Public Class MyLoading
|
|
|
|
Public Event IsErrorChanged(sender As Object, isError As Boolean)
|
|
Public Event StateChanged(sender As Object, newState As MyLoadingState, oldState As MyLoadingState)
|
|
Public Event Click(sender As Object, e As MouseButtonEventArgs)
|
|
|
|
Public Property AutoRun As Boolean = True
|
|
Private Uuid As Integer = GetUuid()
|
|
|
|
#Region "颜色"
|
|
|
|
Public Property Foreground As SolidColorBrush
|
|
Get
|
|
Return GetValue(ForegroundProperty)
|
|
End Get
|
|
Set(value As SolidColorBrush)
|
|
SetValue(ForegroundProperty, value)
|
|
End Set
|
|
End Property
|
|
Public Shared ReadOnly ForegroundProperty As DependencyProperty = DependencyProperty.Register("Foreground", GetType(SolidColorBrush), GetType(MyLoading))
|
|
Public Sub New()
|
|
InitializeComponent()
|
|
SetResourceReference(ForegroundProperty, "ColorBrush3")
|
|
End Sub
|
|
|
|
#End Region
|
|
|
|
#Region "文本"
|
|
|
|
Private Property _ShowProgress As Boolean = False
|
|
Public Property ShowProgress As Boolean
|
|
Get
|
|
Return _ShowProgress
|
|
End Get
|
|
Set(value As Boolean)
|
|
If _ShowProgress = value Then Exit Property
|
|
_ShowProgress = value
|
|
RefreshText()
|
|
End Set
|
|
End Property
|
|
|
|
Private _Text As String = "加载中"
|
|
Public Property Text As String
|
|
Get
|
|
Return _Text
|
|
End Get
|
|
Set(ByVal value As String)
|
|
_Text = value
|
|
RefreshText()
|
|
End Set
|
|
End Property
|
|
|
|
Private _TextError As String = "加载失败"
|
|
Public Property TextError As String
|
|
Get
|
|
Return _TextError
|
|
End Get
|
|
Set(ByVal value As String)
|
|
_TextError = value
|
|
RefreshText()
|
|
End Set
|
|
End Property
|
|
''' <summary>
|
|
''' 是否在使用 Loader 时使用 Loader 的错误输出来替换默认的错误文本显示。
|
|
''' </summary>
|
|
Public Property TextErrorInherit As Boolean = True
|
|
|
|
Private Sub RefreshText() Handles Me.IsErrorChanged, Me.Loaded
|
|
If InnerState = MyLoadingState.Error Then
|
|
If TextErrorInherit AndAlso State.IsLoader Then
|
|
Dim Ex As Exception = CType(State, Object).Error
|
|
If Ex Is Nothing Then
|
|
LabText.Text = "未知错误"
|
|
Else
|
|
Do While Ex.InnerException IsNot Nothing
|
|
Ex = Ex.InnerException
|
|
Loop
|
|
LabText.Text = StrTrim(Ex.Message)
|
|
If LabText.Text.Contains("远程主机强迫关闭了一个现有的连接") OrElse LabText.Text.Contains("操作已超时") OrElse LabText.Text.Contains("操作超时") OrElse LabText.Text.Contains("服务器超时") OrElse LabText.Text.Contains("连接超时") Then LabText.Text = "网络环境不佳,请重试或尝试使用 VPN"
|
|
End If
|
|
Else
|
|
LabText.Text = TextError
|
|
End If
|
|
Else
|
|
If ShowProgress AndAlso State.IsLoader Then
|
|
LabText.Text = Text & " - " & Math.Floor(CType(State, Object).Progress * 100) & "%"
|
|
Else
|
|
LabText.Text = Text
|
|
End If
|
|
End If
|
|
End Sub
|
|
|
|
#End Region
|
|
|
|
#Region "状态改变"
|
|
|
|
'状态枚举
|
|
Public Enum MyLoadingState
|
|
Unloaded = -1
|
|
Run = 0
|
|
[Stop] = 1
|
|
[Error] = 2
|
|
End Enum
|
|
|
|
'用于外部改变的公开状态
|
|
Private WithEvents _State As ILoadingTrigger
|
|
Public Property State As ILoadingTrigger
|
|
Get
|
|
InitState()
|
|
Return _State
|
|
End Get
|
|
Set(value As ILoadingTrigger)
|
|
_State = value
|
|
RefreshState()
|
|
End Set
|
|
End Property
|
|
Private Sub InitState() Handles Me.Loaded
|
|
If _State Is Nothing Then
|
|
_State = New MyLoadingStateSimulator
|
|
If AutoRun Then _State.LoadingState = MyLoadingState.Run
|
|
End If
|
|
End Sub
|
|
Private Sub RefreshState() Handles _State.LoadingStateChanged, Me.Loaded, Me.Unloaded
|
|
If _State.LoadingState = MyLoadingState.Run AndAlso Not IsLoaded Then InnerState = MyLoadingState.Stop
|
|
InnerState = _State.LoadingState
|
|
OuterState = _State.LoadingState
|
|
AniLoop()
|
|
End Sub
|
|
|
|
'用于引发外部事件的状态
|
|
Private Property _OuterState As MyLoadingState = MyLoadingState.Unloaded
|
|
Private Property OuterState As MyLoadingState
|
|
Get
|
|
Return _OuterState
|
|
End Get
|
|
Set(value As MyLoadingState)
|
|
If _OuterState = value Then Exit Property
|
|
Dim OldValue = _OuterState
|
|
_OuterState = value
|
|
'引发事件
|
|
RaiseEvent StateChanged(Me, value, OldValue)
|
|
If (OldValue = MyLoadingState.Error) <> (value = MyLoadingState.Error) Then RaiseEvent IsErrorChanged(Me, value = MyLoadingState.Error)
|
|
End Set
|
|
End Property
|
|
|
|
|
|
'用于引发内部动画事件的状态
|
|
Private Property _InnerState As MyLoadingState = MyLoadingState.Unloaded
|
|
Private Property InnerState As MyLoadingState
|
|
Get
|
|
Return _InnerState
|
|
End Get
|
|
Set(value As MyLoadingState)
|
|
If _InnerState = value Then Exit Property
|
|
Dim OldValue = _InnerState
|
|
_InnerState = value
|
|
'引发事件
|
|
AniLoop()
|
|
If (OldValue = MyLoadingState.Error) <> (value = MyLoadingState.Error) Then ErrorAnimation(Me, value = MyLoadingState.Error)
|
|
End Set
|
|
End Property
|
|
|
|
#End Region
|
|
|
|
#Region "动画"
|
|
|
|
''' <summary>
|
|
''' 是否需要动画。
|
|
''' </summary>
|
|
Public Property HasAnimation As Boolean = True
|
|
|
|
''' <summary>
|
|
''' 主动画循环是否正在运行中。
|
|
''' </summary>
|
|
Private IsLooping As Boolean = False
|
|
Private Sub AniLoop()
|
|
'这坨循环代码也是老屎坑了,救救.jpg
|
|
If Not HasAnimation OrElse IsLooping OrElse Not InnerState = MyLoadingState.Run OrElse AniSpeed > 10 OrElse Not IsLoaded Then Exit Sub
|
|
IsLooping = True
|
|
ErrorAnimationWaiting = True
|
|
If ShowProgress Then
|
|
RefreshText()
|
|
AniStart({
|
|
AaRotateTransform(PathPickaxe, -20 - CType(PathPickaxe.RenderTransform, RotateTransform).Angle, 350, 250, New AniEaseInBack(AniEasePower.Weak)),
|
|
AaCode(AddressOf RefreshText, 100), '这是为了省下一个 Timer 线程……
|
|
AaCode(AddressOf RefreshText, 200),
|
|
AaCode(AddressOf RefreshText, 300),
|
|
AaCode(AddressOf RefreshText, 400),
|
|
AaCode(AddressOf RefreshText, 500),
|
|
AaRotateTransform(PathPickaxe, 50, 900,, New AniEaseOutFluent, True),
|
|
AaRotateTransform(PathPickaxe, 25, 900,, New AniEaseOutElastic(AniEasePower.Weak)),
|
|
AaCode(Sub()
|
|
PathLeft.Opacity = 1
|
|
PathLeft.Margin = New Thickness(7, 41, 0, 0)
|
|
PathRight.Opacity = 1
|
|
PathRight.Margin = New Thickness(14, 41, 0, 0)
|
|
ErrorAnimationWaiting = False
|
|
RefreshText()
|
|
End Sub),
|
|
AaCode(AddressOf RefreshText, 100),
|
|
AaCode(AddressOf RefreshText, 200),
|
|
AaCode(AddressOf RefreshText, 300),
|
|
AaCode(AddressOf RefreshText, 400),
|
|
AaCode(AddressOf RefreshText, 500),
|
|
AaCode(AddressOf RefreshText, 600),
|
|
AaCode(AddressOf RefreshText, 700),
|
|
AaCode(AddressOf RefreshText, 800),
|
|
AaOpacity(PathLeft, -1, 100, 70),
|
|
AaX(PathLeft, -5, 180, 20, New AniEaseOutFluent),
|
|
AaY(PathLeft, -6, 180, 20, New AniEaseOutFluent),
|
|
AaOpacity(PathRight, -1, 100, 70),
|
|
AaX(PathRight, 5, 180, 20, New AniEaseOutFluent),
|
|
AaY(PathRight, -6, 180, 20, New AniEaseOutFluent),
|
|
AaCode(Sub()
|
|
IsLooping = False
|
|
AniLoop()
|
|
End Sub,, True)
|
|
}, "MyLoader Loop " & Uuid & "/" & GetUuid())
|
|
Else
|
|
AniStart({
|
|
AaRotateTransform(PathPickaxe, -20 - CType(PathPickaxe.RenderTransform, RotateTransform).Angle, 350, 250, New AniEaseInBack(AniEasePower.Weak)),
|
|
AaRotateTransform(PathPickaxe, 50, 900,, New AniEaseOutFluent, True),
|
|
AaRotateTransform(PathPickaxe, 25, 900,, New AniEaseOutElastic(AniEasePower.Weak)),
|
|
AaCode(Sub()
|
|
PathLeft.Opacity = 1
|
|
PathLeft.Margin = New Thickness(7, 41, 0, 0)
|
|
PathRight.Opacity = 1
|
|
PathRight.Margin = New Thickness(14, 41, 0, 0)
|
|
ErrorAnimationWaiting = False
|
|
End Sub),
|
|
AaOpacity(PathLeft, -1, 100, 50),
|
|
AaX(PathLeft, -5, 180,, New AniEaseOutFluent),
|
|
AaY(PathLeft, -6, 180,, New AniEaseOutFluent),
|
|
AaOpacity(PathRight, -1, 100, 50),
|
|
AaX(PathRight, 5, 180,, New AniEaseOutFluent),
|
|
AaY(PathRight, -6, 180,, New AniEaseOutFluent),
|
|
AaCode(Sub()
|
|
IsLooping = False
|
|
AniLoop()
|
|
End Sub,, True)
|
|
}, "MyLoader Loop " & Uuid & "/" & GetUuid())
|
|
End If
|
|
End Sub
|
|
|
|
''' <summary>
|
|
''' 镐子是否还没挥下去,要求错误动画等待。
|
|
''' </summary>
|
|
Private ErrorAnimationWaiting As Boolean = False
|
|
Private Sub ErrorAnimation(sender As Object, isError As Boolean)
|
|
If isError Then
|
|
'非错误变为错误
|
|
Dim Wait As Integer = If(ErrorAnimationWaiting, 400, 0)
|
|
AniStart({
|
|
AaColor(PanBack, ForegroundProperty, "ColorBrushRedLight", 300),
|
|
AaOpacity(PathError, 1 - PathError.Opacity, 100, 300 + Wait),
|
|
AaScaleTransform(PathError, 1 - CType(PathError.RenderTransform, ScaleTransform).ScaleX, 400, 300 + Wait, New AniEaseOutBack)
|
|
}, "MyLoader Error " & Uuid)
|
|
Else
|
|
'错误变为非错误
|
|
AniStart({
|
|
AaOpacity(PathError, -PathError.Opacity, 100),
|
|
AaScaleTransform(PathError, 0.5 - CType(PathError.RenderTransform, ScaleTransform).ScaleX, 200),
|
|
AaColor(PanBack, ForegroundProperty, "ColorBrush3", 300)
|
|
}, "MyLoader Error " & Uuid)
|
|
End If
|
|
End Sub
|
|
|
|
#End Region
|
|
|
|
#Region "点击事件"
|
|
|
|
Private Sub Button_MouseUp(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonUp
|
|
RaiseEvent Click(sender, e)
|
|
End Sub
|
|
Private IsMouseDown As Boolean = False
|
|
Private Sub Button_MouseDown(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonDown
|
|
'鼠标点击判定(务必放在点击事件之后,以使得 Button_MouseUp 先于 Button_MouseLeave 执行)
|
|
IsMouseDown = True
|
|
End Sub
|
|
Private Sub Button_MouseLeave(sender As Object, e As Object) Handles Me.MouseLeave, Me.MouseLeftButtonUp
|
|
IsMouseDown = False
|
|
End Sub
|
|
|
|
#End Region
|
|
|
|
End Class
|
|
|
|
Public Interface ILoadingTrigger
|
|
ReadOnly Property IsLoader As Boolean
|
|
Property LoadingState As MyLoadingState
|
|
Event LoadingStateChanged(NewState As MyLoadingState, OldState As MyLoadingState)
|
|
End Interface
|
|
|
|
Public Class MyLoadingStateSimulator
|
|
Implements ILoadingTrigger
|
|
Private Property _LoadingState As MyLoadingState = MyLoadingState.Unloaded
|
|
Public Property LoadingState As MyLoadingState Implements ILoadingTrigger.LoadingState
|
|
Get
|
|
Return _LoadingState
|
|
End Get
|
|
Set(value As MyLoadingState)
|
|
If _LoadingState = value Then Exit Property
|
|
Dim OldState = _LoadingState
|
|
_LoadingState = value
|
|
RaiseEvent LoadingStateChanged(value, OldState)
|
|
End Set
|
|
End Property
|
|
Public ReadOnly Property IsLoader As Boolean = False Implements ILoadingTrigger.IsLoader
|
|
|
|
Public Event LoadingStateChanged(NewState As MyLoadingState, OldState As MyLoadingState) Implements ILoadingTrigger.LoadingStateChanged
|
|
End Class
|