MyComboBox.vb 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. Public Class MyComboBox
  2. Inherits ComboBox
  3. Implements ISettingControl
  4. Public Event TextChanged(sender As Object, e As TextChangedEventArgs)
  5. '基础
  6. Public Uuid As Integer = GetUuid()
  7. Private TextBox As MyTextBox
  8. Public Property HintText As String = ""
  9. Public Overrides Sub OnApplyTemplate()
  10. MyBase.OnApplyTemplate()
  11. If Not IsEditable Then Return
  12. Try
  13. TextBox = Template.FindName("PART_EditableTextBox", Me)
  14. TextBox.AddHandler(LostFocusEvent, New RoutedEventHandler(AddressOf RefreshColor))
  15. TextBox.ChangedEventList.Add(New RoutedEventHandler(Sub(sender, e) RaiseEvent TextChanged(sender, e)))
  16. TextBox.Tag = Tag '有时需要用文本框的 Tag 来写入设置
  17. If Text = "" Then
  18. TextBox.Text = _Text
  19. Else
  20. RaiseEvent TextChanged(Me, Nothing)
  21. End If
  22. If HintText.Length > 0 Then TextBox.HintText = HintText
  23. Catch ex As Exception
  24. Logger.Error(ex, $"初始化可编辑文本框失败({If(Name, "")})")
  25. End Try
  26. End Sub
  27. Private _Text As String = SelectedItem
  28. Public Shadows Property Text As String
  29. Get
  30. If IsEditable Then
  31. If TextBox Is Nothing Then
  32. Return If(_Text, "")
  33. Else
  34. Return If(TextBox.Text, "")
  35. End If
  36. Else
  37. Return If(SelectedItem, "").ToString
  38. End If
  39. End Get
  40. Set(value As String)
  41. If IsEditable Then
  42. If IsNothing(TextBox) Then
  43. _Text = value
  44. Else
  45. TextBox.Text = value
  46. End If
  47. Else
  48. Throw New NotSupportedException("该 ComboBox 不支持修改文本。")
  49. End If
  50. End Set
  51. End Property
  52. '鼠标按下接口
  53. Private IsMouseDown As Boolean = False
  54. Private Sub MyComboBox_PreviewMouseLeftButtonDown(sender As Object, e As MouseButtonEventArgs) Handles Me.PreviewMouseLeftButtonDown
  55. IsMouseDown = True
  56. End Sub
  57. Private Sub MyComboBox_PreviewMouseLeftButtonUp(sender As Object, e As EventArgs) Handles Me.PreviewMouseLeftButtonUp, Me.MouseLeave
  58. IsMouseDown = False
  59. End Sub
  60. '指向动画
  61. Public Sub RefreshColor() Handles Me.IsEnabledChanged, Me.MouseEnter, Me.MouseLeave, Me.PreviewMouseLeftButtonDown, Me.PreviewMouseLeftButtonUp, Me.GotKeyboardFocus
  62. '判断当前颜色
  63. Dim ForeColorName As String
  64. Dim BackColorName As String
  65. Dim Time As Integer
  66. If IsEnabled Then
  67. If IsMouseDown OrElse IsDropDownOpen OrElse (IsEditable AndAlso Template.FindName("PART_EditableTextBox", Me).IsFocused) Then
  68. ForeColorName = "ColorBrush3"
  69. BackColorName = "ColorBrush7"
  70. Time = 10
  71. ElseIf IsMouseOver Then
  72. ForeColorName = "ColorBrush4"
  73. BackColorName = "ColorBrush7"
  74. Time = 100
  75. Else
  76. ForeColorName = "ColorBrushBg0"
  77. BackColorName = "ColorBrushHalfWhite"
  78. Time = 100
  79. End If
  80. Else
  81. ForeColorName = "ColorBrushGray5"
  82. BackColorName = "ColorBrushGray6"
  83. Time = 200
  84. End If
  85. '触发颜色动画
  86. If IsLoaded AndAlso AniControlEnabled = 0 Then '防止默认属性变更触发动画
  87. '有动画
  88. AniStart({
  89. AaColor(Me, ForegroundProperty, ForeColorName, Time),
  90. AaColor(Me, BackgroundProperty, BackColorName, Time)
  91. }, "MyComboBox Color " & Uuid)
  92. Else
  93. '无动画
  94. AniStop("MyComboBox Color " & Uuid)
  95. SetResourceReference(ForegroundProperty, ForeColorName)
  96. SetResourceReference(BackgroundProperty, BackColorName)
  97. End If
  98. End Sub
  99. Private RealWidth As Double '由于下拉框 Popup 宽度与 Width 一致,故不能为 NaN(Auto)
  100. Private Sub MyComboBox_DropDownOpened(sender As Object, e As EventArgs) Handles Me.DropDownOpened
  101. RealWidth = Width
  102. Width = ActualWidth
  103. '将下拉菜单透明度与主窗口同步
  104. Try
  105. CType(Template.FindName("PanPopup", Me), Grid).Opacity = FrmMain.Opacity
  106. Catch ex As Exception
  107. Logger.Error(ex, "设置下拉框透明度失败")
  108. End Try
  109. End Sub
  110. Private Sub MyComboBox_DropDownClosed(sender As Object, e As EventArgs) Handles Me.DropDownClosed
  111. Width = RealWidth
  112. End Sub
  113. '修复 WPF Bug:下拉框文本修改后,依然误认为还选择着此前的选项,导致再次点击该选项时内容不变
  114. Private IsTextChanging As Boolean = False
  115. Private Sub MyComboBox_TextChanged(sender As Object, e As TextChangedEventArgs) Handles Me.TextChanged
  116. If IsTextChanging OrElse Not IsEditable Then Return
  117. If SelectedItem Is Nothing OrElse Text = SelectedItem.ToString Then Return
  118. Dim RawText As String = Text
  119. Dim RawSelectionStart As Integer = TextBox.SelectionStart
  120. IsTextChanging = True
  121. SelectedItem = Nothing
  122. Text = RawText
  123. TextBox.SelectionStart = RawSelectionStart
  124. IsTextChanging = False
  125. End Sub
  126. Public ReadOnly Property ContentPresenter As ContentPresenter
  127. Get
  128. Return Template.FindName("PART_Content", Me)
  129. End Get
  130. End Property
  131. Private Sub MyComboBox_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles Me.SelectionChanged
  132. If IsLoaded AndAlso AniControlEnabled = 0 Then RaiseCustomEvent()
  133. End Sub
  134. #Region "设置"
  135. Private Sub RefreshSetting(NewValue As String) Implements ISettingControl.RefreshSetting
  136. Dim TargetItem = Items.OfType(Of DependencyObject)().FirstOrDefault(Function(i) Val(If(SettingService.GetValue(i), -1)) = NewValue)
  137. If TargetItem IsNot Nothing Then
  138. SelectedItem = TargetItem
  139. ElseIf Items.Count > NewValue Then
  140. SelectedIndex = NewValue
  141. Else
  142. Logger.Warn($"尝试显示设置 {SettingService.GetKey(Me)},但没有找到设置值 {NewValue} 的对应项")
  143. SelectedIndex = -1
  144. SelectedItem = Nothing
  145. End If
  146. End Sub
  147. Private Function GetCurrentSetting() As String Implements ISettingControl.GetCurrentSetting
  148. If SelectedItem Is Nothing Then Return Nothing
  149. If TypeOf SelectedItem Is DependencyObject Then
  150. Return If(SettingService.GetValue(SelectedItem), SelectedIndex)
  151. Else
  152. Return SelectedIndex
  153. End If
  154. End Function
  155. Private Sub SaveSetting() Handles Me.SelectionChanged
  156. If SelectedItem Is Nothing Then Return
  157. SettingService.SaveSetting(Me)
  158. End Sub
  159. #End Region
  160. End Class