MyTextBox.vb 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. Public Class MyTextBox
  2. Inherits TextBox
  3. '自定义属性
  4. Public Property HasAnimation As Boolean = True
  5. Public Property ShowValidateResult As Boolean = True
  6. '额外控件初始化
  7. Private _labWrong As TextBlock = Nothing
  8. Private ReadOnly Property labWrong As TextBlock
  9. Get
  10. If Template Is Nothing Then Return Nothing
  11. If _labWrong Is Nothing Then _labWrong = Template.FindName("labWrong", Me)
  12. Return _labWrong
  13. End Get
  14. End Property
  15. Private _labHint As TextBlock = Nothing
  16. Private ReadOnly Property labHint As TextBlock
  17. Get
  18. If Template Is Nothing Then Return Nothing
  19. If _labHint Is Nothing Then _labHint = Template.FindName("labHint", Me)
  20. Return _labHint
  21. End Get
  22. End Property
  23. Public Overrides Sub OnApplyTemplate()
  24. MyBase.OnApplyTemplate()
  25. If HintText = "" OrElse labHint.Text <> "" Then Exit Sub
  26. labHint.Text = If(Text = "", HintText, "")
  27. End Sub
  28. '事件
  29. Public Uuid As Integer = GetUuid()
  30. Public Shared Event ValidateChanged(sender As Object, e As EventArgs)
  31. Public ChangedEventList As New List(Of RoutedEventHandler)
  32. Public Custom Event ValidatedTextChanged As RoutedEventHandler
  33. AddHandler(value As RoutedEventHandler)
  34. ChangedEventList.Add(value)
  35. End AddHandler
  36. RemoveHandler(value As RoutedEventHandler)
  37. ChangedEventList.Remove(value)
  38. End RemoveHandler
  39. RaiseEvent(sender As Object, e As TextChangedEventArgs)
  40. For Each handler As RoutedEventHandler In ChangedEventList
  41. If Not IsNothing(handler) Then handler.Invoke(sender, e)
  42. Next
  43. End RaiseEvent
  44. End Event
  45. '输入验证
  46. ''' <summary>
  47. ''' 输入验证结果。若为空字符串则无错误,否则为第一个错误原因。
  48. ''' </summary>
  49. Public Property ValidateResult As String
  50. Get
  51. Return GetValue(ValidateResultProperty)
  52. End Get
  53. Set(value As String)
  54. SetValue(ValidateResultProperty, value)
  55. End Set
  56. End Property
  57. Public Shared ReadOnly ValidateResultProperty As DependencyProperty = DependencyProperty.Register("ValidateResult", GetType(String), GetType(MyTextBox), New PropertyMetadata(""))
  58. ''' <summary>
  59. ''' 输入验证的规则。
  60. ''' </summary>
  61. Public Property ValidateRules As ObjectModel.Collection(Of Validate)
  62. Get
  63. Return _ValidateRules
  64. End Get
  65. Set(Value As ObjectModel.Collection(Of Validate))
  66. _ValidateRules = Value
  67. Validate()
  68. End Set
  69. End Property
  70. Private _ValidateRules As New ObjectModel.Collection(Of Validate)
  71. ''' <summary>
  72. ''' 进行输入验证。
  73. ''' </summary>
  74. Public Sub Validate() Handles Me.Loaded
  75. '执行输入验证
  76. ValidateResult = ""
  77. For Each ValidateRule As Validate In ValidateRules
  78. ValidateResult = ValidateRule.Validate(Text)
  79. If IsNothing(ValidateResult) OrElse Not ValidateResult = "" Then Exit For
  80. Next
  81. Dim NewResult As Integer = If(ValidateResult = "", 0, 1)
  82. '根据结果改变样式
  83. If ShownValidateResult <> NewResult Then
  84. If IsLoaded AndAlso labWrong IsNot Nothing Then
  85. ChangeValidateResult(ValidateResult = "", True)
  86. Else
  87. RunInNewThread(Sub()
  88. Thread.Sleep(30)
  89. RunInUi(Sub() ChangeValidateResult(NewResult, False))
  90. End Sub, "DelayedValidate Change")
  91. End If
  92. End If
  93. '更新错误信息
  94. If ShowValidateResult AndAlso Not ValidateResult = "" Then
  95. If IsLoaded AndAlso labWrong IsNot Nothing Then
  96. labWrong.Text = ValidateResult
  97. Else
  98. RunInNewThread(Sub()
  99. Dim IsFinished As Boolean = False
  100. Do Until IsFinished
  101. Thread.Sleep(20)
  102. RunInUiWait(Sub()
  103. If labWrong IsNot Nothing Then
  104. labWrong.Text = ValidateResult
  105. IsFinished = True
  106. End If
  107. If Not IsLoaded Then IsFinished = True
  108. End Sub)
  109. Loop
  110. End Sub, "DelayedValidate Text")
  111. End If
  112. End If
  113. End Sub
  114. Private ShownValidateResult As Integer = -1
  115. Private Sub ChangeValidateResult(NewResult As Boolean, IsLoaded As Boolean)
  116. If IsLoaded AndAlso AniControlEnabled = 0 AndAlso IsTextChanged AndAlso labWrong IsNot Nothing Then
  117. If NewResult Then
  118. '变为正确
  119. ShownValidateResult = 0
  120. AniStart({
  121. AaOpacity(labWrong, -labWrong.Opacity, 150),
  122. AaHeight(labWrong, -labWrong.Height, 150,, New AniEaseOutFluent),
  123. AaCode(Sub() labWrong.Visibility = Visibility.Collapsed,, True)
  124. }, "MyTextBox Validate " & Uuid)
  125. ElseIf ShowValidateResult Then
  126. '变为错误
  127. ShownValidateResult = 1
  128. labWrong.Visibility = Visibility.Visible
  129. AniStart({
  130. AaOpacity(labWrong, 1 - labWrong.Opacity, 170),
  131. AaHeight(labWrong, 21 - labWrong.Height, 300,, New AniEaseOutBack(AniEasePower.Weak))
  132. }, "MyTextBox Validate " & Uuid)
  133. Else
  134. '变为错误,但不显示文本
  135. ShownValidateResult = 2
  136. End If
  137. Else
  138. ShownValidateResult = 3
  139. 'AniStop("MyTextBox Validate " & Uuid)
  140. 'If NewResult Then
  141. ' '变为正确
  142. ' labWrong.Opacity = 0
  143. ' labWrong.Height = 0
  144. ' labWrong.Visibility = Visibility.Collapsed
  145. 'Else
  146. ' '变为错误
  147. ' labWrong.Visibility = Visibility.Visible
  148. ' labWrong.Text = ValidateResult
  149. ' labWrong.Opacity = 1
  150. ' labWrong.Height = 20.5
  151. 'End If
  152. 'Dim OriginalEnabled As Integer = AniControlEnabled
  153. 'AniControlEnabled += 1
  154. 'RefreshColor()
  155. 'AniControlEnabled = OriginalEnabled
  156. End If
  157. RefreshColor()
  158. RaiseEvent ValidateChanged(Me, New EventArgs)
  159. End Sub
  160. '提示文本
  161. ''' <summary>
  162. ''' 是否已经由用户输入过文本,若尚未输入过,则不显示输入检查的失败。
  163. ''' </summary>
  164. Private IsTextChanged As Boolean = False
  165. Private _HintText As String = ""
  166. Public Property HintText As String
  167. Get
  168. Return _HintText
  169. End Get
  170. Set(value As String)
  171. _HintText = value
  172. If labHint IsNot Nothing Then labHint.Text = If(Text = "", HintText, "")
  173. End Set
  174. End Property
  175. Private Sub MyTextBox_TextChanged(sender As MyTextBox, e As TextChangedEventArgs) Handles Me.TextChanged
  176. Try
  177. '改变提示文本
  178. If labHint IsNot Nothing Then labHint.Text = If(Text = "", HintText, "")
  179. '改变输入记录
  180. IsTextChanged = IsLoaded
  181. '进行输入验证
  182. Validate()
  183. If Not ValidateResult = "" Then Exit Sub
  184. '改变文本
  185. RaiseEvent ValidatedTextChanged(sender, e)
  186. Catch ex As Exception
  187. Log(ex, "进行输入验证时出错", LogLevel.Assert)
  188. End Try
  189. End Sub
  190. '颜色
  191. Private Sub RefreshColor() Handles Me.IsEnabledChanged, Me.MouseEnter, Me.MouseLeave, Me.GotFocus, Me.LostFocus
  192. Try
  193. '手动关闭动画
  194. If Not HasAnimation Then Exit Sub
  195. '不对 ComboBox 从属进行动画
  196. If TemplatedParent IsNot Nothing AndAlso TypeOf TemplatedParent Is MyComboBox Then Exit Sub
  197. '判断当前颜色
  198. Dim ForeColorName As String, BackColorName As String
  199. Dim AnimationTime As Integer
  200. If IsEnabled Then
  201. If ValidateResult = "" OrElse Not IsTextChanged Then
  202. If IsFocused Then
  203. ForeColorName = "ColorBrush4"
  204. BackColorName = "ColorBrush9"
  205. AnimationTime = 60
  206. ElseIf IsMouseOver Then
  207. ForeColorName = "ColorBrush3"
  208. BackColorName = "ColorBrushHalfWhite"
  209. AnimationTime = 100
  210. Else
  211. ForeColorName = "ColorBrush1"
  212. BackColorName = "ColorBrushHalfWhite"
  213. AnimationTime = 200
  214. End If
  215. Else
  216. ForeColorName = "ColorBrushRedLight"
  217. BackColorName = "ColorBrushRedBack"
  218. AnimationTime = 200
  219. 'If IsFocused OrElse IsMouseOver Then
  220. ' ForeColorName = "ColorBrushRedLight"
  221. ' BackColorName = "ColorBrushRedBack"
  222. ' AnimationTime = 100
  223. 'Else
  224. ' ForeColorName = "ColorBrushRedDark"
  225. ' BackColorName = "ColorBrushHalfWhite"
  226. ' AnimationTime = 200
  227. 'End If
  228. End If
  229. Else
  230. ForeColorName = "ColorBrushGray4"
  231. BackColorName = "ColorBrushHalfWhite"
  232. AnimationTime = 200
  233. End If
  234. '触发颜色动画
  235. If IsLoaded AndAlso AniControlEnabled = 0 Then '防止默认属性变更触发动画
  236. '有动画
  237. AniStart({
  238. AaColor(Me, BorderBrushProperty, ForeColorName, AnimationTime),
  239. AaColor(Me, BackgroundProperty, BackColorName, AnimationTime)
  240. }, "MyTextBox Color " & Uuid)
  241. Else
  242. '无动画
  243. AniStop("MyTextBox Color " & Uuid)
  244. SetResourceReference(BorderBrushProperty, ForeColorName)
  245. SetResourceReference(BackgroundProperty, BackColorName)
  246. End If
  247. Catch ex As Exception
  248. Log(ex, "文本框颜色改变出错")
  249. End Try
  250. End Sub
  251. Private Sub RefreshTextColor() Handles Me.IsEnabledChanged
  252. Dim NewColor As MyColor = If(IsEnabled, ColorGray1, ColorGray4)
  253. If CType(Foreground, SolidColorBrush).Color.R = NewColor.R Then Exit Sub
  254. If IsLoaded AndAlso AniControlEnabled = 0 AndAlso Not Text = "" Then
  255. '有动画
  256. AniStart({AaColor(Me, ForegroundProperty, If(IsEnabled, "ColorBrushGray1", "ColorBrushGray4"), 200)}, "MyTextBox TextColor " & Uuid)
  257. Else
  258. '无动画
  259. AniStop("MyTextBox TextColor " & Uuid)
  260. Foreground = NewColor
  261. End If
  262. End Sub
  263. End Class