XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEToolBox

【WPF】XFE工具箱

公开
关注 0 Fork 0 Star 0
返回提交历史

XFEstudio/XFEToolBox

新增 XFEToolBox 在线升级检测与一键升级功能

- 实现升级协议与流程,集成 UpgradeHelper/UpgradeService,支持自动/手动检测新版本、发行说明弹窗、忽略版本管理 - 设置页新增“软件更新”分组,支持手动检查、自动检测开关、当前版本显示、忽略版本清理等 - 主窗口支持启动时自动检测升级 - 统一 Installer 及主程序参数与路径,增强参数校验与异常提示 - README 增加升级协议说明,明确流程与参数格式 - 引入 XFEExtension.NetCore.UpgradeHelper 依赖,版本号提升至 1.1.0 - 优化弹窗辅助类及相关属性、命令、界面绑定

97019ed
XFE工作室室长 <mail@xfegzs.com>
提交于

代码差异

15 个文件 +439 -13
Modified XFEToolBox.Client.Installer/App.xaml.cs +17 -3
@@ -16,11 +16,25 @@ namespace XFEToolBox.Client.Installer
16 16 {
17 17 SystemProfile.FirstInstall = true;
18 18 }
19 else if (e.Args.Length == 3 &&
20 string.Equals(e.Args[0], "Upgrade", StringComparison.OrdinalIgnoreCase) &&
21 Uri.TryCreate(e.Args[1], UriKind.Absolute, out var parsedDownloadUri) &&
22 parsedDownloadUri is { } downloadUri &&
23 (downloadUri.Scheme == Uri.UriSchemeHttp || downloadUri.Scheme == Uri.UriSchemeHttps) &&
24 System.IO.Directory.Exists(e.Args[2]))
25 {
26 SystemProfile.StartMode = "Upgrade";
27 SystemProfile.DownloadUrl = downloadUri.AbsoluteUri;
28 SystemProfile.InstallPath = System.IO.Path.GetFullPath(e.Args[2]);
29 }
19 30 else
20 31 {
21 SystemProfile.StartMode = e.Args[0];
22 SystemProfile.DownloadUrl = e.Args[1];
23 SystemProfile.InstallPath = e.Args[2];
32 MessageBox.Show(
33 "Installer 收到的升级参数无效。请从 XFEToolBox 内重新检查更新。",
34 "无法开始升级",
35 MessageBoxButton.OK,
36 MessageBoxImage.Error);
37 Shutdown(-1);
24 38 }
25 39 }
26 40 }
Modified XFEToolBox.Client.Installer/Profiles/SystemProfile.cs +6 -1
@@ -2,6 +2,9 @@
2 2 {
3 3 public class SystemProfile
4 4 {
5 public const string ApplicationName = "XFEToolBox";
6 public const string ApplicationExecutableName = ApplicationName + ".exe";
7
5 8 /// <summary>
6 9 /// 当前窗口DPI缩放
7 10 /// </summary>
@@ -29,7 +32,9 @@
29 32 /// <summary>
30 33 /// 安装目录
31 34 /// </summary>
32 public static string InstallPath { get; set; } = @$"{Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86)}\XFEToolBox.Client.Installer";
35 public static string InstallPath { get; set; } = System.IO.Path.Combine(
36 Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86),
37 ApplicationName);
33 38 /// <summary>
34 39 /// 第一次安装
35 40 /// </summary>
Modified XFEToolBox.Client.Installer/README.md +10 -0
@@ -16,3 +16,13 @@
16 16 ## 将软件压缩包放入安装器
17 17
18 18 - 将完成上述操作后的软件打包为打包为`Source.zip`文件(请注意,压缩包内应为包含exe的直接目录,而非二级目录),并替换`Resources\Resource`目录下0KB的`Source.zip`文件
19
20 ## 在线升级协议
21
22 - 客户端通过 `XFEExtension.NetCore.UpgradeHelper` 请求 `http://upgrade.api.xfe.studio/upgrade`,升级服务中的应用名固定为 `XFEToolBox`
23 - 检测到新版本并经用户确认后,客户端以管理员权限调用同目录的 `Installer.exe`
24 - 调用参数依次为:`Upgrade`、升级压缩包的 HTTP/HTTPS 地址、当前 XFEToolBox 安装目录
25 - 等价命令:`Installer.exe Upgrade <downloadUrl> <installDirectory>`
26 - Installer 会将压缩包下载为安装目录下的 `InstallPackage.zip`,解压覆盖完成后删除临时压缩包,并启动 `XFEToolBox.exe`
27 - 发布升级包时不要增加二级目录;压缩包根目录应直接包含 `XFEToolBox.exe` 及其依赖文件
28 - 在线升级包不要覆盖正在运行的 `Installer.exe`;Installer 自身需要更新时,应在后续安装包发布流程中单独替换
Modified XFEToolBox.Client.Installer/ViewModel/Pages/InstallPageViewModel.cs +2 -2
@@ -16,7 +16,7 @@ namespace XFEToolBox.Client.Installer.ViewModel.Pages
16 16 [ObservableProperty]
17 17 bool agreementChecked = false;
18 18 [ObservableProperty]
19 string installPath = @$"{Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86)}\XFEToolBox.Client.Installer";
19 string installPath = SystemProfile.InstallPath;
20 20 public InstallPage ViewPage { get; set; } = viewPage;
21 21
22 22 [RelayCommand]
@@ -37,7 +37,7 @@ namespace XFEToolBox.Client.Installer.ViewModel.Pages
37 37 if (openFolderDialog.ShowDialog() == true)
38 38 {
39 39 if (FileHelper.IsRootPath(openFolderDialog.FolderName))
40 InstallPath = $@"{openFolderDialog.FolderName}XFEToolBox.Client.Installer";
40 InstallPath = Path.Combine(openFolderDialog.FolderName, SystemProfile.ApplicationName);
41 41 else
42 42 InstallPath = openFolderDialog.FolderName;
43 43 SystemProfile.InstallPath = InstallPath;
Modified XFEToolBox.Client.Installer/ViewModel/Pages/InstallProgressPageViewModel.cs +1 -1
@@ -14,7 +14,7 @@ namespace XFEToolBox.Client.Installer.ViewModel.Pages
14 14 [RelayCommand]
15 15 void ConfirmSuccess()
16 16 {
17 var startInfo = new ProcessStartInfo(Path.Combine(SystemProfile.InstallPath, "XFE工具箱.exe"))
17 var startInfo = new ProcessStartInfo(Path.Combine(SystemProfile.InstallPath, SystemProfile.ApplicationExecutableName))
18 18 {
19 19 UseShellExecute = true,
20 20 WorkingDirectory = SystemProfile.InstallPath
Modified XFEToolBox.Client.Installer/Views/Pages/InstallProgressPage.xaml.cs +4 -3
@@ -30,9 +30,10 @@ namespace XFEToolBox.Client.Installer.Views.Pages
30 30 {
31 31 case "Upgrade":
32 32 var filePath = Path.Combine(SystemProfile.InstallPath, "InstallPackage.zip");
33 if (File.Exists(filePath) && File.OpenRead(filePath) is FileStream fileStream)
33 if (File.Exists(filePath))
34 34 {
35 Install(fileStream);
35 using (var fileStream = File.OpenRead(filePath))
36 Install(fileStream);
36 37 File.Delete(filePath);
37 38 }
38 39 break;
@@ -42,7 +43,7 @@ namespace XFEToolBox.Client.Installer.Views.Pages
42 43 if (SystemProfile.InstallPath != string.Empty && !Directory.Exists(SystemProfile.InstallPath))
43 44 Directory.CreateDirectory(SystemProfile.InstallPath);
44 45 if (Install(innerStream))
45 FileHelper.CreateShortCut($@"{Environment.GetFolderPath(Environment.SpecialFolder.Desktop)}\XFE工具箱.lnk", Path.Combine(SystemProfile.InstallPath, "XFEToolBox.exe"), null, "XFE工具箱快捷方式", null, SystemProfile.InstallPath);
46 FileHelper.CreateShortCut($@"{Environment.GetFolderPath(Environment.SpecialFolder.Desktop)}\XFE工具箱.lnk", Path.Combine(SystemProfile.InstallPath, SystemProfile.ApplicationExecutableName), null, "XFE工具箱快捷方式", null, SystemProfile.InstallPath);
46 47 }
47 48 break;
48 49 }
Modified XFEToolBox.Client.Installer/XFEToolBox.Client.Installer.csproj +1 -0
@@ -9,6 +9,7 @@
9 9 <ApplicationManifest>app.manifest</ApplicationManifest>
10 10 <ApplicationIcon>Resources\Icon\Icon.ico</ApplicationIcon>
11 11 <AssemblyName>Installer</AssemblyName>
12 <Version>1.1.0</Version>
12 13 </PropertyGroup>
13 14
14 15 <ItemGroup>
Modified XFEToolBox/Profiles/CrossVersionProfiles/SystemProfile.cs +10 -0
@@ -46,6 +46,16 @@ public partial class SystemProfile : XFEProfile
46 46 [ProfileProperty]
47 47 private bool mainTutorialCompleted = false;
48 48 /// <summary>
49 /// 是否在主窗口首次加载后自动检查新版本。
50 /// </summary>
51 [ProfileProperty]
52 private bool checkForUpdatesOnStartup = true;
53 /// <summary>
54 /// 用户选择忽略的升级版本。
55 /// </summary>
56 [ProfileProperty]
57 private string ignoredUpgradeVersion = string.Empty;
58 /// <summary>
49 59 /// 最近使用页面、工具和软件的 JSON 记录,由 RecentUsageService 维护。
50 60 /// </summary>
51 61 [ProfileProperty]
Modified XFEToolBox/Utilities/PopupHelper.cs +8 -2
@@ -45,6 +45,9 @@ public static class PopupHelper
45 45 };
46 46
47 47 public static MessageBoxResult? ShowConfirmDialog(object content, bool showCancelButton = false, string confirmText = "确定", string cancelText = "取消")
48 => ShowConfirmDialog(content, new PopupWindowOptions(), showCancelButton, confirmText, cancelText);
49
50 public static MessageBoxResult? ShowConfirmDialog(object content, PopupWindowOptions options, bool showCancelButton = false, string confirmText = "确定", string cancelText = "取消")
48 51 {
49 52 var dialog = CreateNormalDialogPage(content);
50 53 dialog.ViewModel.ConfirmText = confirmText;
@@ -52,7 +55,7 @@ public static class PopupHelper
52 55 dialog.ViewModel.ConfirmGridLength = new GridLength(1, GridUnitType.Star);
53 56 if (showCancelButton)
54 57 dialog.ViewModel.CancelGridLength = new GridLength(1, GridUnitType.Star);
55 return ShowDialog(dialog);
58 return ShowDialog(dialog, options);
56 59 }
57 60
58 61 public static MessageBoxResult? ShowConfirmDialog(string text, Color textColor, bool showCancelButton = false, string confirmText = "确定", string cancelText = "取消") => ShowConfirmDialog(CreateTextContent(text, textColor), showCancelButton, confirmText, cancelText);
@@ -60,6 +63,9 @@ public static class PopupHelper
60 63 public static MessageBoxResult? ShowConfirmDialog(string text, bool showCancelButton = false, string confirmText = "确定", string cancelText = "取消") => ShowConfirmDialog(text, Colors.Black, showCancelButton, confirmText, cancelText);
61 64
62 65 public static MessageBoxResult? ShowYesOrNoDialog(object content, bool showCancelButton = false, string yesText = "是", string noText = "否")
66 => ShowYesOrNoDialog(content, new PopupWindowOptions(), showCancelButton, yesText, noText);
67
68 public static MessageBoxResult? ShowYesOrNoDialog(object content, PopupWindowOptions options, bool showCancelButton = false, string yesText = "是", string noText = "否")
63 69 {
64 70 var dialog = CreateNormalDialogPage(content);
65 71 dialog.ViewModel.YesText = yesText;
@@ -68,7 +74,7 @@ public static class PopupHelper
68 74 dialog.ViewModel.NoGridLength = new GridLength(1, GridUnitType.Star);
69 75 if (showCancelButton)
70 76 dialog.ViewModel.CancelGridLength = new GridLength(1, GridUnitType.Star);
71 return ShowDialog(dialog);
77 return ShowDialog(dialog, options);
72 78 }
73 79
74 80 public static MessageBoxResult? ShowYesOrNoDialog(string text, Color textColor, bool showCancelButton = false, string yesText = "是", string noText = "否") => ShowYesOrNoDialog(CreateTextContent(text, textColor), showCancelButton, yesText, noText);
Added XFEToolBox/Utilities/UpgradeHelper.cs +108 -0
@@ -0,0 +1,108 @@
1 using System.Diagnostics;
2 using System.IO;
3 using System.Reflection;
4 using ApplicationUpgradeManager.Core.Model;
5 using XFEExtension.NetCore.UpgradeHelper.Models;
6 using XFEExtension.NetCore.UpgradeHelper.Utilities;
7
8 namespace XFEToolBox.Client.Utilities;
9
10 /// <summary>
11 /// XFEToolBox 与 ApplicationUpgradeManager 服务之间的统一入口。
12 /// </summary>
13 public static class UpgradeHelper
14 {
15 public const string ApplicationName = "XFEToolBox";
16 public const string RequestAddress = "http://upgrade.api.xfe.studio/upgrade";
17 public const string InstallerFileName = "Installer.exe";
18
19 public static Upgrader Upgrader { get; set; } = new(RequestAddress);
20
21 public static Version Version => Assembly.GetEntryAssembly()?.GetName().Version ?? new Version(1, 0, 0);
22
23 public static string DisplayVersion => Version.ToString(3);
24
25 /// <summary>
26 /// 检查当前版本是否已经是最新版本。网络错误按“未知”处理,不阻断应用启动。
27 /// </summary>
28 public static async Task<bool> CheckUpgrade()
29 {
30 var release = await GetReleaseNotes();
31 return release?.IsLatest ?? true;
32 }
33
34 /// <summary>
35 /// 获取适合直接展示的发行说明。
36 /// </summary>
37 public static async Task<UpgradeInfoNotes?> GetReleaseNotes()
38 {
39 try
40 {
41 return await Upgrader.GetReleaseNotes(ApplicationName, Version.ToString());
42 }
43 catch (Exception exception)
44 {
45 Debug.WriteLine($"[Upgrade] 获取发行说明失败:{exception}");
46 return null;
47 }
48 }
49
50 /// <summary>
51 /// 获取结构化版本记录,供历史版本或高级界面使用。
52 /// </summary>
53 public static async Task<UpgradeInfoObject?> GetReleaseObject()
54 {
55 try
56 {
57 return await Upgrader.GetReleaseObject(ApplicationName, Version.ToString());
58 }
59 catch (Exception exception)
60 {
61 Debug.WriteLine($"[Upgrade] 获取结构化升级信息失败:{exception}");
62 return null;
63 }
64 }
65
66 /// <summary>
67 /// 创建 Installer 的升级启动参数。公开此方法便于发布流程和测试校验协议。
68 /// </summary>
69 public static ProcessStartInfo CreateInstallerStartInfo(
70 string downloadUrl,
71 string? installDirectory = null,
72 string? installerPath = null)
73 {
74 if (!Uri.TryCreate(downloadUrl, UriKind.Absolute, out var downloadUri) ||
75 (downloadUri.Scheme != Uri.UriSchemeHttp && downloadUri.Scheme != Uri.UriSchemeHttps))
76 throw new ArgumentException("升级下载地址必须是有效的 HTTP 或 HTTPS 地址。", nameof(downloadUrl));
77
78 installDirectory = Path.GetFullPath(installDirectory ?? AppContext.BaseDirectory);
79 installerPath = Path.GetFullPath(installerPath ?? Path.Combine(installDirectory, InstallerFileName));
80 if (!Directory.Exists(installDirectory))
81 throw new DirectoryNotFoundException($"找不到应用安装目录:{installDirectory}");
82 if (!File.Exists(installerPath))
83 throw new FileNotFoundException("找不到升级所需的 Installer.exe,请重新安装或修复 XFEToolBox。", installerPath);
84
85 var startInfo = new ProcessStartInfo(installerPath)
86 {
87 UseShellExecute = true,
88 Verb = "runas",
89 WorkingDirectory = installDirectory
90 };
91 startInfo.ArgumentList.Add("Upgrade");
92 startInfo.ArgumentList.Add(downloadUri.AbsoluteUri);
93 startInfo.ArgumentList.Add(installDirectory);
94 return startInfo;
95 }
96
97 /// <summary>
98 /// 以管理员权限启动 Installer,并关闭当前应用释放待替换文件。
99 /// </summary>
100 public static void StartUpdate(string downloadUrl)
101 {
102 var process = Process.Start(CreateInstallerStartInfo(downloadUrl));
103 if (process is null)
104 throw new InvalidOperationException("Installer 未能启动。");
105
106 AppCenter.ExitApp(true);
107 }
108 }
Added XFEToolBox/Utilities/UpgradeService.cs +203 -0
@@ -0,0 +1,203 @@
1 using System.Windows;
2 using System.Windows.Controls;
3 using System.Windows.Media;
4 using ApplicationUpgradeManager.Core.Model;
5 using XFEToolBox.Client.Model;
6 using XFEToolBox.Client.Profiles.CrossVersionProfiles;
7
8 namespace XFEToolBox.Client.Utilities;
9
10 public enum UpgradeCheckOutcome
11 {
12 Latest,
13 UpdateAvailable,
14 Ignored,
15 UpdateStarted,
16 Failed,
17 AlreadyChecking
18 }
19
20 public sealed record UpgradeCheckResult(
21 UpgradeCheckOutcome Outcome,
22 string Message,
23 UpgradeInfoNotes? Release = null);
24
25 /// <summary>
26 /// 协调自动/手动检查、版本忽略、升级提示和 Installer 启动。
27 /// </summary>
28 public static class UpgradeService
29 {
30 private static readonly SemaphoreSlim CheckGate = new(1, 1);
31
32 public static bool IsChecking => CheckGate.CurrentCount == 0;
33
34 public static async Task<UpgradeCheckResult> CheckForUpdatesAsync(bool userInitiated, Window? owner = null)
35 {
36 if (!await CheckGate.WaitAsync(0))
37 return new UpgradeCheckResult(UpgradeCheckOutcome.AlreadyChecking, "正在检查更新,请稍候。");
38
39 try
40 {
41 var release = await UpgradeHelper.GetReleaseNotes();
42 if (release is null)
43 {
44 const string message = "无法连接升级服务器,请检查网络后重试。";
45 if (userInitiated)
46 ShowInformation("检查更新失败", message, owner);
47 return new UpgradeCheckResult(UpgradeCheckOutcome.Failed, message);
48 }
49
50 if (release.IsLatest)
51 {
52 var message = $"当前已是最新版本({UpgradeHelper.DisplayVersion})。";
53 if (userInitiated)
54 ShowInformation("已是最新版本", message, owner);
55 return new UpgradeCheckResult(UpgradeCheckOutcome.Latest, message, release);
56 }
57
58 if (!userInitiated && string.Equals(
59 release.LatestVersion,
60 SystemProfile.IgnoredUpgradeVersion,
61 StringComparison.OrdinalIgnoreCase))
62 {
63 return new UpgradeCheckResult(
64 UpgradeCheckOutcome.Ignored,
65 $"版本 {release.LatestVersion} 已被忽略。",
66 release);
67 }
68
69 var choice = PopupHelper.ShowYesOrNoDialog(
70 CreateReleaseContent(release),
71 new PopupWindowOptions
72 {
73 Title = "发现新版本",
74 Subtitle = $"XFEToolBox {UpgradeHelper.DisplayVersion} → {release.LatestVersion}",
75 Width = 540,
76 Height = 390,
77 Owner = owner
78 },
79 showCancelButton: true,
80 yesText: "立即更新",
81 noText: "忽略此版本");
82
83 if (choice == MessageBoxResult.Yes)
84 {
85 try
86 {
87 UpgradeHelper.StartUpdate(release.DownloadUrl);
88 return new UpgradeCheckResult(UpgradeCheckOutcome.UpdateStarted, "Installer 已启动。", release);
89 }
90 catch (Exception exception)
91 {
92 var message = $"无法启动 Installer:{exception.Message}";
93 ShowInformation("启动升级失败", message, owner);
94 return new UpgradeCheckResult(UpgradeCheckOutcome.Failed, message, release);
95 }
96 }
97
98 if (choice == MessageBoxResult.No)
99 {
100 SystemProfile.IgnoredUpgradeVersion = release.LatestVersion ?? string.Empty;
101 return new UpgradeCheckResult(
102 UpgradeCheckOutcome.Ignored,
103 $"已忽略版本 {release.LatestVersion},仍可在设置中手动检查。",
104 release);
105 }
106
107 return new UpgradeCheckResult(
108 UpgradeCheckOutcome.UpdateAvailable,
109 $"发现版本 {release.LatestVersion},已暂缓更新。",
110 release);
111 }
112 catch (Exception exception)
113 {
114 var message = $"检查更新时发生错误:{exception.Message}";
115 if (userInitiated)
116 ShowInformation("检查更新失败", message, owner);
117 return new UpgradeCheckResult(UpgradeCheckOutcome.Failed, message);
118 }
119 finally
120 {
121 CheckGate.Release();
122 }
123 }
124
125 private static FrameworkElement CreateReleaseContent(UpgradeInfoNotes release)
126 {
127 var notes = string.IsNullOrWhiteSpace(release.ReleaseNotes)
128 ? "该版本暂未提供发行说明。"
129 : release.ReleaseNotes.Trim();
130 var title = new TextBlock
131 {
132 Text = $"可升级至 {release.LatestVersion}",
133 FontSize = 17,
134 FontWeight = FontWeights.SemiBold,
135 Margin = new Thickness(0, 0, 0, 6)
136 };
137 title.SetResourceReference(TextBlock.ForegroundProperty, "ToolTextPrimaryBrush");
138
139 var hint = new TextBlock
140 {
141 Text = "升级将调用同目录下的 Installer,下载完成后替换当前程序文件。",
142 TextWrapping = TextWrapping.Wrap,
143 Margin = new Thickness(0, 0, 0, 12)
144 };
145 hint.SetResourceReference(TextBlock.ForegroundProperty, "ToolTextSecondaryBrush");
146
147 var releaseText = new TextBlock
148 {
149 Text = notes,
150 TextWrapping = TextWrapping.Wrap,
151 Padding = new Thickness(14),
152 LineHeight = 22
153 };
154 releaseText.SetResourceReference(TextBlock.ForegroundProperty, "ToolTextPrimaryBrush");
155 releaseText.SetResourceReference(TextBlock.BackgroundProperty, "ToolControlBackgroundBrush");
156
157 return new Grid
158 {
159 Margin = new Thickness(18, 14, 18, 12),
160 Children =
161 {
162 new StackPanel
163 {
164 Children =
165 {
166 title,
167 hint,
168 new ScrollViewer
169 {
170 MaxHeight = 205,
171 VerticalScrollBarVisibility = ScrollBarVisibility.Auto,
172 HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled,
173 Content = releaseText
174 }
175 }
176 }
177 }
178 };
179 }
180
181 private static void ShowInformation(string title, string message, Window? owner)
182 {
183 var text = new TextBlock
184 {
185 Text = message,
186 TextWrapping = TextWrapping.Wrap,
187 Margin = new Thickness(18),
188 VerticalAlignment = VerticalAlignment.Center
189 };
190 text.SetResourceReference(TextBlock.ForegroundProperty, "ToolTextPrimaryBrush");
191 PopupHelper.ShowConfirmDialog(
192 text,
193 new PopupWindowOptions
194 {
195 Title = title,
196 Subtitle = "XFEToolBox 软件更新",
197 Width = 390,
198 Height = 230,
199 Owner = owner
200 },
201 confirmText: "知道了");
202 }
203 }
Modified XFEToolBox/ViewModel/Pages/SettingPageViewModel.cs +42 -0
@@ -29,8 +29,16 @@ public partial class SettingPageViewModel(SettingPage viewPage) : ObservableObje
29 29 string totalProfileSize = "计算中...";
30 30 [ObservableProperty]
31 31 string downloadDirectory = "目标下载目录:";
32 [ObservableProperty]
33 string upgradeStatus = "可手动检查更新,也可在启动时自动检测新版本。";
34 [ObservableProperty]
35 string ignoredUpgradeVersionDisplay = GetIgnoredUpgradeVersionDisplay();
36 [ObservableProperty]
37 [NotifyCanExecuteChangedFor(nameof(CheckUpgradeCommand))]
38 bool isCheckingForUpdates;
32 39 bool ignoreNextScroll = false;
33 40 public SettingPage ViewPage { get; set; } = viewPage;
41 public string CurrentApplicationVersion => $"当前版本 {UpgradeHelper.DisplayVersion}";
34 42
35 43 public static void LoadSettingProfile(DependencyObject parent)
36 44 {
@@ -269,5 +277,39 @@ public partial class SettingPageViewModel(SettingPage viewPage) : ObservableObje
269 277 ViewPage.scrollViewer.ScrollToVerticalOffset(ViewPage.scrollViewer.VerticalOffset + textBlock.TranslatePoint(new(), ViewPage.scrollViewer).Y - 20);
270 278 }
271 279 }
280
281 private bool CanCheckUpgrade() => !IsCheckingForUpdates;
282
283 [RelayCommand(CanExecute = nameof(CanCheckUpgrade))]
284 async Task CheckUpgrade()
285 {
286 IsCheckingForUpdates = true;
287 UpgradeStatus = "正在连接升级服务器...";
288 try
289 {
290 var result = await UpgradeService.CheckForUpdatesAsync(
291 userInitiated: true,
292 owner: Window.GetWindow(ViewPage));
293 UpgradeStatus = result.Message;
294 IgnoredUpgradeVersionDisplay = GetIgnoredUpgradeVersionDisplay();
295 }
296 finally
297 {
298 IsCheckingForUpdates = false;
299 }
300 }
301
302 [RelayCommand]
303 void ClearIgnoredUpgradeVersion()
304 {
305 SystemProfile.IgnoredUpgradeVersion = string.Empty;
306 IgnoredUpgradeVersionDisplay = GetIgnoredUpgradeVersionDisplay();
307 UpgradeStatus = "已清除忽略记录,后续检查会再次提示所有新版本。";
308 }
309
310 private static string GetIgnoredUpgradeVersionDisplay() =>
311 string.IsNullOrWhiteSpace(SystemProfile.IgnoredUpgradeVersion)
312 ? "未忽略任何版本"
313 : $"已忽略 {SystemProfile.IgnoredUpgradeVersion}";
272 314 #endregion
273 315 }
Modified XFEToolBox/Views/Pages/SettingPage.xaml +22 -0
Modified XFEToolBox/Views/Windows/MainWindow.xaml.cs +3 -0
Modified XFEToolBox/XFEToolBox.Client.csproj +2 -1