PageDownloadInstall.xaml.vb 61 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282
  1. Public Class PageDownloadInstall
  2. Private Sub LoaderInit() Handles Me.Initialized
  3. DisabledPageAnimControls.Add(BtnStart)
  4. PageLoaderInit(LoadMinecraft, PanLoad, PanAllBack, Nothing, DlClientListLoader, AddressOf LoadMinecraft_OnFinish)
  5. End Sub
  6. Private IsLoad As Boolean = False
  7. Private Sub Init() Handles Me.Loaded
  8. PanBack.ScrollToHome()
  9. DlOptiFineListLoader.Start()
  10. DlLiteLoaderListLoader.Start()
  11. DlFabricListLoader.Start()
  12. DlNeoForgeListLoader.Start()
  13. '重载预览
  14. TextSelectName.ValidateRules = New ObjectModel.Collection(Of Validate) From {New ValidateFolderName(PathMcFolder & "versions")}
  15. TextSelectName.Validate()
  16. SelectReload()
  17. '非重复加载部分
  18. If IsLoad Then Exit Sub
  19. IsLoad = True
  20. McDownloadForgeRecommendedRefresh()
  21. LoadOptiFine.State = DlOptiFineListLoader
  22. LoadLiteLoader.State = DlLiteLoaderListLoader
  23. LoadFabric.State = DlFabricListLoader
  24. LoadFabricApi.State = DlFabricApiLoader
  25. LoadNeoForge.State = DlNeoForgeListLoader
  26. LoadOptiFabric.State = DlOptiFabricLoader
  27. End Sub
  28. #Region "页面切换"
  29. '页面切换动画
  30. Public IsInSelectPage As Boolean = False
  31. Private IsFirstLoaded As Boolean = False
  32. Private Sub EnterSelectPage()
  33. If IsInSelectPage Then Exit Sub
  34. IsInSelectPage = True
  35. PanInner.Margin = New Thickness(25, 10, 25, 40)
  36. AutoSelectedFabricApi = False
  37. AutoSelectedOptiFabric = False
  38. IsSelectNameEdited = False
  39. PanSelect.Visibility = Visibility.Visible
  40. PanSelect.IsHitTestVisible = True
  41. PanMinecraft.IsHitTestVisible = False
  42. PanBack.IsHitTestVisible = False
  43. PanBack.ScrollToHome()
  44. DisabledPageAnimControls.Remove(BtnStart)
  45. BtnStart.Show = True
  46. CardOptiFine.IsSwaped = True
  47. CardLiteLoader.IsSwaped = True
  48. CardForge.IsSwaped = True
  49. CardNeoForge.IsSwaped = True
  50. CardFabric.IsSwaped = True
  51. CardFabricApi.IsSwaped = True
  52. CardOptiFabric.IsSwaped = True
  53. If Not Setup.Get("HintInstallBack") Then
  54. Setup.Set("HintInstallBack", True)
  55. Hint("点击 Minecraft 项即可返回游戏主版本选择页面!")
  56. End If
  57. '如果在选择页面按了刷新键,选择页的东西可能会由于动画被隐藏,但不会由于加载结束而再次显示,因此这里需要手动恢复
  58. For Each Control In GetAllAnimControls(PanSelect)
  59. Control.Opacity = 1
  60. If Control.RenderTransform Is Nothing OrElse TypeOf Control.RenderTransform Is TranslateTransform Then
  61. Control.RenderTransform = New TranslateTransform
  62. End If
  63. Next
  64. '启动 Forge 加载
  65. If SelectedMinecraftId.StartsWith("1.") Then
  66. Dim ForgeLoader = New LoaderTask(Of String, List(Of DlForgeVersionEntry))("DlForgeVersion " & SelectedMinecraftId, AddressOf DlForgeVersionMain)
  67. LoadForge.State = ForgeLoader
  68. ForgeLoader.Start(SelectedMinecraftId)
  69. End If
  70. '启动 Fabric API、OptiFabric 加载
  71. DlFabricApiLoader.Start()
  72. DlOptiFabricLoader.Start()
  73. AniStart({
  74. AaOpacity(PanMinecraft, -PanMinecraft.Opacity, 90, 10),
  75. AaTranslateX(PanMinecraft, -50 - CType(PanMinecraft.RenderTransform, TranslateTransform).X, 100, 10),
  76. AaCode(
  77. Sub()
  78. PanBack.ScrollToHome()
  79. TextSelectName.Validate()
  80. OptiFine_Loaded()
  81. LiteLoader_Loaded()
  82. Forge_Loaded()
  83. NeoForge_Loaded()
  84. Fabric_Loaded()
  85. FabricApi_Loaded()
  86. OptiFabric_Loaded()
  87. SelectReload()
  88. End Sub, After:=True),
  89. AaOpacity(PanSelect, 1 - PanSelect.Opacity, 90, 100),
  90. AaTranslateX(PanSelect, -CType(PanSelect.RenderTransform, TranslateTransform).X, 200, 100, Ease:=New AniEaseOutFluent(AniEasePower.ExtraStrong)),
  91. AaCode(
  92. Sub()
  93. PanMinecraft.Visibility = Visibility.Collapsed
  94. PanBack.IsHitTestVisible = True
  95. '初始化 Binding
  96. If IsFirstLoaded Then Exit Sub
  97. IsFirstLoaded = True
  98. BtnOptiFineClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardOptiFine.MainTextBlock, .Mode = BindingMode.OneWay})
  99. BtnLiteLoaderClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardLiteLoader.MainTextBlock, .Mode = BindingMode.OneWay})
  100. BtnForgeClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardForge.MainTextBlock, .Mode = BindingMode.OneWay})
  101. BtnNeoForgeClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardNeoForge.MainTextBlock, .Mode = BindingMode.OneWay})
  102. BtnFabricClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardFabric.MainTextBlock, .Mode = BindingMode.OneWay})
  103. BtnFabricApiClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardFabricApi.MainTextBlock, .Mode = BindingMode.OneWay})
  104. BtnOptiFabricClearInner.SetBinding(Shapes.Path.FillProperty, New Binding("Foreground") With {.Source = CardOptiFabric.MainTextBlock, .Mode = BindingMode.OneWay})
  105. End Sub,, True)
  106. }, "FrmDownloadInstall SelectPageSwitch", True)
  107. End Sub
  108. Public Sub ExitSelectPage() Handles BtnBack.Click
  109. If Not IsInSelectPage Then Exit Sub
  110. IsInSelectPage = False
  111. PanInner.Margin = New Thickness(25, 10, 25, 25)
  112. DisabledPageAnimControls.Add(BtnStart)
  113. BtnStart.Show = False
  114. SelectClear() '清除已选择项
  115. PanMinecraft.Visibility = Visibility.Visible
  116. PanSelect.IsHitTestVisible = False
  117. PanMinecraft.IsHitTestVisible = True
  118. PanBack.IsHitTestVisible = False
  119. PanBack.ScrollToHome()
  120. AniStart({
  121. AaOpacity(PanSelect, -PanSelect.Opacity, 90, 10),
  122. AaTranslateX(PanSelect, 50 - CType(PanSelect.RenderTransform, TranslateTransform).X, 100, 10),
  123. AaCode(Sub() PanBack.ScrollToHome(), After:=True),
  124. AaOpacity(PanMinecraft, 1 - PanMinecraft.Opacity, 90, 100),
  125. AaTranslateX(PanMinecraft, -CType(PanMinecraft.RenderTransform, TranslateTransform).X, 200, 100, Ease:=New AniEaseOutFluent(AniEasePower.ExtraStrong)),
  126. AaCode(
  127. Sub()
  128. PanSelect.Visibility = Visibility.Collapsed
  129. PanBack.IsHitTestVisible = True
  130. End Sub,, True)
  131. }, "FrmDownloadInstall SelectPageSwitch")
  132. End Sub
  133. Public Sub MinecraftSelected(sender As MyListItem, e As MouseButtonEventArgs)
  134. SelectedMinecraftId = sender.Title
  135. SelectedMinecraftJsonUrl = sender.Tag("url").ToString
  136. SelectedMinecraftIcon = sender.Logo
  137. EnterSelectPage()
  138. End Sub
  139. #End Region
  140. #Region "选择"
  141. 'Minecraft
  142. Private SelectedMinecraftId As String
  143. Private SelectedMinecraftJsonUrl As String
  144. Private SelectedMinecraftIcon As String
  145. 'OptiFine
  146. Private SelectedOptiFine As DlOptiFineListEntry = Nothing
  147. Private Sub SetOptiFineInfoShow(IsShow As String)
  148. If PanOptiFineInfo.Tag = IsShow Then Exit Sub
  149. PanOptiFineInfo.Tag = IsShow
  150. If IsShow = "True" Then
  151. '显示信息栏
  152. AniStart({
  153. AaTranslateY(PanOptiFineInfo, -CType(PanOptiFineInfo.RenderTransform, TranslateTransform).Y, 270, 100, Ease:=New AniEaseOutBack),
  154. AaOpacity(PanOptiFineInfo, 1 - PanOptiFineInfo.Opacity, 100, 90)
  155. }, "SetOptiFineInfoShow")
  156. Else
  157. '隐藏信息栏
  158. AniStart({
  159. AaTranslateY(PanOptiFineInfo, 6 - CType(PanOptiFineInfo.RenderTransform, TranslateTransform).Y, 200),
  160. AaOpacity(PanOptiFineInfo, -PanOptiFineInfo.Opacity, 100)
  161. }, "SetOptiFineInfoShow")
  162. End If
  163. End Sub
  164. 'LiteLoader
  165. Private SelectedLiteLoader As DlLiteLoaderListEntry = Nothing
  166. Private Sub SetLiteLoaderInfoShow(IsShow As String)
  167. If PanLiteLoaderInfo.Tag = IsShow Then Exit Sub
  168. PanLiteLoaderInfo.Tag = IsShow
  169. If IsShow = "True" Then
  170. '显示信息栏
  171. AniStart({
  172. AaTranslateY(PanLiteLoaderInfo, -CType(PanLiteLoaderInfo.RenderTransform, TranslateTransform).Y, 270, 100, Ease:=New AniEaseOutBack),
  173. AaOpacity(PanLiteLoaderInfo, 1 - PanLiteLoaderInfo.Opacity, 100, 90)
  174. }, "SetLiteLoaderInfoShow")
  175. Else
  176. '隐藏信息栏
  177. AniStart({
  178. AaTranslateY(PanLiteLoaderInfo, 6 - CType(PanLiteLoaderInfo.RenderTransform, TranslateTransform).Y, 200),
  179. AaOpacity(PanLiteLoaderInfo, -PanLiteLoaderInfo.Opacity, 100)
  180. }, "SetLiteLoaderInfoShow")
  181. End If
  182. End Sub
  183. 'Forge
  184. Private SelectedForge As DlForgeVersionEntry = Nothing
  185. Private Sub SetForgeInfoShow(IsShow As String)
  186. If PanForgeInfo.Tag = IsShow Then Exit Sub
  187. PanForgeInfo.Tag = IsShow
  188. If IsShow = "True" Then
  189. '显示信息栏
  190. AniStart({
  191. AaTranslateY(PanForgeInfo, -CType(PanForgeInfo.RenderTransform, TranslateTransform).Y, 270, 100, Ease:=New AniEaseOutBack),
  192. AaOpacity(PanForgeInfo, 1 - PanForgeInfo.Opacity, 100, 90)
  193. }, "SetForgeInfoShow")
  194. Else
  195. '隐藏信息栏
  196. AniStart({
  197. AaTranslateY(PanForgeInfo, 6 - CType(PanForgeInfo.RenderTransform, TranslateTransform).Y, 200),
  198. AaOpacity(PanForgeInfo, -PanForgeInfo.Opacity, 100)
  199. }, "SetForgeInfoShow")
  200. End If
  201. End Sub
  202. 'NeoForge
  203. Private SelectedNeoForge As DlNeoForgeListEntry = Nothing
  204. Private Sub SetNeoForgeInfoShow(IsShow As String)
  205. If PanNeoForgeInfo.Tag = IsShow Then Exit Sub
  206. PanNeoForgeInfo.Tag = IsShow
  207. If IsShow = "True" Then
  208. '显示信息栏
  209. AniStart({
  210. AaTranslateY(PanNeoForgeInfo, -CType(PanNeoForgeInfo.RenderTransform, TranslateTransform).Y, 270, 100, Ease:=New AniEaseOutBack),
  211. AaOpacity(PanNeoForgeInfo, 1 - PanNeoForgeInfo.Opacity, 100, 90)
  212. }, "SetNeoForgeInfoShow")
  213. Else
  214. '隐藏信息栏
  215. AniStart({
  216. AaTranslateY(PanNeoForgeInfo, 6 - CType(PanNeoForgeInfo.RenderTransform, TranslateTransform).Y, 200),
  217. AaOpacity(PanNeoForgeInfo, -PanNeoForgeInfo.Opacity, 100)
  218. }, "SetNeoForgeInfoShow")
  219. End If
  220. End Sub
  221. 'Fabric
  222. Private SelectedFabric As String = Nothing
  223. Private Sub SetFabricInfoShow(IsShow As String)
  224. If PanFabricInfo.Tag = IsShow Then Exit Sub
  225. PanFabricInfo.Tag = IsShow
  226. If IsShow = "True" Then
  227. '显示信息栏
  228. AniStart({
  229. AaTranslateY(PanFabricInfo, -CType(PanFabricInfo.RenderTransform, TranslateTransform).Y, 270, 100, Ease:=New AniEaseOutBack),
  230. AaOpacity(PanFabricInfo, 1 - PanFabricInfo.Opacity, 100, 90)
  231. }, "SetFabricInfoShow")
  232. Else
  233. '隐藏信息栏
  234. AniStart({
  235. AaTranslateY(PanFabricInfo, 6 - CType(PanFabricInfo.RenderTransform, TranslateTransform).Y, 200),
  236. AaOpacity(PanFabricInfo, -PanFabricInfo.Opacity, 100)
  237. }, "SetFabricInfoShow")
  238. End If
  239. End Sub
  240. 'FabricApi
  241. Private SelectedFabricApi As CompFile = Nothing
  242. Private Sub SetFabricApiInfoShow(IsShow As String)
  243. If PanFabricApiInfo.Tag = IsShow Then Exit Sub
  244. PanFabricApiInfo.Tag = IsShow
  245. If IsShow = "True" Then
  246. '显示信息栏
  247. AniStart({
  248. AaTranslateY(PanFabricApiInfo, -CType(PanFabricApiInfo.RenderTransform, TranslateTransform).Y, 270, 100, Ease:=New AniEaseOutBack),
  249. AaOpacity(PanFabricApiInfo, 1 - PanFabricApiInfo.Opacity, 100, 90)
  250. }, "SetFabricApiInfoShow")
  251. Else
  252. '隐藏信息栏
  253. AniStart({
  254. AaTranslateY(PanFabricApiInfo, 6 - CType(PanFabricApiInfo.RenderTransform, TranslateTransform).Y, 200),
  255. AaOpacity(PanFabricApiInfo, -PanFabricApiInfo.Opacity, 100)
  256. }, "SetFabricApiInfoShow")
  257. End If
  258. End Sub
  259. 'OptiFabric
  260. Private SelectedOptiFabric As CompFile = Nothing
  261. Private Sub SetOptiFabricInfoShow(IsShow As String)
  262. If PanOptiFabricInfo.Tag = IsShow Then Exit Sub
  263. PanOptiFabricInfo.Tag = IsShow
  264. If IsShow = "True" Then
  265. '显示信息栏
  266. AniStart({
  267. AaTranslateY(PanOptiFabricInfo, -CType(PanOptiFabricInfo.RenderTransform, TranslateTransform).Y, 270, 100, Ease:=New AniEaseOutBack),
  268. AaOpacity(PanOptiFabricInfo, 1 - PanOptiFabricInfo.Opacity, 100, 90)
  269. }, "SetOptiFabricInfoShow")
  270. Else
  271. '隐藏信息栏
  272. AniStart({
  273. AaTranslateY(PanOptiFabricInfo, 6 - CType(PanOptiFabricInfo.RenderTransform, TranslateTransform).Y, 200),
  274. AaOpacity(PanOptiFabricInfo, -PanOptiFabricInfo.Opacity, 100)
  275. }, "SetOptiFabricInfoShow")
  276. End If
  277. End Sub
  278. Private IsReloading As Boolean = False '#3742 中,LoadOptiFineGetError 会初始化 LoadOptiFine,触发事件 LoadOptiFine.StateChanged,导致再次调用 SelectReload
  279. ''' <summary>
  280. ''' 重载已选择的项目的显示。
  281. ''' </summary>
  282. Private Sub SelectReload() Handles CardOptiFine.Swap, LoadOptiFine.StateChanged, CardForge.Swap, LoadForge.StateChanged, CardNeoForge.Swap, LoadNeoForge.StateChanged, CardFabric.Swap, LoadFabric.StateChanged, CardFabricApi.Swap, LoadFabricApi.StateChanged, CardOptiFabric.Swap, LoadOptiFabric.StateChanged, CardLiteLoader.Swap, LoadLiteLoader.StateChanged
  283. If SelectedMinecraftId Is Nothing OrElse IsReloading Then Exit Sub
  284. IsReloading = True
  285. '主预览
  286. SelectNameUpdate()
  287. ImgLogo.Source = GetSelectLogo()
  288. 'OptiFine
  289. Dim OptiFineError As String = LoadOptiFineGetError()
  290. CardOptiFine.MainSwap.Visibility = If(OptiFineError Is Nothing, Visibility.Visible, Visibility.Collapsed)
  291. If OptiFineError IsNot Nothing Then CardOptiFine.IsSwaped = True '例如在同时展开卡片时选择了不兼容项则强制折叠
  292. SetOptiFineInfoShow(CardOptiFine.IsSwaped)
  293. If SelectedOptiFine Is Nothing Then
  294. BtnOptiFineClear.Visibility = Visibility.Collapsed
  295. ImgOptiFine.Visibility = Visibility.Collapsed
  296. LabOptiFine.Text = If(OptiFineError, "可以添加")
  297. LabOptiFine.Foreground = ColorGray4
  298. Else
  299. BtnOptiFineClear.Visibility = Visibility.Visible
  300. ImgOptiFine.Visibility = Visibility.Visible
  301. LabOptiFine.Text = SelectedOptiFine.NameDisplay.Replace(SelectedMinecraftId & " ", "")
  302. LabOptiFine.Foreground = ColorGray1
  303. End If
  304. 'LiteLoader
  305. If Not SelectedMinecraftId.Contains("1.") OrElse Val(SelectedMinecraftId.Split(".")(1)) > 12 Then
  306. CardLiteLoader.Visibility = Visibility.Collapsed
  307. Else
  308. CardLiteLoader.Visibility = Visibility.Visible
  309. Dim LiteLoaderError As String = LoadLiteLoaderGetError()
  310. CardLiteLoader.MainSwap.Visibility = If(LiteLoaderError Is Nothing, Visibility.Visible, Visibility.Collapsed)
  311. If LiteLoaderError IsNot Nothing Then CardLiteLoader.IsSwaped = True '例如在同时展开卡片时选择了不兼容项则强制折叠
  312. SetLiteLoaderInfoShow(CardLiteLoader.IsSwaped)
  313. If SelectedLiteLoader Is Nothing Then
  314. BtnLiteLoaderClear.Visibility = Visibility.Collapsed
  315. ImgLiteLoader.Visibility = Visibility.Collapsed
  316. LabLiteLoader.Text = If(LiteLoaderError, "可以添加")
  317. LabLiteLoader.Foreground = ColorGray4
  318. Else
  319. BtnLiteLoaderClear.Visibility = Visibility.Visible
  320. ImgLiteLoader.Visibility = Visibility.Visible
  321. LabLiteLoader.Text = SelectedLiteLoader.Inherit
  322. LabLiteLoader.Foreground = ColorGray1
  323. End If
  324. End If
  325. 'Forge
  326. Dim ForgeError As String = LoadForgeGetError()
  327. CardForge.MainSwap.Visibility = If(ForgeError Is Nothing, Visibility.Visible, Visibility.Collapsed)
  328. If ForgeError IsNot Nothing Then CardForge.IsSwaped = True
  329. SetForgeInfoShow(CardForge.IsSwaped)
  330. If SelectedForge Is Nothing Then
  331. BtnForgeClear.Visibility = Visibility.Collapsed
  332. ImgForge.Visibility = Visibility.Collapsed
  333. LabForge.Text = If(ForgeError, "可以添加")
  334. LabForge.Foreground = ColorGray4
  335. Else
  336. BtnForgeClear.Visibility = Visibility.Visible
  337. ImgForge.Visibility = Visibility.Visible
  338. LabForge.Text = SelectedForge.VersionName
  339. LabForge.Foreground = ColorGray1
  340. End If
  341. 'NeoForge
  342. If Not SelectedMinecraftId.Contains("1.") OrElse Val(SelectedMinecraftId.Split(".")(1)) <= 19 Then
  343. CardNeoForge.Visibility = Visibility.Collapsed
  344. Else
  345. CardNeoForge.Visibility = Visibility.Visible
  346. Dim NeoForgeError As String = LoadNeoForgeGetError()
  347. CardNeoForge.MainSwap.Visibility = If(NeoForgeError Is Nothing, Visibility.Visible, Visibility.Collapsed)
  348. If NeoForgeError IsNot Nothing Then CardNeoForge.IsSwaped = True
  349. SetNeoForgeInfoShow(CardNeoForge.IsSwaped)
  350. If SelectedNeoForge Is Nothing Then
  351. BtnNeoForgeClear.Visibility = Visibility.Collapsed
  352. ImgNeoForge.Visibility = Visibility.Collapsed
  353. LabNeoForge.Text = If(NeoForgeError, "可以添加")
  354. LabNeoForge.Foreground = ColorGray4
  355. Else
  356. BtnNeoForgeClear.Visibility = Visibility.Visible
  357. ImgNeoForge.Visibility = Visibility.Visible
  358. LabNeoForge.Text = SelectedNeoForge.VersionName
  359. LabNeoForge.Foreground = ColorGray1
  360. End If
  361. End If
  362. 'Fabric
  363. If SelectedMinecraftId.Contains("1.") AndAlso Val(SelectedMinecraftId.Split(".")(1)) <= 13 Then
  364. CardFabric.Visibility = Visibility.Collapsed
  365. Else
  366. CardFabric.Visibility = Visibility.Visible
  367. Dim FabricError As String = LoadFabricGetError()
  368. CardFabric.MainSwap.Visibility = If(FabricError Is Nothing, Visibility.Visible, Visibility.Collapsed)
  369. If FabricError IsNot Nothing Then CardFabric.IsSwaped = True
  370. SetFabricInfoShow(CardFabric.IsSwaped)
  371. If SelectedFabric Is Nothing Then
  372. BtnFabricClear.Visibility = Visibility.Collapsed
  373. ImgFabric.Visibility = Visibility.Collapsed
  374. LabFabric.Text = If(FabricError, "可以添加")
  375. LabFabric.Foreground = ColorGray4
  376. Else
  377. BtnFabricClear.Visibility = Visibility.Visible
  378. ImgFabric.Visibility = Visibility.Visible
  379. LabFabric.Text = SelectedFabric.Replace("+build", "")
  380. LabFabric.Foreground = ColorGray1
  381. End If
  382. End If
  383. 'FabricApi
  384. If SelectedFabric Is Nothing Then
  385. CardFabricApi.Visibility = Visibility.Collapsed
  386. Else
  387. CardFabricApi.Visibility = Visibility.Visible
  388. Dim FabricApiError As String = LoadFabricApiGetError()
  389. CardFabricApi.MainSwap.Visibility = If(FabricApiError Is Nothing, Visibility.Visible, Visibility.Collapsed)
  390. If FabricApiError IsNot Nothing OrElse SelectedFabric Is Nothing Then CardFabricApi.IsSwaped = True
  391. SetFabricApiInfoShow(CardFabricApi.IsSwaped)
  392. If SelectedFabricApi Is Nothing Then
  393. BtnFabricApiClear.Visibility = Visibility.Collapsed
  394. ImgFabricApi.Visibility = Visibility.Collapsed
  395. LabFabricApi.Text = If(FabricApiError, "可以添加")
  396. LabFabricApi.Foreground = ColorGray4
  397. Else
  398. BtnFabricApiClear.Visibility = Visibility.Visible
  399. ImgFabricApi.Visibility = Visibility.Visible
  400. LabFabricApi.Text = SelectedFabricApi.DisplayName.Split("]")(1).Replace("Fabric API ", "").Replace(" build ", ".").Split("+").First.Trim
  401. LabFabricApi.Foreground = ColorGray1
  402. End If
  403. End If
  404. 'OptiFabric
  405. If SelectedFabric Is Nothing OrElse SelectedOptiFine Is Nothing Then
  406. CardOptiFabric.Visibility = Visibility.Collapsed
  407. Else
  408. CardOptiFabric.Visibility = Visibility.Visible
  409. Dim OptiFabricError As String = LoadOptiFabricGetError()
  410. CardOptiFabric.MainSwap.Visibility = If(OptiFabricError Is Nothing, Visibility.Visible, Visibility.Collapsed)
  411. If OptiFabricError IsNot Nothing OrElse SelectedFabric Is Nothing Then CardOptiFabric.IsSwaped = True
  412. SetOptiFabricInfoShow(CardOptiFabric.IsSwaped)
  413. If SelectedOptiFabric Is Nothing Then
  414. BtnOptiFabricClear.Visibility = Visibility.Collapsed
  415. ImgOptiFabric.Visibility = Visibility.Collapsed
  416. LabOptiFabric.Text = If(OptiFabricError, "可以添加")
  417. LabOptiFabric.Foreground = ColorGray4
  418. Else
  419. BtnOptiFabricClear.Visibility = Visibility.Visible
  420. ImgOptiFabric.Visibility = Visibility.Visible
  421. LabOptiFabric.Text = SelectedOptiFabric.DisplayName.ToLower.Replace("optifabric-", "").Replace(".jar", "").Trim.TrimStart("v")
  422. LabOptiFabric.Foreground = ColorGray1
  423. End If
  424. End If
  425. '主警告
  426. If SelectedFabric IsNot Nothing AndAlso SelectedFabricApi Is Nothing Then
  427. HintFabricAPI.Visibility = Visibility.Visible
  428. Else
  429. HintFabricAPI.Visibility = Visibility.Collapsed
  430. End If
  431. If SelectedFabric IsNot Nothing AndAlso SelectedOptiFine IsNot Nothing AndAlso SelectedOptiFabric Is Nothing Then
  432. If SelectedMinecraftId.StartsWith("1.14") OrElse SelectedMinecraftId.StartsWith("1.15") Then
  433. HintOptiFabric.Visibility = Visibility.Collapsed
  434. HintOptiFabricOld.Visibility = Visibility.Visible
  435. Else
  436. HintOptiFabric.Visibility = Visibility.Visible
  437. HintOptiFabricOld.Visibility = Visibility.Collapsed
  438. End If
  439. Else
  440. HintOptiFabric.Visibility = Visibility.Collapsed
  441. HintOptiFabricOld.Visibility = Visibility.Collapsed
  442. End If
  443. If SelectedMinecraftId.Contains("1.") AndAlso Val(SelectedMinecraftId.Split(".")(1)) >= 16 AndAlso SelectedOptiFine IsNot Nothing AndAlso
  444. (SelectedForge IsNot Nothing OrElse SelectedFabric IsNot Nothing) Then
  445. HintModOptiFine.Visibility = Visibility.Visible
  446. Else
  447. HintModOptiFine.Visibility = Visibility.Collapsed
  448. End If
  449. '结束
  450. IsReloading = False
  451. End Sub
  452. ''' <summary>
  453. ''' 清空已选择的项目。
  454. ''' </summary>
  455. Private Sub SelectClear()
  456. SelectedMinecraftId = Nothing
  457. SelectedMinecraftJsonUrl = Nothing
  458. SelectedMinecraftIcon = Nothing
  459. SelectedOptiFine = Nothing
  460. SelectedLiteLoader = Nothing
  461. SelectedForge = Nothing
  462. SelectedNeoForge = Nothing
  463. SelectedFabric = Nothing
  464. SelectedFabricApi = Nothing
  465. SelectedOptiFabric = Nothing
  466. End Sub
  467. ''' <summary>
  468. ''' 获取版本图标。
  469. ''' </summary>
  470. Private Function GetSelectLogo() As String
  471. If SelectedFabric IsNot Nothing Then
  472. Return "pack://application:,,,/images/Blocks/Fabric.png"
  473. ElseIf SelectedForge IsNot Nothing Then
  474. Return "pack://application:,,,/images/Blocks/Anvil.png"
  475. ElseIf SelectedNeoForge IsNot Nothing Then
  476. Return "pack://application:,,,/images/Blocks/NeoForge.png"
  477. ElseIf SelectedLiteLoader IsNot Nothing Then
  478. Return "pack://application:,,,/images/Blocks/Egg.png"
  479. ElseIf SelectedOptiFine IsNot Nothing Then
  480. Return "pack://application:,,,/images/Blocks/GrassPath.png"
  481. Else
  482. Return SelectedMinecraftIcon
  483. End If
  484. End Function
  485. '版本名处理
  486. ''' <summary>
  487. ''' 获取默认版本名。
  488. ''' </summary>
  489. Private Function GetSelectName() As String
  490. Dim Name As String = SelectedMinecraftId
  491. If SelectedFabric IsNot Nothing Then
  492. Name += "-Fabric " & SelectedFabric.Replace("+build", "")
  493. End If
  494. If SelectedForge IsNot Nothing Then
  495. Name += "-Forge_" & SelectedForge.VersionName
  496. End If
  497. If SelectedNeoForge IsNot Nothing Then
  498. Name += "-NeoForge_" & SelectedNeoForge.VersionName
  499. End If
  500. If SelectedLiteLoader IsNot Nothing Then
  501. Name += "-LiteLoader"
  502. End If
  503. If SelectedOptiFine IsNot Nothing Then
  504. Name += "-OptiFine_" & SelectedOptiFine.NameDisplay.Replace(SelectedMinecraftId & " ", "").Replace(" ", "_")
  505. End If
  506. Return Name
  507. End Function
  508. Private IsSelectNameEdited As Boolean = False
  509. Private IsSelectNameChanging As Boolean = False
  510. Private Sub SelectNameUpdate()
  511. If IsSelectNameEdited OrElse IsSelectNameChanging Then Exit Sub
  512. IsSelectNameChanging = True
  513. TextSelectName.Text = GetSelectName()
  514. IsSelectNameChanging = False
  515. End Sub
  516. Private Sub TextSelectName_TextChanged(sender As Object, e As TextChangedEventArgs) Handles TextSelectName.TextChanged
  517. If IsSelectNameChanging Then Exit Sub
  518. IsSelectNameEdited = True
  519. SelectReload()
  520. End Sub
  521. Private Sub TextSelectName_ValidateChanged(sender As Object, e As EventArgs) Handles TextSelectName.ValidateChanged
  522. BtnStart.IsEnabled = TextSelectName.IsValidated
  523. End Sub
  524. #End Region
  525. #Region "加载器"
  526. '结果数据化
  527. Private Sub LoadMinecraft_OnFinish()
  528. ExitSelectPage() '返回
  529. Try
  530. Dim Dict As New Dictionary(Of String, List(Of JObject)) From {
  531. {"正式版", New List(Of JObject)}, {"预览版", New List(Of JObject)}, {"远古版", New List(Of JObject)}, {"愚人节版", New List(Of JObject)}
  532. }
  533. Dim Versions As JArray = DlClientListLoader.Output.Value("versions")
  534. For Each Version As JObject In Versions
  535. '确定分类
  536. Dim Type As String = Version("type")
  537. Select Case Type
  538. Case "release"
  539. Type = "正式版"
  540. Case "snapshot"
  541. Type = "预览版"
  542. 'Mojang 误分类
  543. If Version("id").ToString.StartsWith("1.") AndAlso
  544. Not Version("id").ToString.ToLower.Contains("combat") AndAlso
  545. Not Version("id").ToString.ToLower.Contains("rc") AndAlso
  546. Not Version("id").ToString.ToLower.Contains("experimental") AndAlso
  547. Not Version("id").ToString.ToLower.Contains("pre") Then
  548. Type = "正式版"
  549. Version("type") = "release"
  550. End If
  551. '愚人节版本
  552. Select Case Version("id").ToString.ToLower
  553. Case "20w14infinite", "20w14∞"
  554. Type = "愚人节版"
  555. Version("id") = "20w14∞"
  556. Version("type") = "special"
  557. Version.Add("lore", GetMcFoolName(Version("id")))
  558. Case "3d shareware v1.34", "1.rv-pre1", "15w14a", "2.0", "22w13oneblockatatime", "23w13a_or_b", "24w14potato"
  559. Type = "愚人节版"
  560. Version("type") = "special"
  561. Version.Add("lore", GetMcFoolName(Version("id")))
  562. Case Else '4/1 自动视作愚人节版
  563. Dim ReleaseDate = Version("releaseTime").Value(Of Date).ToUniversalTime().AddHours(2)
  564. If ReleaseDate.Month = 4 AndAlso ReleaseDate.Day = 1 Then
  565. Type = "愚人节版"
  566. Version("type") = "special"
  567. End If
  568. End Select
  569. Case "special"
  570. '已被处理的愚人节版
  571. Type = "愚人节版"
  572. Case Else
  573. Type = "远古版"
  574. End Select
  575. '加入辞典
  576. Dict(Type).Add(Version)
  577. Next
  578. '排序
  579. For Each Pair In Dict.ToList
  580. Dict(Pair.Key) = Pair.Value.OrderByDescending(Function(j) j("releaseTime").Value(Of Date)).ToList
  581. Next
  582. '清空当前
  583. PanMinecraft.Children.Clear()
  584. '添加最新版本
  585. Dim CardInfo As New MyCard With {.Title = "最新版本", .Margin = New Thickness(0, 15, 0, 15), .SwapType = 2}
  586. Dim TopestVersions As New List(Of JObject)
  587. Dim Release As JObject = Dict("正式版")(0).DeepClone()
  588. Release("lore") = "最新正式版,发布于 " & Release("releaseTime").Value(Of Date).ToString("yyyy'/'MM'/'dd HH':'mm")
  589. TopestVersions.Add(Release)
  590. If Dict("正式版")(0)("releaseTime").Value(Of Date) < Dict("预览版")(0)("releaseTime").Value(Of Date) Then
  591. Dim Snapshot As JObject = Dict("预览版")(0).DeepClone()
  592. Snapshot("lore") = "最新预览版,发布于 " & Snapshot("releaseTime").Value(Of Date).ToString("yyyy'/'MM'/'dd HH':'mm")
  593. TopestVersions.Add(Snapshot)
  594. End If
  595. Dim PanInfo As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = TopestVersions}
  596. MyCard.StackInstall(PanInfo, 7)
  597. CardInfo.Children.Add(PanInfo)
  598. PanMinecraft.Children.Insert(0, CardInfo)
  599. '添加其他版本
  600. For Each Pair As KeyValuePair(Of String, List(Of JObject)) In Dict
  601. If Not Pair.Value.Any() Then Continue For
  602. '增加卡片
  603. Dim NewCard As New MyCard With {.Title = Pair.Key & " (" & Pair.Value.Count & ")", .Margin = New Thickness(0, 0, 0, 15), .SwapType = 7}
  604. Dim NewStack As New StackPanel With {.Margin = New Thickness(20, MyCard.SwapedHeight, 18, 0), .VerticalAlignment = VerticalAlignment.Top, .RenderTransform = New TranslateTransform(0, 0), .Tag = Pair.Value}
  605. NewCard.Children.Add(NewStack)
  606. NewCard.SwapControl = NewStack
  607. NewCard.IsSwaped = True
  608. PanMinecraft.Children.Add(NewCard)
  609. Next
  610. '自动选择版本
  611. If McVersionWaitingForSelect Is Nothing Then Exit Try
  612. Log("[Download] 自动选择 MC 版本:" & McVersionWaitingForSelect)
  613. For Each Version As JObject In Versions
  614. If Version("id").ToString <> McVersionWaitingForSelect Then Continue For
  615. Dim Item = McDownloadListItem(Version, Sub()
  616. End Sub, False)
  617. MinecraftSelected(Item, Nothing)
  618. Next
  619. Catch ex As Exception
  620. Log(ex, "可视化安装版本列表出错", LogLevel.Feedback)
  621. End Try
  622. End Sub
  623. ''' <summary>
  624. ''' 当 MC 版本列表加载完时,立即自动选择的版本。用于外部调用。
  625. ''' </summary>
  626. Public Shared McVersionWaitingForSelect As String = Nothing
  627. #End Region
  628. #Region "OptiFine 列表"
  629. ''' <summary>
  630. ''' 获取 OptiFine 的加载异常信息。若正常则返回 Nothing。
  631. ''' </summary>
  632. Private Function LoadOptiFineGetError() As String
  633. If SelectedNeoForge IsNot Nothing Then Return "与 NeoForge 不兼容"
  634. If LoadOptiFine Is Nothing OrElse LoadOptiFine.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "加载中……"
  635. If LoadOptiFine.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadOptiFine.State, Object).Error.Message
  636. '检查 Forge 1.13 - 1.14.3:全部不兼容
  637. If SelectedForge IsNot Nothing AndAlso
  638. VersionSortInteger(SelectedMinecraftId, "1.13") >= 0 AndAlso VersionSortInteger("1.14.3", SelectedMinecraftId) >= 0 Then
  639. Return "与 Forge 不兼容"
  640. End If
  641. '检查 Forge 版本
  642. Dim HasAny As Boolean = False
  643. Dim HasRequiredVersion As Boolean = False
  644. For Each OptiFineVersion As DlOptiFineListEntry In DlOptiFineListLoader.Output.Value
  645. If Not OptiFineVersion.NameDisplay.StartsWith(SelectedMinecraftId & " ") Then Continue For '不是同一个大版本
  646. HasAny = True
  647. If SelectedForge Is Nothing Then Return Nothing '未选择 Forge
  648. If IsOptiFineSuitForForge(OptiFineVersion, SelectedForge) Then Return Nothing '该版本可用
  649. If OptiFineVersion.RequiredForgeVersion IsNot Nothing Then HasRequiredVersion = True
  650. Next
  651. If Not HasAny Then
  652. Return "不可用"
  653. ElseIf HasRequiredVersion Then
  654. Return "仅兼容特定版本的 Forge"
  655. Else
  656. Return "与 Forge 不兼容"
  657. End If
  658. End Function
  659. '检查某个 OptiFine 是否与某个 Forge 兼容
  660. Private Function IsOptiFineSuitForForge(OptiFine As DlOptiFineListEntry, Forge As DlForgeVersionEntry)
  661. If Forge.Inherit <> OptiFine.Inherit Then Return False '不是同一个大版本
  662. If OptiFine.RequiredForgeVersion Is Nothing Then Return False '不兼容 Forge
  663. If String.IsNullOrWhiteSpace(OptiFine.RequiredForgeVersion) Then Return True '#4183
  664. If OptiFine.RequiredForgeVersion.Contains(".") Then 'XX.X.XXX
  665. Return VersionSortInteger(Forge.Version.ToString, OptiFine.RequiredForgeVersion) = 0
  666. Else 'XXXX
  667. Return Forge.Version.Revision = OptiFine.RequiredForgeVersion
  668. End If
  669. End Function
  670. '限制展开
  671. Private Sub CardOptiFine_PreviewSwap(sender As Object, e As RouteEventArgs) Handles CardOptiFine.PreviewSwap
  672. If LoadOptiFineGetError() IsNot Nothing Then e.Handled = True
  673. End Sub
  674. ''' <summary>
  675. ''' 尝试重新可视化 OptiFine 版本列表。
  676. ''' </summary>
  677. Private Sub OptiFine_Loaded() Handles LoadOptiFine.StateChanged
  678. Try
  679. If DlOptiFineListLoader.State <> LoadState.Finished Then Exit Sub
  680. '获取版本列表
  681. Dim Versions As New List(Of DlOptiFineListEntry)
  682. For Each Version As DlOptiFineListEntry In DlOptiFineListLoader.Output.Value
  683. If SelectedForge IsNot Nothing AndAlso Not IsOptiFineSuitForForge(Version, SelectedForge) Then Continue For
  684. If Version.NameDisplay.StartsWith(SelectedMinecraftId & " ") Then Versions.Add(Version)
  685. Next
  686. If Not Versions.Any() Then Exit Sub
  687. '排序
  688. Versions = Versions.Sort(
  689. Function(Left As DlOptiFineListEntry, Right As DlOptiFineListEntry) As Boolean
  690. If Not Left.IsPreview AndAlso Right.IsPreview Then Return True
  691. If Left.IsPreview AndAlso Not Right.IsPreview Then Return False
  692. Return VersionSortBoolean(Left.NameDisplay, Right.NameDisplay)
  693. End Function)
  694. '可视化
  695. PanOptiFine.Children.Clear()
  696. For Each Version In Versions
  697. PanOptiFine.Children.Add(OptiFineDownloadListItem(Version, AddressOf OptiFine_Selected, False))
  698. Next
  699. Catch ex As Exception
  700. Log(ex, "可视化 OptiFine 安装版本列表出错", LogLevel.Feedback)
  701. End Try
  702. End Sub
  703. '选择与清除
  704. Private Sub OptiFine_Selected(sender As MyListItem, e As EventArgs)
  705. SelectedOptiFine = sender.Tag
  706. If SelectedForge IsNot Nothing AndAlso Not IsOptiFineSuitForForge(SelectedOptiFine, SelectedForge) Then SelectedForge = Nothing
  707. OptiFabric_Loaded()
  708. Forge_Loaded()
  709. NeoForge_Loaded()
  710. CardOptiFine.IsSwaped = True
  711. SelectReload()
  712. End Sub
  713. Private Sub OptiFine_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnOptiFineClear.MouseLeftButtonUp
  714. SelectedOptiFine = Nothing
  715. SelectedOptiFabric = Nothing
  716. CardOptiFine.IsSwaped = True
  717. e.Handled = True
  718. Forge_Loaded()
  719. NeoForge_Loaded()
  720. SelectReload()
  721. End Sub
  722. #End Region
  723. #Region "LiteLoader 列表"
  724. ''' <summary>
  725. ''' 获取 LiteLoader 的加载异常信息。若正常则返回 Nothing。
  726. ''' </summary>
  727. Private Function LoadLiteLoaderGetError() As String
  728. If Not SelectedMinecraftId.Contains("1.") OrElse Val(SelectedMinecraftId.Split(".")(1)) > 12 Then Return "不可用"
  729. If LoadLiteLoader Is Nothing OrElse LoadLiteLoader.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "加载中……"
  730. If LoadLiteLoader.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadLiteLoader.State, Object).Error.Message
  731. For Each Version As DlLiteLoaderListEntry In DlLiteLoaderListLoader.Output.Value
  732. If Version.Inherit = SelectedMinecraftId Then Return Nothing
  733. Next
  734. Return "不可用"
  735. End Function
  736. '限制展开
  737. Private Sub CardLiteLoader_PreviewSwap(sender As Object, e As RouteEventArgs) Handles CardLiteLoader.PreviewSwap
  738. If LoadLiteLoaderGetError() IsNot Nothing Then e.Handled = True
  739. End Sub
  740. ''' <summary>
  741. ''' 尝试重新可视化 LiteLoader 版本列表。
  742. ''' </summary>
  743. Private Sub LiteLoader_Loaded() Handles LoadLiteLoader.StateChanged
  744. Try
  745. If DlLiteLoaderListLoader.State <> LoadState.Finished Then Exit Sub
  746. '获取版本列表
  747. Dim Versions As New List(Of DlLiteLoaderListEntry)
  748. For Each Version As DlLiteLoaderListEntry In DlLiteLoaderListLoader.Output.Value
  749. If Version.Inherit = SelectedMinecraftId Then Versions.Add(Version)
  750. Next
  751. If Not Versions.Any() Then Exit Sub
  752. '可视化
  753. PanLiteLoader.Children.Clear()
  754. For Each Version In Versions
  755. PanLiteLoader.Children.Add(LiteLoaderDownloadListItem(Version, AddressOf LiteLoader_Selected, False))
  756. Next
  757. Catch ex As Exception
  758. Log(ex, "可视化 LiteLoader 安装版本列表出错", LogLevel.Feedback)
  759. End Try
  760. End Sub
  761. '选择与清除
  762. Private Sub LiteLoader_Selected(sender As MyListItem, e As EventArgs)
  763. SelectedLiteLoader = sender.Tag
  764. CardLiteLoader.IsSwaped = True
  765. SelectReload()
  766. End Sub
  767. Private Sub LiteLoader_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnLiteLoaderClear.MouseLeftButtonUp
  768. SelectedLiteLoader = Nothing
  769. CardLiteLoader.IsSwaped = True
  770. e.Handled = True
  771. SelectReload()
  772. End Sub
  773. #End Region
  774. #Region "Forge 列表"
  775. ''' <summary>
  776. ''' 获取 Forge 的加载异常信息。若正常则返回 Nothing。
  777. ''' </summary>
  778. Private Function LoadForgeGetError() As String
  779. If Not SelectedMinecraftId.StartsWith("1.") Then Return "不可用"
  780. If Not LoadForge.State.IsLoader Then Return "加载中……"
  781. Dim Loader As LoaderTask(Of String, List(Of DlForgeVersionEntry)) = LoadForge.State
  782. If SelectedMinecraftId <> Loader.Input Then Return "加载中……"
  783. If Loader.State = LoadState.Loading Then Return "加载中……"
  784. If Loader.State = LoadState.Failed Then
  785. Dim ErrorMessage As String = Loader.Error.Message
  786. If ErrorMessage.Contains("不可用") Then
  787. Return "不可用"
  788. Else
  789. Return "获取版本列表失败:" & ErrorMessage
  790. End If
  791. End If
  792. If Loader.State <> LoadState.Finished Then Return "获取版本列表失败:未知错误,状态为 " & GetStringFromEnum(Loader.State)
  793. Dim NotSuitForOptiFine As Boolean = False
  794. For Each Version In Loader.Output
  795. If Version.Category = "universal" OrElse Version.Category = "client" Then Continue For '跳过无法自动安装的版本
  796. If SelectedNeoForge IsNot Nothing Then Return "与 NeoForge 不兼容"
  797. If SelectedFabric IsNot Nothing Then Return "与 Fabric 不兼容"
  798. If SelectedOptiFine IsNot Nothing AndAlso
  799. VersionSortInteger(SelectedMinecraftId, "1.13") >= 0 AndAlso VersionSortInteger("1.14.3", SelectedMinecraftId) >= 0 Then
  800. Return "与 OptiFine 不兼容" '1.13 ~ 1.14.3 OptiFine 检查
  801. End If
  802. If SelectedOptiFine IsNot Nothing AndAlso Not IsOptiFineSuitForForge(SelectedOptiFine, Version) Then
  803. NotSuitForOptiFine = True '与 OptiFine 不兼容
  804. Continue For
  805. End If
  806. Return Nothing
  807. Next
  808. Return If(NotSuitForOptiFine, "与 OptiFine 不兼容", "该版本不支持自动安装")
  809. End Function
  810. '限制展开
  811. Private Sub CardForge_PreviewSwap(sender As Object, e As RouteEventArgs) Handles CardForge.PreviewSwap
  812. If LoadForgeGetError() IsNot Nothing Then e.Handled = True
  813. End Sub
  814. ''' <summary>
  815. ''' 尝试重新可视化 Forge 版本列表。
  816. ''' </summary>
  817. Private Sub Forge_Loaded() Handles LoadForge.StateChanged
  818. Try
  819. If Not LoadForge.State.IsLoader Then Exit Sub
  820. Dim Loader As LoaderTask(Of String, List(Of DlForgeVersionEntry)) = LoadForge.State
  821. If SelectedMinecraftId <> Loader.Input Then Exit Sub
  822. If Loader.State <> LoadState.Finished Then Exit Sub
  823. '获取要显示的版本
  824. Dim Versions = Loader.Output.ToList '复制数组,以免 Output 在实例化后变空
  825. If Not Loader.Output.Any() Then Exit Sub
  826. PanForge.Children.Clear()
  827. Versions = Versions.Where(
  828. Function(v)
  829. If v.Category = "universal" OrElse v.Category = "client" Then Return False '跳过无法自动安装的版本
  830. If SelectedOptiFine IsNot Nothing AndAlso Not IsOptiFineSuitForForge(SelectedOptiFine, v) Then Return False
  831. Return True
  832. End Function).OrderByDescending(Function(v) v.Version).ToList()
  833. ForgeDownloadListItemPreload(PanForge, Versions, AddressOf Forge_Selected, False)
  834. For Each Version In Versions
  835. PanForge.Children.Add(ForgeDownloadListItem(Version, AddressOf Forge_Selected, False))
  836. Next
  837. Catch ex As Exception
  838. Log(ex, "可视化 Forge 安装版本列表出错", LogLevel.Feedback)
  839. End Try
  840. End Sub
  841. '选择与清除
  842. Private Sub Forge_Selected(sender As MyListItem, e As EventArgs)
  843. SelectedForge = sender.Tag
  844. CardForge.IsSwaped = True
  845. If SelectedOptiFine IsNot Nothing AndAlso Not IsOptiFineSuitForForge(SelectedOptiFine, SelectedForge) Then SelectedOptiFine = Nothing
  846. OptiFine_Loaded()
  847. SelectReload()
  848. End Sub
  849. Private Sub Forge_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnForgeClear.MouseLeftButtonUp
  850. SelectedForge = Nothing
  851. CardForge.IsSwaped = True
  852. e.Handled = True
  853. OptiFine_Loaded()
  854. SelectReload()
  855. End Sub
  856. #End Region
  857. #Region "NeoForge 列表"
  858. ''' <summary>
  859. ''' 获取 NeoForge 的加载异常信息。若正常则返回 Nothing。
  860. ''' </summary>
  861. Private Function LoadNeoForgeGetError() As String
  862. If Not SelectedMinecraftId.StartsWith("1.") Then Return "不可用"
  863. If SelectedOptiFine IsNot Nothing Then Return "与 OptiFine 不兼容"
  864. If SelectedForge IsNot Nothing Then Return "与 Forge 不兼容"
  865. If SelectedFabric IsNot Nothing Then Return "与 Fabric 不兼容"
  866. If LoadNeoForge Is Nothing OrElse LoadNeoForge.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "加载中……"
  867. If LoadNeoForge.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadNeoForge.State, Object).Error.Message
  868. If DlNeoForgeListLoader.Output.Value.Any(Function(v) v.Inherit = SelectedMinecraftId) Then
  869. Return Nothing
  870. Else
  871. Return "不可用"
  872. End If
  873. End Function
  874. '限制展开
  875. Private Sub CardNeoForge_PreviewSwap(sender As Object, e As RouteEventArgs) Handles CardNeoForge.PreviewSwap
  876. If LoadNeoForgeGetError() IsNot Nothing Then e.Handled = True
  877. End Sub
  878. ''' <summary>
  879. ''' 尝试重新可视化 NeoForge 版本列表。
  880. ''' </summary>
  881. Private Sub NeoForge_Loaded() Handles LoadNeoForge.StateChanged
  882. Try
  883. '获取版本列表
  884. If DlNeoForgeListLoader.State <> LoadState.Finished Then Exit Sub
  885. Dim Versions = DlNeoForgeListLoader.Output.Value.Where(Function(v) v.Inherit = SelectedMinecraftId).ToList
  886. If Not Versions.Any() Then Exit Sub
  887. '可视化
  888. PanNeoForge.Children.Clear()
  889. NeoForgeDownloadListItemPreload(PanNeoForge, Versions, AddressOf NeoForge_Selected, False)
  890. For Each Version In Versions
  891. PanNeoForge.Children.Add(NeoForgeDownloadListItem(Version, AddressOf NeoForge_Selected, False))
  892. Next
  893. Catch ex As Exception
  894. Log(ex, "可视化 NeoForge 安装版本列表出错", LogLevel.Feedback)
  895. End Try
  896. End Sub
  897. '选择与清除
  898. Private Sub NeoForge_Selected(sender As MyListItem, e As EventArgs)
  899. SelectedNeoForge = sender.Tag
  900. CardNeoForge.IsSwaped = True
  901. OptiFine_Loaded()
  902. SelectReload()
  903. End Sub
  904. Private Sub NeoForge_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnNeoForgeClear.MouseLeftButtonUp
  905. SelectedNeoForge = Nothing
  906. CardNeoForge.IsSwaped = True
  907. e.Handled = True
  908. OptiFine_Loaded()
  909. SelectReload()
  910. End Sub
  911. #End Region
  912. #Region "Fabric 列表"
  913. ''' <summary>
  914. ''' 获取 Fabric 的加载异常信息。若正常则返回 Nothing。
  915. ''' </summary>
  916. Private Function LoadFabricGetError() As String
  917. If LoadFabric Is Nothing OrElse LoadFabric.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "加载中……"
  918. If LoadFabric.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadFabric.State, Object).Error.Message
  919. For Each Version As JObject In DlFabricListLoader.Output.Value("game")
  920. If Version("version").ToString = SelectedMinecraftId.Replace("∞", "infinite").Replace("Combat Test 7c", "1.16_combat-3") Then
  921. If SelectedForge IsNot Nothing Then Return "与 Forge 不兼容"
  922. If SelectedNeoForge IsNot Nothing Then Return "与 NeoForge 不兼容"
  923. Return Nothing
  924. End If
  925. Next
  926. Return "不可用"
  927. End Function
  928. '限制展开
  929. Private Sub CardFabric_PreviewSwap(sender As Object, e As RouteEventArgs) Handles CardFabric.PreviewSwap
  930. If LoadFabricGetError() IsNot Nothing Then e.Handled = True
  931. End Sub
  932. ''' <summary>
  933. ''' 尝试重新可视化 Fabric 版本列表。
  934. ''' </summary>
  935. Private Sub Fabric_Loaded() Handles LoadFabric.StateChanged
  936. Try
  937. If DlFabricListLoader.State <> LoadState.Finished Then Exit Sub
  938. '获取版本列表
  939. Dim Versions As JArray = DlFabricListLoader.Output.Value("loader")
  940. If Not Versions.Any() Then Exit Sub
  941. '可视化
  942. PanFabric.Children.Clear()
  943. PanFabric.Tag = Versions
  944. CardFabric.SwapControl = PanFabric
  945. CardFabric.SwapType = 12
  946. Catch ex As Exception
  947. Log(ex, "可视化 Fabric 安装版本列表出错", LogLevel.Feedback)
  948. End Try
  949. End Sub
  950. '选择与清除
  951. Public Sub Fabric_Selected(sender As MyListItem, e As EventArgs)
  952. SelectedFabric = sender.Tag("version").ToString
  953. FabricApi_Loaded()
  954. OptiFabric_Loaded()
  955. CardFabric.IsSwaped = True
  956. SelectReload()
  957. End Sub
  958. Private Sub Fabric_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnFabricClear.MouseLeftButtonUp
  959. SelectedFabric = Nothing
  960. SelectedFabricApi = Nothing
  961. SelectedOptiFabric = Nothing
  962. CardFabric.IsSwaped = True
  963. e.Handled = True
  964. SelectReload()
  965. End Sub
  966. #End Region
  967. #Region "Fabric API 列表"
  968. ''' <summary>
  969. ''' 从显示名判断该 API 是否与某版本适配。
  970. ''' </summary>
  971. Public Shared Function IsSuitableFabricApi(DisplayName As String, MinecraftVersion As String) As Boolean
  972. Try
  973. If DisplayName Is Nothing OrElse MinecraftVersion Is Nothing Then Return False
  974. DisplayName = DisplayName.ToLower : MinecraftVersion = MinecraftVersion.Replace("∞", "infinite").Replace("Combat Test 7c", "1.16_combat-3").ToLower
  975. If DisplayName.StartsWith("[" & MinecraftVersion & "]") Then Return True
  976. If Not DisplayName.Contains("/") OrElse Not DisplayName.Contains("]") Then Return False
  977. '直接的判断(例如 1.18.1/22w03a)
  978. For Each Part As String In DisplayName.BeforeFirst("]").TrimStart("[").Split("/")
  979. If Part = MinecraftVersion Then Return True
  980. Next
  981. '将版本名分割语素(例如 1.16.4/5)
  982. Dim Lefts = RegexSearch(DisplayName.BeforeFirst("]"), "[a-z/]+|[0-9/]+")
  983. Dim Rights = RegexSearch(MinecraftVersion.BeforeFirst("]"), "[a-z/]+|[0-9/]+")
  984. '对每段进行判断
  985. Dim i As Integer = 0
  986. While True
  987. '两边均缺失,感觉是一个东西
  988. If Lefts.Count - 1 < i AndAlso Rights.Count - 1 < i Then Return True
  989. '确定两边是否一致
  990. Dim LeftValue As String = If(Lefts.Count - 1 < i, "-1", Lefts(i))
  991. Dim RightValue As String = If(Rights.Count - 1 < i, "-1", Rights(i))
  992. If Not LeftValue.Contains("/") Then
  993. If LeftValue <> RightValue Then Return False
  994. Else
  995. '左边存在斜杠
  996. If Not LeftValue.Contains(RightValue) Then Return False
  997. End If
  998. i += 1
  999. End While
  1000. Return True
  1001. Catch ex As Exception
  1002. Log(ex, "判断 Fabric API 版本适配性出错(" & DisplayName & ", " & MinecraftVersion & ")")
  1003. Return False
  1004. End Try
  1005. End Function
  1006. ''' <summary>
  1007. ''' 获取 FabricApi 的加载异常信息。若正常则返回 Nothing。
  1008. ''' </summary>
  1009. Private Function LoadFabricApiGetError() As String
  1010. If LoadFabricApi Is Nothing OrElse LoadFabricApi.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "加载中……"
  1011. If LoadFabricApi.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadFabricApi.State, Object).Error.Message
  1012. If DlFabricApiLoader.Output Is Nothing Then
  1013. If SelectedFabric Is Nothing Then Return "需要安装 Fabric"
  1014. Return "加载中……"
  1015. End If
  1016. For Each Version In DlFabricApiLoader.Output
  1017. If Not IsSuitableFabricApi(Version.DisplayName, SelectedMinecraftId) Then Continue For
  1018. If SelectedFabric Is Nothing Then Return "需要安装 Fabric"
  1019. Return Nothing
  1020. Next
  1021. Return "不可用"
  1022. End Function
  1023. '限制展开
  1024. Private Sub CardFabricApi_PreviewSwap(sender As Object, e As RouteEventArgs) Handles CardFabricApi.PreviewSwap
  1025. If LoadFabricApiGetError() IsNot Nothing Then e.Handled = True
  1026. End Sub
  1027. Private AutoSelectedFabricApi As Boolean = False
  1028. ''' <summary>
  1029. ''' 尝试重新可视化 FabricApi 版本列表。
  1030. ''' </summary>
  1031. Private Sub FabricApi_Loaded() Handles LoadFabricApi.StateChanged
  1032. Try
  1033. If DlFabricApiLoader.State <> LoadState.Finished Then Exit Sub
  1034. If SelectedMinecraftId Is Nothing OrElse SelectedFabric Is Nothing Then Exit Sub
  1035. '获取版本列表
  1036. Dim Versions As New List(Of CompFile)
  1037. For Each Version In DlFabricApiLoader.Output
  1038. If IsSuitableFabricApi(Version.DisplayName, SelectedMinecraftId) Then
  1039. If Not Version.DisplayName.StartsWith("[") Then
  1040. Log("[Download] 已特判修改 Fabric API 显示名:" & Version.DisplayName, LogLevel.Debug)
  1041. Version.DisplayName = "[" & SelectedMinecraftId & "] " & Version.DisplayName
  1042. End If
  1043. Versions.Add(Version)
  1044. End If
  1045. Next
  1046. If Not Versions.Any() Then Exit Sub
  1047. Versions = Versions.OrderByDescending(Function(v) v.ReleaseDate).ToList
  1048. '可视化
  1049. PanFabricApi.Children.Clear()
  1050. For Each Version In Versions
  1051. If Not IsSuitableFabricApi(Version.DisplayName, SelectedMinecraftId) Then Continue For
  1052. PanFabricApi.Children.Add(FabricApiDownloadListItem(Version, AddressOf FabricApi_Selected))
  1053. Next
  1054. '自动选择 Fabric API
  1055. If Not AutoSelectedFabricApi Then
  1056. AutoSelectedFabricApi = True
  1057. Log($"[Download] 已自动选择 Fabric API:{CType(PanFabricApi.Children(0), MyListItem).Title}")
  1058. FabricApi_Selected(PanFabricApi.Children(0), Nothing)
  1059. End If
  1060. Catch ex As Exception
  1061. Log(ex, "可视化 Fabric API 安装版本列表出错", LogLevel.Feedback)
  1062. End Try
  1063. End Sub
  1064. '选择与清除
  1065. Private Sub FabricApi_Selected(sender As MyListItem, e As EventArgs)
  1066. SelectedFabricApi = sender.Tag
  1067. CardFabricApi.IsSwaped = True
  1068. SelectReload()
  1069. End Sub
  1070. Private Sub FabricApi_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnFabricApiClear.MouseLeftButtonUp
  1071. SelectedFabricApi = Nothing
  1072. CardFabricApi.IsSwaped = True
  1073. e.Handled = True
  1074. SelectReload()
  1075. End Sub
  1076. #End Region
  1077. #Region "OptiFabric 列表"
  1078. ''' <summary>
  1079. ''' 从显示名判断该 Mod 是否与某版本适配。
  1080. ''' </summary>
  1081. Private Function IsSuitableOptiFabric(ModFile As CompFile, MinecraftVersion As String) As Boolean
  1082. Try
  1083. If MinecraftVersion Is Nothing Then Return False
  1084. Return ModFile.GameVersions.Contains(MinecraftVersion)
  1085. Catch ex As Exception
  1086. Log(ex, "判断 OptiFabric 版本适配性出错(" & MinecraftVersion & ")")
  1087. Return False
  1088. End Try
  1089. End Function
  1090. Private AutoSelectedOptiFabric As Boolean = False
  1091. ''' <summary>
  1092. ''' 获取 OptiFabric 的加载异常信息。若正常则返回 Nothing。
  1093. ''' </summary>
  1094. Private Function LoadOptiFabricGetError() As String
  1095. If SelectedMinecraftId.StartsWith("1.14") OrElse SelectedMinecraftId.StartsWith("1.15") Then Return "不兼容老版本 Fabric,请手动下载 OptiFabric Origins"
  1096. If LoadOptiFabric Is Nothing OrElse LoadOptiFabric.State.LoadingState = MyLoading.MyLoadingState.Run Then Return "加载中……"
  1097. If LoadOptiFabric.State.LoadingState = MyLoading.MyLoadingState.Error Then Return "获取版本列表失败:" & CType(LoadOptiFabric.State, Object).Error.Message
  1098. If DlOptiFabricLoader.Output Is Nothing Then
  1099. If SelectedFabric Is Nothing AndAlso SelectedOptiFine Is Nothing Then Return "需要安装 OptiFine 与 Fabric"
  1100. If SelectedFabric Is Nothing Then Return "需要安装 Fabric"
  1101. If SelectedOptiFine Is Nothing Then Return "需要安装 OptiFine"
  1102. Return "加载中……"
  1103. End If
  1104. For Each Version In DlOptiFabricLoader.Output
  1105. If Not IsSuitableOptiFabric(Version, SelectedMinecraftId) Then Continue For '2135#
  1106. If SelectedFabric Is Nothing AndAlso SelectedOptiFine Is Nothing Then Return "需要安装 OptiFine 与 Fabric"
  1107. If SelectedFabric Is Nothing Then Return "需要安装 Fabric"
  1108. If SelectedOptiFine Is Nothing Then Return "需要安装 OptiFine"
  1109. Return Nothing '通过检查
  1110. Next
  1111. Return "不可用"
  1112. End Function
  1113. '限制展开
  1114. Private Sub CardOptiFabric_PreviewSwap(sender As Object, e As RouteEventArgs) Handles CardOptiFabric.PreviewSwap
  1115. If LoadOptiFabricGetError() IsNot Nothing Then e.Handled = True
  1116. End Sub
  1117. ''' <summary>
  1118. ''' 尝试重新可视化 OptiFabric 版本列表。
  1119. ''' </summary>
  1120. Private Sub OptiFabric_Loaded() Handles LoadOptiFabric.StateChanged
  1121. Try
  1122. If DlOptiFabricLoader.State <> LoadState.Finished Then Exit Sub
  1123. If SelectedMinecraftId Is Nothing OrElse SelectedFabric Is Nothing OrElse SelectedOptiFine Is Nothing Then Exit Sub
  1124. '获取版本列表
  1125. Dim Versions As New List(Of CompFile)
  1126. For Each Version In DlOptiFabricLoader.Output
  1127. If IsSuitableOptiFabric(Version, SelectedMinecraftId) Then Versions.Add(Version)
  1128. Next
  1129. If Not Versions.Any() Then Exit Sub
  1130. '排序
  1131. Versions = Versions.OrderByDescending(Function(v) v.ReleaseDate).ToList
  1132. '可视化
  1133. PanOptiFabric.Children.Clear()
  1134. For Each Version In Versions
  1135. If Not IsSuitableOptiFabric(Version, SelectedMinecraftId) Then Continue For
  1136. PanOptiFabric.Children.Add(OptiFabricDownloadListItem(Version, AddressOf OptiFabric_Selected))
  1137. Next
  1138. '自动选择 OptiFabric
  1139. If Not AutoSelectedOptiFabric AndAlso
  1140. Not (SelectedMinecraftId.StartsWith("1.14") OrElse SelectedMinecraftId.StartsWith("1.15")) Then '1.14~15 不自动选择
  1141. AutoSelectedOptiFabric = True
  1142. Log($"[Download] 已自动选择 OptiFabric:{CType(PanOptiFabric.Children(0), MyListItem).Title}")
  1143. OptiFabric_Selected(PanOptiFabric.Children(0), Nothing)
  1144. End If
  1145. Catch ex As Exception
  1146. Log(ex, "可视化 OptiFabric 安装版本列表出错", LogLevel.Feedback)
  1147. End Try
  1148. End Sub
  1149. '选择与清除
  1150. Private Sub OptiFabric_Selected(sender As MyListItem, e As EventArgs)
  1151. SelectedOptiFabric = sender.Tag
  1152. CardOptiFabric.IsSwaped = True
  1153. SelectReload()
  1154. End Sub
  1155. Private Sub OptiFabric_Clear(sender As Object, e As MouseButtonEventArgs) Handles BtnOptiFabricClear.MouseLeftButtonUp
  1156. SelectedOptiFabric = Nothing
  1157. CardOptiFabric.IsSwaped = True
  1158. e.Handled = True
  1159. SelectReload()
  1160. End Sub
  1161. #End Region
  1162. #Region "安装"
  1163. Private Sub TextSelectName_KeyDown(sender As Object, e As KeyEventArgs) Handles TextSelectName.KeyDown
  1164. If e.Key = Key.Enter AndAlso BtnStart.IsEnabled Then BtnStart_Click()
  1165. End Sub
  1166. Private Sub BtnStart_Click() Handles BtnStart.Click
  1167. '确认版本隔离
  1168. If (SelectedForge IsNot Nothing OrElse SelectedNeoForge IsNot Nothing OrElse SelectedFabric IsNot Nothing) AndAlso
  1169. (Setup.Get("LaunchArgumentIndieV2") = 0 OrElse Setup.Get("LaunchArgumentIndieV2") = 2) Then
  1170. If MyMsgBox("你尚未开启版本隔离,这会导致多个版本共用同一个 Mod 文件夹。" & vbCrLf &
  1171. "因此游戏可能会因为读取到与当前版本不符的 Mod 而崩溃。" & vbCrLf &
  1172. "推荐在开始下载前,在 设置 → 启动选项 → 版本隔离 中开启版本隔离!", "版本隔离提示", "取消下载", "继续") = 1 Then
  1173. Exit Sub
  1174. End If
  1175. End If
  1176. '提交安装申请
  1177. Dim VersionName As String = TextSelectName.Text
  1178. Dim Request As New McInstallRequest With {
  1179. .TargetVersionName = VersionName,
  1180. .TargetVersionFolder = $"{PathMcFolder}versions\{VersionName}\",
  1181. .MinecraftJson = SelectedMinecraftJsonUrl,
  1182. .MinecraftName = SelectedMinecraftId,
  1183. .OptiFineEntry = SelectedOptiFine,
  1184. .ForgeEntry = SelectedForge,
  1185. .NeoForgeEntry = SelectedNeoForge,
  1186. .FabricVersion = SelectedFabric,
  1187. .FabricApi = SelectedFabricApi,
  1188. .OptiFabric = SelectedOptiFabric,
  1189. .LiteLoaderEntry = SelectedLiteLoader
  1190. }
  1191. If Not McInstall(Request) Then Exit Sub
  1192. '返回,这样在再次进入安装页面时这个版本就会显示文件夹已重复
  1193. ExitSelectPage()
  1194. End Sub
  1195. #End Region
  1196. End Class