MyListItem.xaml.vb 30 KB

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