1
0

MyPageRight.vb 25 KB

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