MyListItem.xaml.vb 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. Imports System.Windows.Markup
  2. <ContentProperty("Inlines")>
  3. Public Class MyListItem
  4. Implements IMyRadio
  5. Public Event Click(sender As Object, e As MouseButtonEventArgs)
  6. Public Event LogoClick(sender As Object, e As MouseButtonEventArgs)
  7. Public Event Check(sender As Object, e As RouteEventArgs) Implements IMyRadio.Check
  8. Public Event Changed(sender As Object, e As RouteEventArgs) Implements IMyRadio.Changed
  9. #Region "后加载控件"
  10. '指向背景
  11. Private _RectBack As Border = Nothing
  12. Public ReadOnly Property RectBack As Border
  13. Get
  14. If _RectBack Is Nothing Then
  15. Dim Rect As New Border With {
  16. .Name = "RectBack",
  17. .CornerRadius = New CornerRadius(If(IsScaleAnimationEnabled OrElse Height > 40, 6, 0)),
  18. .RenderTransform = If(IsScaleAnimationEnabled, New ScaleTransform(0.8, 0.8), Nothing),
  19. .RenderTransformOrigin = New Point(0.5, 0.5),
  20. .BorderThickness = New Thickness(GetWPFSize(1)),
  21. .SnapsToDevicePixels = True,
  22. .IsHitTestVisible = False,
  23. .Opacity = 0
  24. }
  25. Rect.SetResourceReference(Border.BackgroundProperty, "ColorBrush7")
  26. Rect.SetResourceReference(Border.BorderBrushProperty, "ColorBrush6")
  27. SetColumnSpan(Rect, 999)
  28. SetRowSpan(Rect, 999)
  29. Children.Insert(0, Rect)
  30. _RectBack = Rect
  31. '<!--<Border x:Name = "RectBack" CornerRadius="3" RenderTransformOrigin="0.5,0.5" SnapsToDevicePixels="True"
  32. 'IsHitTestVisible = "False" Opacity="0" BorderThickness="1"
  33. 'Grid.ColumnSpan = "4" Background="{DynamicResource ColorBrush7}" BorderBrush="{DynamicResource ColorBrush6}"/>-->
  34. End If
  35. Return _RectBack
  36. End Get
  37. End Property
  38. '按钮
  39. Public ButtonStack As FrameworkElement
  40. '图标
  41. Public PathLogo As FrameworkElement
  42. '勾选条
  43. Public RectCheck As Border
  44. '副文本
  45. Private _LabInfo As TextBlock = Nothing
  46. Public ReadOnly Property LabInfo As TextBlock
  47. Get
  48. If _LabInfo Is Nothing Then
  49. Dim Lab As New TextBlock With {
  50. .Name = "LabInfo",
  51. .SnapsToDevicePixels = False,
  52. .UseLayoutRounding = False,
  53. .HorizontalAlignment = HorizontalAlignment.Left,
  54. .IsHitTestVisible = False,
  55. .TextTrimming = TextTrimming.CharacterEllipsis,
  56. .Visibility = Visibility.Collapsed,
  57. .FontSize = 12,
  58. .Margin = New Thickness(4, 0, 0, 0),
  59. .Opacity = 0.6
  60. }
  61. SetColumn(Lab, 3)
  62. SetRow(Lab, 2)
  63. Children.Add(Lab)
  64. _LabInfo = Lab
  65. '<TextBlock Grid.Row="2" SnapsToDevicePixels="False" UseLayoutRounding="False" HorizontalAlignment="Left" x:Name = "LabInfo" IsHitTestVisible="False" Grid.Column="2"
  66. 'TextTrimming = "CharacterEllipsis" Visibility="Collapsed" FontSize="12" Foreground="{StaticResource ColorBrushGray2}" Margin="4,0,0,0" />
  67. End If
  68. Return _LabInfo
  69. End Get
  70. End Property
  71. #End Region
  72. #Region "自定义属性"
  73. 'Uuid
  74. Public Uuid As Integer = GetUuid()
  75. ''' <summary>
  76. ''' 是否启用缩放动画。
  77. ''' </summary>
  78. Public Property IsScaleAnimationEnabled As Boolean
  79. Get
  80. Return _IsScaleAnimationEnabled
  81. End Get
  82. Set
  83. _IsScaleAnimationEnabled = Value
  84. If _RectBack IsNot Nothing Then RectBack.CornerRadius = New CornerRadius(If(Value, 6, 0))
  85. End Set
  86. End Property
  87. Private _IsScaleAnimationEnabled As Boolean = True
  88. '边距
  89. Public Property PaddingLeft As Integer
  90. Get
  91. Return ColumnPaddingLeft.Width.Value
  92. End Get
  93. Set(value As Integer)
  94. ColumnPaddingLeft.Width = New GridLength(value)
  95. End Set
  96. End Property
  97. ''' <summary>
  98. ''' 右边距的最小值。
  99. ''' 在存在右侧按钮时,右边距会被自动设置为 5 + 按钮数 * 25。
  100. ''' </summary>
  101. Public Property MinPaddingRight As Integer = 4
  102. '按钮
  103. Private _Buttons As IEnumerable(Of MyIconButton)
  104. Public Property Buttons As IEnumerable(Of MyIconButton)
  105. Get
  106. Return _Buttons
  107. End Get
  108. Set(value As IEnumerable(Of MyIconButton))
  109. _Buttons = value
  110. '没有特殊按钮,移除原 Stack
  111. If ButtonStack IsNot Nothing Then
  112. Children.Remove(ButtonStack)
  113. ButtonStack = Nothing
  114. End If
  115. '添加新 Stack
  116. Select Case value.Count
  117. Case 0
  118. '没有按钮,不添加新的
  119. Case 1
  120. '只有一个按钮
  121. For Each Btn As MyIconButton In value
  122. If Btn.Height.Equals(Double.NaN) Then Btn.Height = 25
  123. If Btn.Width.Equals(Double.NaN) Then Btn.Width = 25
  124. With Btn
  125. .Opacity = 0
  126. .Margin = New Thickness(0, 0, 5, 0)
  127. .SnapsToDevicePixels = False
  128. .HorizontalAlignment = HorizontalAlignment.Right
  129. .VerticalAlignment = VerticalAlignment.Center
  130. .SnapsToDevicePixels = False
  131. .UseLayoutRounding = False
  132. End With
  133. SetColumnSpan(Btn, 10) : SetRowSpan(Btn, 10)
  134. Children.Add(Btn)
  135. ButtonStack = Btn
  136. Next
  137. Case Else
  138. '有复数按钮,使用 StackPanel
  139. ButtonStack = New StackPanel With {.Opacity = 0, .Margin = New Thickness(0, 0, 5, 0), .SnapsToDevicePixels = False, .Orientation = Orientation.Horizontal, .HorizontalAlignment = HorizontalAlignment.Right, .VerticalAlignment = VerticalAlignment.Center, .UseLayoutRounding = False}
  140. SetColumnSpan(ButtonStack, 10) : SetRowSpan(ButtonStack, 10)
  141. '构造按钮
  142. For Each Btn As MyIconButton In value
  143. If Btn.Height.Equals(Double.NaN) Then Btn.Height = 25
  144. If Btn.Width.Equals(Double.NaN) Then Btn.Width = 25
  145. CType(ButtonStack, StackPanel).Children.Add(Btn)
  146. Next
  147. Children.Add(ButtonStack)
  148. End Select
  149. End Set
  150. End Property
  151. '标题
  152. Public ReadOnly Property Inlines As InlineCollection
  153. Get
  154. Return LabTitle.Inlines
  155. End Get
  156. End Property
  157. Public Property Title As String
  158. Get
  159. Return GetValue(TitleProperty)
  160. End Get
  161. Set(value As String)
  162. SetValue(TitleProperty, value.ReplaceLineEndings(""))
  163. End Set
  164. End Property
  165. Public Shared ReadOnly TitleProperty As DependencyProperty = DependencyProperty.Register("Title", GetType(String), GetType(MyListItem))
  166. '字号
  167. Public Property FontSize As Double
  168. Get
  169. Return GetValue(FontSizeProperty)
  170. End Get
  171. Set(value As Double)
  172. SetValue(FontSizeProperty, value)
  173. End Set
  174. End Property
  175. Public Shared ReadOnly FontSizeProperty As DependencyProperty = DependencyProperty.Register("FontSize", GetType(Double), GetType(MyListItem), New PropertyMetadata(CType(14, Double)))
  176. '信息
  177. Private _Info As String = ""
  178. Public Property Info As String
  179. Get
  180. Return _Info
  181. End Get
  182. Set(value As String)
  183. If _Info = value Then Return
  184. value = value.ReplaceLineEndings("")
  185. _Info = value
  186. LabInfo.Text = value
  187. LabInfo.Visibility = If(value = "", Visibility.Collapsed, Visibility.Visible)
  188. End Set
  189. End Property
  190. '图片
  191. Private _Logo As String = ""
  192. Public Property Logo As String
  193. Get
  194. Return _Logo
  195. End Get
  196. Set(value As String)
  197. If _Logo = value Then Return
  198. _Logo = value
  199. '删除旧 Logo
  200. If Not IsNothing(PathLogo) Then Children.Remove(PathLogo)
  201. '添加新 Logo
  202. If Not _Logo = "" Then
  203. If _Logo.StartsWithF("http", True) Then
  204. '网络图片
  205. PathLogo = New MyImage With {
  206. .Tag = Me,
  207. .IsHitTestVisible = LogoClickable,
  208. .Source = _Logo,
  209. .RenderTransformOrigin = New Point(0.5, 0.5),
  210. .RenderTransform = New ScaleTransform With {.ScaleX = LogoScale, .ScaleY = LogoScale},
  211. .SnapsToDevicePixels = True, .UseLayoutRounding = False}
  212. RenderOptions.SetBitmapScalingMode(PathLogo, BitmapScalingMode.Linear)
  213. ElseIf _Logo.EndsWithF(".png", True) OrElse _Logo.EndsWithF(".jpg", True) OrElse _Logo.EndsWithF(".webp", True) Then
  214. '位图
  215. PathLogo = New Canvas With {
  216. .Tag = Me,
  217. .IsHitTestVisible = LogoClickable,
  218. .Background = New MyBitmap(_Logo),
  219. .RenderTransformOrigin = New Point(0.5, 0.5),
  220. .RenderTransform = New ScaleTransform With {.ScaleX = LogoScale, .ScaleY = LogoScale},
  221. .SnapsToDevicePixels = True, .UseLayoutRounding = False,
  222. .HorizontalAlignment = HorizontalAlignment.Stretch, .VerticalAlignment = VerticalAlignment.Stretch
  223. }
  224. RenderOptions.SetBitmapScalingMode(PathLogo, BitmapScalingMode.Linear)
  225. Else
  226. '矢量图
  227. PathLogo = New Shapes.Path With {
  228. .Tag = Me,
  229. .IsHitTestVisible = LogoClickable, .HorizontalAlignment = HorizontalAlignment.Center, .VerticalAlignment = VerticalAlignment.Center, .Stretch = Stretch.Uniform,
  230. .Data = (New GeometryConverter).ConvertFromString(_Logo),
  231. .RenderTransformOrigin = New Point(0.5, 0.5),
  232. .RenderTransform = New ScaleTransform With {.ScaleX = LogoScale, .ScaleY = LogoScale},
  233. .SnapsToDevicePixels = False, .UseLayoutRounding = False}
  234. PathLogo.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = Me})
  235. End If
  236. SetColumn(PathLogo, 2)
  237. SetRowSpan(PathLogo, 4)
  238. OnSizeChanged() '设置边距
  239. Children.Add(PathLogo)
  240. '图标的点击事件
  241. If LogoClickable Then
  242. AddHandler PathLogo.MouseLeave, Sub(sender, e) IsLogoDown = False
  243. AddHandler PathLogo.MouseLeftButtonDown, Sub(sender, e) IsLogoDown = True
  244. AddHandler PathLogo.MouseLeftButtonUp, Sub(sender, e) If IsLogoDown Then IsLogoDown = False : RaiseEvent LogoClick(sender.Tag, e)
  245. End If
  246. End If
  247. '改变行距
  248. ColumnLogo.Width = New GridLength(If(_Logo = "", 0, 34) + If(Height < 40, 0, 4))
  249. End Set
  250. End Property
  251. Private _LogoScale As Double = 1
  252. Public Property LogoScale() As Double
  253. Get
  254. Return _LogoScale
  255. End Get
  256. Set(value As Double)
  257. _LogoScale = value
  258. If Not IsNothing(PathLogo) Then PathLogo.RenderTransform = New ScaleTransform With {.ScaleX = LogoScale, .ScaleY = LogoScale}
  259. End Set
  260. End Property
  261. '图标的点击
  262. ''' <summary>
  263. ''' 该 Logo 是否可用点击触发事件。需要在 Logo 属性之前设置。
  264. ''' </summary>
  265. Public Property LogoClickable As Boolean = False
  266. Private IsLogoDown As Boolean = False
  267. '勾选选项
  268. Public Enum CheckType
  269. None
  270. Clickable
  271. RadioBox
  272. CheckBox
  273. End Enum
  274. Private _Type As CheckType = CheckType.None
  275. Public Property Type As CheckType
  276. Get
  277. Return _Type
  278. End Get
  279. Set(value As CheckType)
  280. If _Type = value Then Return
  281. _Type = value
  282. '切换左栏大小
  283. ColumnCheck.Width = New GridLength(If(_Type = CheckType.None OrElse _Type = CheckType.Clickable, If(Height < 40, 4, 2), 6))
  284. '切换竖条控件
  285. If _Type = CheckType.None OrElse _Type = CheckType.Clickable Then
  286. '移除竖条控件
  287. If Not IsNothing(RectCheck) Then
  288. Children.Remove(RectCheck)
  289. RectCheck = Nothing
  290. End If
  291. SetChecked(False, False, False)
  292. Else
  293. '添加竖条控件
  294. If IsNothing(RectCheck) Then
  295. RectCheck = New Border With {
  296. .Width = 5, .Height = If(Checked, Double.NaN, 0), .CornerRadius = New CornerRadius(2, 2, 2, 2),
  297. .VerticalAlignment = If(Checked, VerticalAlignment.Stretch, VerticalAlignment.Center),
  298. .HorizontalAlignment = HorizontalAlignment.Left, .UseLayoutRounding = False, .SnapsToDevicePixels = False,
  299. .Margin = If(Checked, New Thickness(-1, 6, 0, 6), New Thickness(-1, 0, 0, 0))}
  300. RectCheck.SetResourceReference(Border.BackgroundProperty, "ColorBrush3")
  301. SetRowSpan(RectCheck, 4)
  302. Children.Add(RectCheck)
  303. End If
  304. End If
  305. End Set
  306. End Property
  307. '适应尺寸
  308. Private Sub OnSizeChanged() Handles Me.SizeChanged
  309. ColumnCheck.Width = New GridLength(If(_Type = CheckType.None OrElse _Type = CheckType.Clickable, If(Height < 40, 4, 2), 6))
  310. ColumnLogo.Width = New GridLength(If(_Logo = "", 0, 34) + If(Height < 40, 0, 4))
  311. If PathLogo IsNot Nothing Then
  312. If _Logo.EndsWithF(".png", True) OrElse _Logo.EndsWithF(".jpg", True) OrElse _Logo.EndsWithF(".webp", True) Then
  313. PathLogo.Margin = New Thickness(4, 5, 3, 5)
  314. Else
  315. PathLogo.Margin = New Thickness(If(Height < 40, 6, 8), 8, If(Height < 40, 4, 6), 8)
  316. End If
  317. End If
  318. LabTitle.Margin = New Thickness(4, 0, 0, If(Height < 40, 0, 2))
  319. End Sub
  320. '勾选状态
  321. Private _Checked As Boolean = False
  322. Public Property Checked As Boolean
  323. Get
  324. Return _Checked
  325. End Get
  326. Set(value As Boolean)
  327. SetChecked(value, False, value <> _Checked) '仅在值发生变化时触发动画 (#4596)
  328. End Set
  329. End Property
  330. ''' <summary>
  331. ''' 手动设置 Checked 属性。
  332. ''' </summary>
  333. ''' <param name="value">新的 Checked 属性。</param>
  334. ''' <param name="user">是否由用户引发。</param>
  335. ''' <param name="anime">是否执行动画。</param>
  336. Public Sub SetChecked(value As Boolean, user As Boolean, anime As Boolean)
  337. Try
  338. '自定义属性基础
  339. Dim ChangedEventArgs As New RouteEventArgs(user)
  340. Dim RawValue = _Checked
  341. If Type = CheckType.RadioBox Then
  342. If IsInitialized AndAlso Not value = _Checked Then
  343. _Checked = value
  344. RaiseEvent Changed(Me, ChangedEventArgs)
  345. If ChangedEventArgs.Handled Then
  346. _Checked = RawValue
  347. Return
  348. End If
  349. End If
  350. _Checked = value
  351. Else
  352. If value = _Checked Then Return
  353. _Checked = value
  354. If IsInitialized Then
  355. RaiseEvent Changed(Me, ChangedEventArgs)
  356. If ChangedEventArgs.Handled Then
  357. _Checked = RawValue
  358. Return
  359. End If
  360. End If
  361. End If
  362. If value Then
  363. Dim CheckEventArgs As New RouteEventArgs(user)
  364. RaiseEvent Check(Me, CheckEventArgs)
  365. If CheckEventArgs.Handled Then Return
  366. End If
  367. '保证只有一个单选 ListItem 选中
  368. If Type = CheckType.RadioBox Then
  369. If IsNothing(Parent) Then Return
  370. Dim RadioboxList As New List(Of MyListItem)
  371. Dim CheckedCount As Integer = 0
  372. '收集控件列表与选中个数
  373. For Each Control In CType(Parent, Object).Children
  374. Control = MyVirtualizingElement.TryInit(Control)
  375. If TypeOf Control Is MyListItem AndAlso CType(Control, MyListItem).Type = CheckType.RadioBox Then
  376. RadioboxList.Add(Control)
  377. If Control.Checked Then CheckedCount += 1
  378. End If
  379. Next
  380. '判断选中情况
  381. Select Case CheckedCount
  382. Case 0
  383. '没有任何单选框被选中,选择第一个
  384. RadioboxList(0).Checked = True
  385. Case Is > 1
  386. '选中项目多于 1 个
  387. If Me.Checked Then
  388. '如果本控件选中,则取消其他所有控件的选中
  389. For Each Control As MyListItem In RadioboxList
  390. If Control.Checked AndAlso Not Control.Equals(Me) Then Control.Checked = False
  391. Next
  392. Else
  393. '如果本控件未选中,则只保留第一个选中的控件
  394. Dim FirstChecked = False
  395. For Each Control As MyListItem In RadioboxList
  396. If Control.Checked Then
  397. If FirstChecked Then
  398. Control.Checked = False '修改 Checked 会自动触发 Change 事件,所以不用额外触发
  399. Else
  400. FirstChecked = True
  401. End If
  402. End If
  403. Next
  404. End If
  405. End Select
  406. End If
  407. '更改动画
  408. If IsLoaded AndAlso AniControlEnabled = 0 AndAlso anime Then '防止默认属性变更触发动画
  409. Dim Anim As New List(Of AniData)
  410. If Checked Then
  411. '由无变有
  412. If Not IsNothing(RectCheck) Then
  413. Dim Delta = ActualHeight - RectCheck.ActualHeight - 12
  414. Anim.Add(AaHeight(RectCheck, Delta * 0.4, 200,, New AniEaseOutFluent(AniEasePower.Weak)))
  415. Anim.Add(AaHeight(RectCheck, Delta * 0.6, 300,, New AniEaseOutBack(AniEasePower.Weak)))
  416. Anim.Add(AaOpacity(RectCheck, 1 - RectCheck.Opacity, 30))
  417. RectCheck.VerticalAlignment = VerticalAlignment.Center
  418. RectCheck.Margin = New Thickness(-1, 0, 0, 0)
  419. End If
  420. Anim.Add(AaColor(Me, ForegroundProperty, If(Height < 40, "ColorBrush3", "ColorBrush2"), 200))
  421. Else
  422. '由有变无
  423. If Not IsNothing(RectCheck) Then
  424. 'Anim.Add(AaWidth(RectCheck, -RectCheck.Width, 120,, New AniEaseInFluent))
  425. Anim.Add(AaHeight(RectCheck, -RectCheck.ActualHeight, 120,, New AniEaseInFluent(AniEasePower.Weak)))
  426. Anim.Add(AaOpacity(RectCheck, -RectCheck.Opacity, 70, 40))
  427. RectCheck.VerticalAlignment = VerticalAlignment.Center
  428. End If
  429. Anim.Add(AaColor(Me, ForegroundProperty, "ColorBrush1", 120))
  430. End If
  431. AniStart(Anim, "MyListItem Checked " & Uuid)
  432. Else
  433. '不使用动画
  434. AniStop("MyListItem Checked " & Uuid)
  435. If Checked Then
  436. If Not IsNothing(RectCheck) Then
  437. RectCheck.Height = Double.NaN
  438. RectCheck.Margin = New Thickness(-1, 6, 0, 6)
  439. RectCheck.Opacity = 1
  440. RectCheck.VerticalAlignment = VerticalAlignment.Stretch
  441. End If
  442. SetResourceReference(ForegroundProperty, If(Height < 40, "ColorBrush3", "ColorBrush2"))
  443. Else
  444. If Not IsNothing(RectCheck) Then
  445. RectCheck.Height = 0
  446. RectCheck.Margin = New Thickness(-1, 0, 0, 0)
  447. RectCheck.Opacity = 0
  448. RectCheck.VerticalAlignment = VerticalAlignment.Center
  449. End If
  450. SetResourceReference(ForegroundProperty, "ColorBrush1")
  451. End If
  452. End If
  453. Catch ex As Exception
  454. Logger.Warn(ex, "设置 Checked 失败")
  455. End Try
  456. End Sub
  457. '前景色绑定
  458. Public Property Foreground As Brush
  459. Get
  460. Return GetValue(ForegroundProperty)
  461. End Get
  462. Set(value As Brush)
  463. SetValue(ForegroundProperty, value)
  464. End Set
  465. End Property
  466. Public Shared ReadOnly ForegroundProperty As DependencyProperty = DependencyProperty.Register("Foreground", GetType(Brush), GetType(MyListItem), New PropertyMetadata(CType(Color1, SolidColorBrush)))
  467. '菜单与按钮绑定
  468. Public ContentHandler As Action(Of MyListItem, EventArgs)
  469. #End Region
  470. #Region "点击"
  471. '触发点击事件
  472. Private Sub Button_MouseUp(sender As Object, e As MouseButtonEventArgs) Handles Me.PreviewMouseLeftButtonUp
  473. If Not IsMouseDown Then Return
  474. RaiseEvent Click(sender, e)
  475. If e.Handled Then Return
  476. '触发自定义事件
  477. If CustomEventService.GetEventType(sender) <> CustomEvent.EventType.None OrElse
  478. CustomEventService.GetEvents(sender).Events.Count > 0 Then
  479. RaiseCustomEvent()
  480. e.Handled = True
  481. End If
  482. If e.Handled Then Return
  483. '实际的单击处理
  484. Select Case Type
  485. Case CheckType.Clickable
  486. Logger.Info($"按下单击列表项:{Title}")
  487. Case CheckType.RadioBox
  488. Logger.Info($"按下单选列表项:{Title}")
  489. If Not Checked Then SetChecked(True, True, True)
  490. Case CheckType.CheckBox
  491. Logger.Info($"按下复选列表项({Not Checked}):{Title}")
  492. SetChecked(Not Checked, True, True)
  493. End Select
  494. End Sub
  495. '鼠标点击判定
  496. Private IsMouseDown As Boolean = False
  497. Private Sub Button_MouseDown(sender As Object, e As MouseButtonEventArgs) Handles Me.PreviewMouseLeftButtonDown
  498. If IsMouseDirectlyOver AndAlso Not Type = CheckType.None Then
  499. IsMouseDown = True
  500. If ButtonStack IsNot Nothing Then ButtonStack.IsHitTestVisible = False
  501. End If
  502. End Sub
  503. Private Sub Button_MouseLeave(sender As Object, e As Object) Handles Me.MouseLeave, Me.PreviewMouseLeftButtonUp
  504. IsMouseDown = False
  505. If ButtonStack IsNot Nothing Then ButtonStack.IsHitTestVisible = True
  506. End Sub
  507. #End Region
  508. Private StateLast As String
  509. Public IsMouseOverAnimationEnabled As Boolean = True
  510. Public Sub RefreshColor(sender As Object, e As EventArgs) Handles Me.MouseEnter, Me.MouseLeave, Me.PreviewMouseLeftButtonDown, Me.PreviewMouseLeftButtonUp
  511. '菜单虚拟化检测
  512. If ContentHandler IsNot Nothing Then
  513. ContentHandler(Me, e)
  514. ContentHandler = Nothing
  515. End If
  516. '判断当前颜色
  517. Dim StateNew As String, Time As Integer
  518. If IsMouseDown AndAlso Not (Type = CheckType.RadioBox AndAlso Checked) Then
  519. StateNew = "MouseDown"
  520. Time = 120
  521. Else
  522. If IsMouseOver AndAlso IsMouseOverAnimationEnabled Then
  523. StateNew = "MouseOver"
  524. Time = 120
  525. Else
  526. StateNew = "Idle"
  527. Time = 180
  528. End If
  529. End If
  530. If StateLast = StateNew Then Return
  531. StateLast = StateNew
  532. '触发颜色动画
  533. If IsLoaded AndAlso AniControlEnabled = 0 Then '防止默认属性变更触发动画
  534. '有动画
  535. Dim Ani As New List(Of AniData)
  536. If IsMouseOver AndAlso IsMouseOverAnimationEnabled Then
  537. If ButtonStack IsNot Nothing Then
  538. Ani.Add(AaOpacity(ButtonStack, 1 - ButtonStack.Opacity, Time * 0.7, Time * 0.3))
  539. Ani.Add(AaDouble(Sub(i) ColumnPaddingRight.Width = New GridLength(Math.Max(0, ColumnPaddingRight.Width.Value + i)),
  540. Math.Max(MinPaddingRight, 5 + Buttons.Count * 25) - ColumnPaddingRight.Width.Value, Time * 0.3, Time * 0.7))
  541. End If
  542. Ani.AddRange({
  543. AaColor(RectBack, Border.BackgroundProperty, If(IsMouseDown, "ColorBrush6", "ColorBrushBg1"), Time),
  544. AaOpacity(RectBack, 1 - RectBack.Opacity, Time,, New AniEaseOutFluent)
  545. })
  546. If IsScaleAnimationEnabled Then
  547. Ani.Add(AaScaleTransform(RectBack, 1 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time * 1.6,, New AniEaseOutFluent))
  548. If IsMouseDown Then
  549. Ani.Add(AaScaleTransform(Me, 0.98 - CType(Me.RenderTransform, ScaleTransform).ScaleX, Time * 0.9,, New AniEaseOutFluent))
  550. Else
  551. Ani.Add(AaScaleTransform(Me, 1 - CType(Me.RenderTransform, ScaleTransform).ScaleX, Time * 1.2,, New AniEaseOutFluent))
  552. End If
  553. End If
  554. Else
  555. If ButtonStack IsNot Nothing Then
  556. Ani.Add(AaOpacity(ButtonStack, -ButtonStack.Opacity, Time * 0.4))
  557. Ani.Add(AaDouble(Sub(i) ColumnPaddingRight.Width = New GridLength(Math.Max(0, ColumnPaddingRight.Width.Value + i)),
  558. MinPaddingRight - ColumnPaddingRight.Width.Value, Time * 0.4))
  559. End If
  560. Ani.Add(AaOpacity(RectBack, -RectBack.Opacity, Time))
  561. If IsScaleAnimationEnabled Then
  562. Ani.AddRange({
  563. AaColor(RectBack, Border.BackgroundProperty, If(IsMouseDown, "ColorBrush6", "ColorBrush7"), Time),
  564. AaScaleTransform(Me, 1 - CType(RenderTransform, ScaleTransform).ScaleX, Time * 3,, New AniEaseOutFluent),
  565. AaScaleTransform(RectBack, 0.996 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time,, New AniEaseOutFluent),
  566. AaScaleTransform(RectBack, -0.246, 1,,, True)
  567. })
  568. End If
  569. End If
  570. AniStart(Ani, "ListItem Color " & Uuid)
  571. Else
  572. '无动画
  573. If IsMouseOver AndAlso IsMouseOverAnimationEnabled Then
  574. If ButtonStack IsNot Nothing Then
  575. ButtonStack.Opacity = 1
  576. ColumnPaddingRight.Width = New GridLength(Math.Max(MinPaddingRight, 5 + Buttons.Count * 25))
  577. End If
  578. '由于鼠标已经移入,所以直接实例化 RectBack
  579. RectBack.Background = ColorBg1
  580. RectBack.Opacity = 1
  581. RectBack.RenderTransform = New ScaleTransform(1, 1)
  582. Me.RenderTransform = New ScaleTransform(1, 1)
  583. Else
  584. If ButtonStack IsNot Nothing Then
  585. ButtonStack.Opacity = 0
  586. ColumnPaddingRight.Width = New GridLength(MinPaddingRight)
  587. End If
  588. Me.RenderTransform = New ScaleTransform(1, 1)
  589. If _RectBack IsNot Nothing Then
  590. If IsScaleAnimationEnabled Then RectBack.RenderTransform = New ScaleTransform(0.75, 0.75)
  591. RectBack.Background = Color7
  592. RectBack.Opacity = 0
  593. End If
  594. End If
  595. AniStop("ListItem Color " & Uuid)
  596. End If
  597. End Sub
  598. Private Sub MyListItem_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
  599. If Checked Then
  600. SetResourceReference(ForegroundProperty, If(Height < 40, "ColorBrush3", "ColorBrush2"))
  601. Else
  602. SetResourceReference(ForegroundProperty, "ColorBrush1")
  603. End If
  604. ColumnPaddingRight.Width = New GridLength(MinPaddingRight)
  605. If CustomEventService.GetEventType(Me) = CustomEvent.EventType.打开帮助 AndAlso Not (Title <> "" AndAlso Info <> "") Then '#3266
  606. Try
  607. Dim Entry As New HelpEntry(CustomEvent.GetAbsoluteUrls(CustomEventService.GetEventData(Me), CustomEventService.GetEventType(Me))(0))
  608. Entry.SetToListItem(Me)
  609. Catch ex As Exception
  610. Logger.Error(ex, "设置帮助 MyListItem 失败", LogBehavior.Alert)
  611. CustomEventService.SetEventType(Me, CustomEvent.EventType.None)
  612. CustomEventService.SetEventData(Me, "")
  613. End Try
  614. End If
  615. End Sub
  616. Public Overrides Function ToString() As String
  617. Return Title
  618. End Function
  619. End Class