C# WPF应用启动时目录创建与迁移的实现及代码位置咨询
WPF启动逻辑实现与代码位置建议
嗨,很明确地说:把你的这两项检测与处理逻辑放在App.xaml.cs的OnStartup方法里是非常合适的!因为OnStartup就是WPF应用启动阶段的核心入口,专门用来处理初始化、环境校验、资源准备这类前置操作,完全匹配你的需求场景。
接下来我会把你的需求逻辑整合到现有代码中,同时做一些细节优化(比如避免硬编码路径、增加异常处理):
protected override void OnStartup(StartupEventArgs e) { Application.Current.DispatcherUnhandledException += new DispatcherUnhandledExceptionEventHandler(Current_DispatcherUnhandledException); try { // 初始化日志目录与Log4Net(保留你的原有逻辑) string cwd = Directory.GetCurrentDirectory(); string logPath = Path.Combine(cwd, "log"); if (!Directory.Exists(logPath)) { Directory.CreateDirectory(logPath); } FileInfo log4NetConfig = new FileInfo(Path.Combine(cwd, "Log4net.config")); log4net.Config.XmlConfigurator.Configure(log4NetConfig); // 记录启动日志(保留原有逻辑) System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly(); Version version = assembly.GetName().Version; UpdateService.CheckingForUpdates(); string appName = OtherHelper.GetAppSetting("NomApplication", "N.O.E"); Log.Info($"Démarrage de l'application {appName} version {version}"); // -------------------------- // 新增:你的目录检测与迁移逻辑 // -------------------------- // 1. 检测并创建AppData下的Affaires目录 string appDataRoaming = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); string targetRootPath = Path.Combine(appDataRoaming, "N.O.E"); string targetAffairesPath = Path.Combine(targetRootPath, "Affaires"); if (!Directory.Exists(targetAffairesPath)) { Directory.CreateDirectory(targetAffairesPath); Log.Info($"Création du répertoire cible : {targetAffairesPath}"); } // 2. 检测C盘下的旧目录并处理迁移 string oldAffairesPath = Path.Combine("C:\\", "N.O.E", "Affaires"); if (Directory.Exists(oldAffairesPath)) { // 弹出用户确认对话框 MessageBoxResult result = MessageBox.Show( "Un répertoire 'Affaires' existe dans C:\\N.O.E. Voulez-vous migrer son contenu vers le répertoire AppData ?", "Migration de données", MessageBoxButton.YesNo, MessageBoxImage.Question); if (result == MessageBoxResult.Yes) { try { // 迁移目录(复制所有文件和子目录) CopyDirectory(oldAffairesPath, targetAffairesPath); // 可选:迁移完成后删除旧目录(根据需求调整) Directory.Delete(oldAffairesPath, recursive: true); Log.Info($"Migration réussie depuis {oldAffairesPath} vers {targetAffairesPath}"); MessageBox.Show("Migration terminée avec succès !", "Succès", MessageBoxButton.OK, MessageBoxImage.Information); } catch (Exception ex) { Log.Error($"Erreur lors de la migration : {ex.Message}", ex); MessageBox.Show($"Échec de la migration : {ex.Message}", "Erreur", MessageBoxButton.OK, MessageBoxImage.Error); } } else { Log.Info("Utilisateur a refusé la migration du répertoire C:\\N.O.E\\Affaires"); } } // 保留你原有的其他初始化逻辑 ConfigService.InitializeConfigPathAndModificationDate(); TagService.InitializeReferential(); } catch (Exception ex) { Log.Fatal($"Erreur critique au démarrage : {ex.Message}", ex); MessageBox.Show($"Erreur critique au démarrage : {ex.Message}", "Erreur fatale", MessageBoxButton.OK, MessageBoxImage.Stop); // 终止应用 Shutdown(); } base.OnStartup(e); } // 辅助方法:递归复制目录内容 private void CopyDirectory(string sourceDir, string targetDir) { // 创建目标目录(如果不存在) Directory.CreateDirectory(targetDir); // 复制文件 foreach (string filePath in Directory.GetFiles(sourceDir)) { string fileName = Path.GetFileName(filePath); string targetFilePath = Path.Combine(targetDir, fileName); // 覆盖已存在的文件(可根据需求调整为跳过) File.Copy(filePath, targetFilePath, overwrite: true); } // 递归复制子目录 foreach (string subDirPath in Directory.GetDirectories(sourceDir)) { string subDirName = Path.GetFileName(subDirPath); string targetSubDir = Path.Combine(targetDir, subDirName); CopyDirectory(subDirPath, targetSubDir); } } // 全局异常处理(补充你原有的未完成的事件绑定) private void Current_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) { Log.Error($"Exception non gérée : {e.Exception.Message}", e.Exception); MessageBox.Show($"Une erreur inattendue s'est produite : {e.Exception.Message}", "Erreur", MessageBoxButton.OK, MessageBoxImage.Error); e.Handled = true; }
一些关键细节说明:
- 路径处理:用
Environment.SpecialFolder.ApplicationData代替硬编码的%AppData%,保证跨系统兼容性(比如Windows不同版本的AppData路径一致)。 - 异常处理:给迁移逻辑单独加了try-catch,避免迁移失败导致整个应用启动崩溃;同时完善了全局未处理异常的事件绑定。
- 用户交互:用WPF的
MessageBox实现确认提示,完全适配启动阶段的UI上下文。 - 日志记录:所有关键操作(目录创建、迁移成功/失败、用户选择)都加入了日志,方便后续排查问题。
需要注意的是:如果C盘的N.O.E\Affaires目录包含大量文件,迁移过程可能需要一点时间,你可以考虑添加进度提示(比如一个简单的进度窗口),不过这属于进阶优化,当前代码已经满足核心需求。
内容的提问来源于stack exchange,提问作者Ali
相关产品推荐
相关产品推荐

