You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:09:44