MyPageRight.vb 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. Public Class MyPageRight
  2. Inherits AdornerDecorator
  3. Public PageUuid As Integer = GetUuid()
  4. '“返回顶部” 按钮检测的滚动区域
  5. Public PanScroll As MyScrollViewer
  6. Private Shared ReadOnly PanScrollProperty =
  7. DependencyProperty.RegisterAttached("PanScroll", GetType(String), GetType(MyPageRight), New PropertyMetadata(Nothing, AddressOf OnPanScrollChanged))
  8. Public Shared Sub SetPanScroll(obj As DependencyObject, value As String)
  9. obj.SetValue(PanScrollProperty, value)
  10. End Sub
  11. Private Shared Sub OnPanScrollChanged(d As DependencyObject, e As DependencyPropertyChangedEventArgs)
  12. Dim control = TryCast(d, MyPageRight)
  13. If control IsNot Nothing Then
  14. Dim handler As RoutedEventHandler
  15. handler = Sub(sender, args)
  16. Dim targetName = CStr(e.NewValue)
  17. Dim target = TryCast(control.FindName(targetName), FrameworkElement)
  18. If target IsNot Nothing Then
  19. control.PanScroll = target
  20. End If
  21. RemoveHandler control.Loaded, handler
  22. End Sub
  23. AddHandler control.Loaded, handler
  24. End If
  25. End Sub
  26. '当前状态
  27. Public Enum PageStates
  28. Empty '默认状态,页面全空
  29. LoaderWait '加载环初始等待
  30. LoaderEnter '加载环进入动画
  31. LoaderStayForce '加载环正常显示(强制等待)
  32. LoaderStay '加载环正常显示
  33. LoaderExit '加载环退出动画
  34. ContentEnter '内容进入动画
  35. ContentStay '内容正常显示
  36. ContentExit '刷新导致的全部退出动画,或页面内容退出(子页面更改)导致的全部退出动画
  37. PageExit '切换页面导致的全部退出动画
  38. End Enum
  39. Private _PageState As PageStates = PageStates.Empty
  40. Public Property PageState As PageStates
  41. Get
  42. Return _PageState
  43. End Get
  44. Set(value As PageStates)
  45. If _PageState = value Then Return
  46. _PageState = value
  47. If ModeDebug Then Log("[UI] 页面状态切换为 " & GetStringFromEnum(value))
  48. End Set
  49. End Property
  50. #Region "加载器"
  51. Private PageLoader As LoaderBase
  52. Private PageLoaderInputInvoke
  53. Private PageLoaderUi As MyLoading
  54. Private PanLoader As FrameworkElement
  55. Private PanContent As FrameworkElement
  56. Private PanAlways As FrameworkElement
  57. Private PageLoaderAutoRun As Boolean
  58. '初始化
  59. ''' <summary>
  60. ''' 表明页面存在需要在后台执行的加载器。
  61. ''' </summary>
  62. ''' <param name="LoaderUi">MyLoading 控件。</param>
  63. ''' <param name="PanLoader">MyLoading 控件对应的卡片。</param>
  64. ''' <param name="PanContent">加载结束后出现的内容容器。</param>
  65. ''' <param name="PanAlways">无论是否在加载总是要显示的容器。可以为 Nothing。</param>
  66. ''' <param name="RealLoader">在工作线程执行的加载器。</param>
  67. ''' <param name="FinishedInvoke">当加载器执行完成,在 UI 线程触发的 UI 初始化事件。</param>
  68. Public Sub PageLoaderInit(LoaderUi As MyLoading, PanLoader As FrameworkElement, PanContent As FrameworkElement, PanAlways As FrameworkElement,
  69. RealLoader As LoaderBase,
  70. Optional FinishedInvoke As Action(Of LoaderBase) = Nothing, Optional InputInvoke As Func(Of Object) = Nothing,
  71. Optional AutoRun As Boolean = True)
  72. '初始化参数
  73. Me.PanLoader = PanLoader
  74. Me.PanContent = PanContent
  75. Me.PanAlways = PanAlways
  76. Me.PageLoader = RealLoader
  77. Me.PageLoaderUi = LoaderUi
  78. Me.PageLoaderInputInvoke = InputInvoke
  79. Me.PageLoaderAutoRun = AutoRun
  80. '添加结束 Invoke
  81. If FinishedInvoke IsNot Nothing Then
  82. AddHandler RealLoader.PreviewFinish,
  83. Sub()
  84. Do While PageState = MyPageRight.PageStates.PageExit OrElse PageState = MyPageRight.PageStates.ContentExit
  85. Thread.Sleep(10) '不在退出动画时执行 UI 线程操作,避免退出动画被重置
  86. Loop
  87. RunInUiWait(Sub() FinishedInvoke(RealLoader))
  88. Thread.Sleep(20) '由于大量初始化控件会导致掉帧,延迟触发 State 改变事件
  89. End Sub
  90. End If
  91. AddHandler RealLoader.OnStateChangedUi, Sub(Loader As LoaderBase, NewState As LoadState, OldState As LoadState) RunInUi(Sub() PageLoaderState(Loader, NewState, OldState))
  92. '隐藏 UI
  93. PanLoader.Visibility = Visibility.Collapsed
  94. PanContent.Visibility = Visibility.Collapsed
  95. If PanAlways IsNot Nothing Then PanAlways.Visibility = Visibility.Collapsed
  96. '初次运行加载器
  97. If PageLoaderAutoRun Then
  98. If PageLoader.GetType.Name.StartsWithF("LoaderTask") Then
  99. PageLoader.Start(CType(PageLoader, Object).StartGetInput(Nothing, PageLoaderInputInvoke))
  100. Else
  101. Dim Input = Nothing
  102. If PageLoaderInputInvoke IsNot Nothing Then Input = PageLoaderInputInvoke()
  103. PageLoader.Start(Input)
  104. End If
  105. End If
  106. If PageLoader.State = LoadState.Finished AndAlso FinishedInvoke IsNot Nothing Then
  107. RunInUiWait(Sub() FinishedInvoke(RealLoader)) '加载器已提前完成,直接触发事件
  108. End If
  109. '设置加载环
  110. PageLoaderUi.State = RealLoader
  111. AddHandler PageLoaderUi.Click, Sub() If RealLoader.State = LoadState.Failed Then PageLoaderRestart() '点击重试事件
  112. End Sub
  113. '重试
  114. Public Sub PageLoaderRestart(Optional Input As Object = Nothing, Optional IsForceRestart As Boolean = True) '由外部调用的重试
  115. If Not PageLoaderAutoRun Then Return
  116. If PageLoader.GetType.Name.StartsWithF("LoaderTask") Then
  117. PageLoader.Start(CType(PageLoader, Object).StartGetInput(Input, PageLoaderInputInvoke), IsForceRestart:=IsForceRestart)
  118. Else
  119. If Input Is Nothing AndAlso PageLoaderInputInvoke IsNot Nothing Then Input = PageLoaderInputInvoke()
  120. PageLoader.Start(Input, IsForceRestart:=IsForceRestart)
  121. End If
  122. End Sub
  123. #End Region
  124. #Region "事件"
  125. '外部触发的事件
  126. ''' <summary>
  127. ''' 需要切换到当前页面,并且原本的 Loaded 事件已执行完成。
  128. ''' 需要根据加载器状态,从 Empty 切换到 ContentEnter、LoaderWait、LoaderEnter。
  129. ''' </summary>
  130. Public Sub PageOnEnter()
  131. If ModeDebug Then Log("[UI] 已触发 PageOnEnter")
  132. RaiseEvent PageEnter()
  133. Select Case PageState
  134. Case PageStates.Empty
  135. If PageLoader Is Nothing OrElse PageLoader.State = LoadState.Finished OrElse PageLoader.State = LoadState.Waiting OrElse PageLoader.State = LoadState.Aborted Then
  136. '如果加载器在进入页面时不启动(例如 HiPer 联机),那么在此时就会有 State = Waiting
  137. PageState = PageStates.ContentEnter
  138. TriggerEnterAnimation(PanAlways, If(PanContent, Child))
  139. ElseIf PageLoader.State = LoadState.Loading Then
  140. PageState = PageStates.LoaderWait
  141. AniStart(AaCode(AddressOf PageOnLoaderWaitFinished, 200), "PageRight PageChange " & PageUuid)
  142. Else 'PageLoader.State = LoadState.Failed
  143. PageState = PageStates.LoaderEnter
  144. TriggerEnterAnimation(PanAlways, PanLoader)
  145. End If
  146. Case PageStates.ContentExit
  147. '和上面的一样,但是不管 PanAlways
  148. If PageLoader Is Nothing OrElse PageLoader.State = LoadState.Finished OrElse PageLoader.State = LoadState.Waiting OrElse PageLoader.State = LoadState.Aborted Then
  149. PageState = PageStates.ContentEnter
  150. TriggerEnterAnimation(If(PanContent, Child))
  151. ElseIf PageLoader.State = LoadState.Loading Then
  152. PageState = PageStates.LoaderWait
  153. AniStart(AaCode(AddressOf PageOnLoaderWaitFinished, 200), "PageRight PageChange " & PageUuid)
  154. Else 'PageLoader.State = LoadState.Failed
  155. PageState = PageStates.LoaderEnter
  156. TriggerEnterAnimation(PanLoader)
  157. End If
  158. Case PageStates.ContentEnter '重复调用 PageOnEnter,直接忽略
  159. Case Else
  160. Throw New Exception("在状态为 " & GetStringFromEnum(PageState) & " 时触发了 PageOnEnter 事件。")
  161. End Select
  162. End Sub
  163. Public Event PageEnter()
  164. ''' <summary>
  165. ''' 需要切换到其他页面。
  166. ''' 需要立即切换至 PageExit 或 Empty。
  167. ''' </summary>
  168. Public Sub PageOnExit()
  169. If ModeDebug Then Log("[UI] 已触发 PageOnExit")
  170. RaiseEvent PageExit()
  171. Select Case PageState
  172. Case PageStates.ContentEnter, PageStates.ContentStay
  173. PageState = PageStates.PageExit
  174. TriggerExitAnimation(PanAlways, If(PanContent, Child))
  175. Case PageStates.LoaderEnter, PageStates.LoaderStayForce, PageStates.LoaderStay
  176. PageState = PageStates.PageExit
  177. TriggerExitAnimation(PanAlways, PanLoader)
  178. Case PageStates.LoaderWait
  179. PageState = PageStates.PageExit
  180. TriggerExitAnimation(PanAlways)
  181. Case PageStates.LoaderExit, PageStates.ContentExit
  182. PageState = PageStates.PageExit
  183. If PanAlways IsNot Nothing Then TriggerExitAnimation(PanAlways, If(PanContent, Child))
  184. Case PageStates.PageExit, PageStates.Empty
  185. End Select
  186. End Sub
  187. Public Event PageExit()
  188. ''' <summary>
  189. ''' 即将切换到其他页面,需要强制完成页面状态清理。
  190. ''' 需要立即切换至 Empty。
  191. ''' </summary>
  192. Public Sub PageOnForceExit()
  193. If PageState = PageStates.Empty Then Return
  194. If ModeDebug Then Log("[UI] 已触发 PageOnForceExit")
  195. PageState = PageStates.Empty
  196. AniStop("PageRight PageChange " & PageUuid)
  197. '由于动画会被强制中止,所以需要手动进行隐藏
  198. If PageLoader Is Nothing Then
  199. Child.Visibility = Visibility.Collapsed
  200. Else
  201. PanContent.Visibility = Visibility.Collapsed
  202. PanLoader.Visibility = Visibility.Collapsed
  203. If PanAlways IsNot Nothing Then PanAlways.Visibility = Visibility.Collapsed
  204. End If
  205. End Sub
  206. ''' <summary>
  207. ''' PanContent 中的子页面改变,需要让当前内容退出,再显示新的内容。
  208. ''' 需要在 PageEnter 事件确认要显示的子页面有哪些。
  209. ''' </summary>
  210. Public Sub PageOnContentExit()
  211. If ModeDebug Then Log("[UI] 已触发 PageOnContentExit")
  212. If PageLoader IsNot Nothing AndAlso PageLoader.State = LoadState.Loading Then
  213. Throw New Exception("在调用 PageOnContentExit 时,加载器不能为 Loading 状态")
  214. 'Loading 的加载器可能触发进一步变化,难以预测会触发子页面的动画还是加载器完成的动画
  215. End If
  216. Select Case PageState
  217. Case PageStates.ContentEnter, PageStates.ContentStay
  218. PageState = PageStates.ContentExit
  219. TriggerExitAnimation(PanContent)
  220. Case PageStates.LoaderExit
  221. PageState = PageStates.ContentExit
  222. Case PageStates.LoaderEnter, PageStates.LoaderStayForce, PageStates.LoaderStay
  223. PageState = PageStates.ContentExit
  224. TriggerExitAnimation(PanLoader)
  225. Case PageStates.LoaderWait, PageStates.Empty
  226. PageOnEnter()
  227. End Select
  228. End Sub
  229. '内部触发的事件
  230. ''' <summary>
  231. ''' 逐个进入动画已执行完成。
  232. ''' 需要根据目前状态,从 ContentEnter 切换到 ContentStay,或从 LoaderEnter 切换到 LoaderStayForce。
  233. ''' </summary>
  234. Private Sub PageOnEnterAnimationFinished()
  235. If ModeDebug Then Log("[UI] 已触发 PageOnEnterAnimationFinished")
  236. Select Case PageState
  237. Case PageStates.ContentEnter
  238. PageState = PageStates.ContentStay
  239. Case PageStates.LoaderEnter
  240. PageState = PageStates.LoaderStayForce
  241. AniStart(AaCode(AddressOf PageOnLoaderStayFinished, 400), "PageRight PageChange " & PageUuid)
  242. Case Else
  243. Throw New Exception("在状态为 " & GetStringFromEnum(PageState) & " 时触发了 PageOnEnterAnimationFinished 事件。")
  244. End Select
  245. End Sub
  246. ''' <summary>
  247. ''' 逐个退出动画已执行完成。
  248. ''' 需要根据目前状态,从 AllExit 切换到 Empty,或从 LoaderExit 切换到 ContentEnter,或从 ContentExit 重新触发 PageOnEnter。
  249. ''' </summary>
  250. Private Sub PageOnExitAnimationFinished()
  251. If ModeDebug Then Log("[UI] 已触发 PageOnExitAnimationFinished")
  252. Select Case PageState
  253. Case PageStates.PageExit
  254. PageState = PageStates.Empty
  255. Case PageStates.ContentExit
  256. PageOnEnter()
  257. Case PageStates.LoaderExit
  258. PageState = PageStates.ContentEnter
  259. TriggerEnterAnimation(PanContent)
  260. Case Else
  261. Throw New Exception("在状态为 " & GetStringFromEnum(PageState) & " 时触发了 PageOnExitAnimationFinished 事件。")
  262. End Select
  263. End Sub
  264. ''' <summary>
  265. ''' 加载环进入等待已结束。
  266. ''' 需要从 LoaderWait 切换到 LoaderEnter。
  267. ''' </summary>
  268. Private Sub PageOnLoaderWaitFinished()
  269. If ModeDebug Then Log("[UI] 已触发 PageOnLoaderWaitFinished")
  270. Select Case PageState
  271. Case PageStates.LoaderWait
  272. PageState = PageStates.LoaderEnter
  273. If PanAlways IsNot Nothing AndAlso PanAlways.Visibility = Visibility.Collapsed Then
  274. TriggerEnterAnimation(PanAlways, PanLoader)
  275. Else
  276. TriggerEnterAnimation(PanLoader)
  277. End If
  278. Case Else
  279. Throw New Exception("在状态为 " & GetStringFromEnum(PageState) & " 时触发了 PageOnLoaderWaitFinished 事件。")
  280. End Select
  281. End Sub
  282. ''' <summary>
  283. ''' 加载环展示等待已结束。
  284. ''' 需要从 LoaderStayForce 切换到 LoaderStay 或 LoaderExit。
  285. ''' </summary>
  286. Private Sub PageOnLoaderStayFinished()
  287. If ModeDebug Then Log("[UI] 已触发 PageOnLoaderStayFinished")
  288. Select Case PageState
  289. Case PageStates.LoaderStayForce
  290. If PageLoader.State = LoadState.Finished Then
  291. PageState = PageStates.LoaderExit
  292. TriggerExitAnimation(PanLoader)
  293. Else
  294. PageState = PageStates.LoaderStay
  295. End If
  296. Case Else
  297. Throw New Exception("在状态为 " & GetStringFromEnum(PageState) & " 时触发了 PageOnLoaderWaitFinished 事件。")
  298. End Select
  299. End Sub
  300. ''' <summary>
  301. ''' 全局加载状态已改变。
  302. ''' </summary>
  303. Private Sub PageLoaderState(sender As Object, NewState As LoadState, OldState As LoadState)
  304. Select Case NewState
  305. Case LoadState.Failed, LoadState.Loading
  306. If OldState = LoadState.Failed OrElse OldState = LoadState.Loading Then Return
  307. If ModeDebug Then Log("[UI] 已触发 PageLoaderState (Start/Refresh)")
  308. '(重新)开始运行
  309. '需要从部分状态切换到 ReloadExit
  310. Select Case PageState
  311. Case PageStates.ContentEnter, PageStates.ContentStay
  312. PageState = PageStates.ContentExit
  313. TriggerExitAnimation(PanContent)
  314. Case PageStates.LoaderExit
  315. PageState = PageStates.ContentExit
  316. End Select
  317. Case LoadState.Finished, LoadState.Aborted, LoadState.Waiting
  318. If Not (OldState = LoadState.Failed OrElse OldState = LoadState.Loading) Then Return
  319. If ModeDebug Then Log("[UI] 已触发 PageLoaderState (Stop/Abort)")
  320. '运行结束
  321. '需要从 LoaderWait 切换到 ContentEnter,或从 LoaderStay 切换到 LoaderExit
  322. Select Case PageState
  323. Case PageStates.LoaderWait
  324. PageState = PageStates.ContentEnter
  325. If PanAlways IsNot Nothing AndAlso PanAlways.Visibility = Visibility.Collapsed Then
  326. TriggerEnterAnimation(PanAlways, PanContent)
  327. Else
  328. TriggerEnterAnimation(PanContent)
  329. End If
  330. Case PageStates.LoaderStay
  331. PageState = PageStates.LoaderExit
  332. TriggerExitAnimation(PanLoader)
  333. End Select
  334. End Select
  335. End Sub
  336. #End Region
  337. #Region "动画"
  338. '逐个进入动画
  339. Public Sub TriggerEnterAnimation(ParamArray Elements As FrameworkElement())
  340. Dim RealElements = Elements.Where(Function(e) e IsNot Nothing)
  341. For Each Element In RealElements
  342. Element.Visibility = Visibility.Visible '页面均处于默认的隐藏状态
  343. Next
  344. Dim AniList As New List(Of AniData)
  345. Dim Delay As Integer = 0
  346. '基础动画
  347. For Each Element In RealElements
  348. For Each Control As FrameworkElement In GetAllAnimControls(Element, True)
  349. '还原被隐藏的卡片的消失动画
  350. Control.IsHitTestVisible = True
  351. If Control.RenderTransform IsNot Nothing AndAlso TypeOf Control.RenderTransform Is TranslateTransform Then Control.RenderTransform = Nothing
  352. Next
  353. For Each Control As FrameworkElement In GetAllAnimControls(Element)
  354. If TypeOf Control Is MyExtraTextButton Then
  355. CType(Control, MyExtraTextButton).Show = True
  356. Else
  357. Control.Opacity = 0
  358. Control.RenderTransform = New TranslateTransform(0, -16)
  359. AniList.Add(AaOpacity(Control, 1, 100, Delay, New AniEaseOutFluent(AniEasePower.Weak)))
  360. AniList.Add(AaTranslateY(Control, 5, 250, Delay, New AniEaseOutFluent))
  361. AniList.Add(AaTranslateY(Control, 11, 350, Delay, New AniEaseOutBack))
  362. Delay += 25
  363. End If
  364. Next
  365. Next
  366. '滚动条动画
  367. Dim Scroll As MyScrollBar = GetFirstScrollViewer(RealElements)
  368. If Scroll IsNot Nothing Then
  369. If TypeOf Scroll.RenderTransform IsNot TranslateTransform Then Scroll.RenderTransform = New TranslateTransform(10, 0)
  370. AniList.Add(AaTranslateX(Scroll, -CType(Scroll.RenderTransform, TranslateTransform).X, 350, 0, New AniEaseOutFluent))
  371. End If
  372. '结束
  373. AniList.Add(AaCode(Sub() PageOnEnterAnimationFinished(),, True))
  374. AniStart(AniList, "PageRight PageChange " & PageUuid)
  375. End Sub
  376. '逐个退出动画
  377. Public Sub TriggerExitAnimation(ParamArray Elements As FrameworkElement())
  378. Dim RealElements = Elements.Where(Function(e) e IsNot Nothing)
  379. Dim AniList As New List(Of AniData)
  380. Dim Delay As Integer = 0
  381. For Each Element In RealElements
  382. For Each Control As FrameworkElement In GetAllAnimControls(Element)
  383. If TypeOf Control Is MyExtraTextButton Then
  384. CType(Control, MyExtraTextButton).Show = False
  385. Else
  386. Control.IsHitTestVisible = False
  387. AniList.Add(AaOpacity(Control, -1, 70, Delay))
  388. AniList.Add(AaTranslateY(Control, -6, 70, Delay))
  389. Delay += 15
  390. End If
  391. Next
  392. Next
  393. '滚动条动画
  394. Dim Scroll As MyScrollBar = GetFirstScrollViewer(RealElements)
  395. If Scroll IsNot Nothing Then
  396. If TypeOf Scroll.RenderTransform IsNot TranslateTransform Then Scroll.RenderTransform = New TranslateTransform
  397. AniList.Add(AaTranslateX(Scroll, 10 - CType(Scroll.RenderTransform, TranslateTransform).X, 90, 0, New AniEaseInFluent))
  398. End If
  399. '结束
  400. AniList.Add(AaCode(
  401. Sub()
  402. For Each Element In RealElements
  403. Element.Visibility = Visibility.Collapsed
  404. Next
  405. PageOnExitAnimationFinished()
  406. End Sub,, True))
  407. AniStart(AniList, "PageRight PageChange " & PageUuid)
  408. End Sub
  409. ''' <summary>
  410. ''' 禁用页面切换动画的控件列表。
  411. ''' </summary>
  412. Public DisabledPageAnimControls As New List(Of FrameworkElement)
  413. ''' <summary>
  414. ''' 遍历获取所有需要生成动画的控件。
  415. ''' </summary>
  416. Friend Function GetAllAnimControls(Element As FrameworkElement, Optional IgnoreInvisibility As Boolean = False) As IEnumerable(Of FrameworkElement)
  417. Dim AllControls As New List(Of FrameworkElement)
  418. _GetAllAnimControls(Element, AllControls, IgnoreInvisibility)
  419. Return AllControls.Except(DisabledPageAnimControls)
  420. End Function
  421. Private Sub _GetAllAnimControls(Element As FrameworkElement, ByRef AllControls As List(Of FrameworkElement), IgnoreInvisibility As Boolean)
  422. If Not IgnoreInvisibility AndAlso Element.Visibility = Visibility.Collapsed Then Return
  423. If TypeOf Element Is MyCard OrElse TypeOf Element Is MyHint OrElse TypeOf Element Is MyExtraTextButton OrElse TypeOf Element Is TextBlock OrElse TypeOf Element Is MyTextButton Then
  424. AllControls.Add(Element)
  425. ElseIf TypeOf Element Is ContentControl Then
  426. Dim Content = CType(Element, ContentControl).Content
  427. If Content IsNot Nothing AndAlso TypeOf Content Is FrameworkElement Then _GetAllAnimControls(Content, AllControls, IgnoreInvisibility)
  428. ElseIf TypeOf Element Is Panel Then
  429. For Each Element2 In CType(Element, Panel).Children
  430. If TypeOf Element2 Is FrameworkElement Then _GetAllAnimControls(Element2, AllControls, IgnoreInvisibility)
  431. Next
  432. End If
  433. End Sub
  434. '查找列表中的第一个滚动条
  435. Private Function GetFirstScrollViewer(Elements As IEnumerable(Of FrameworkElement)) As MyScrollBar
  436. Dim Viewer As MyScrollViewer = Nothing
  437. For Each Element In Elements
  438. If TypeOf Element Is MyScrollViewer Then
  439. Viewer = Element
  440. GoTo FindViewer
  441. End If
  442. For Each Control In LogicalTreeHelper.GetChildren(Element)
  443. If TypeOf Control Is MyScrollViewer Then
  444. Viewer = Control
  445. GoTo FindViewer
  446. End If
  447. Next
  448. Next
  449. Return Nothing
  450. FindViewer:
  451. If Viewer.ComputedVerticalScrollBarVisibility <> Visibility.Visible Then Return Nothing
  452. Return Viewer.ScrollBar
  453. End Function
  454. #End Region
  455. End Class