Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

增加首页图片更换功能#2431

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
Aether-1013 wants to merge1 commit intobabalae:main
base:main
Choose a base branch
Loading
fromAether-1013:feature/banner-image-switch

Conversation

@Aether-1013
Copy link

@Aether-1013Aether-1013 commentedNov 2, 2025
edited by coderabbitaibot
Loading

  • 增强ResetBannerImageCommand的错误处理和日志记录
  • 添加完整路径检查和备用恢复方案
  • 优化文件删除和默认图片恢复逻辑

Summary by CodeRabbit

发布说明

  • 新功能
    • 支持自定义首页横幅图片:右键点击横幅可打开文件对话框选择新图片
    • 添加重置横幅功能:用户可将横幅恢复为默认图片
    • 自定义图片会自动保存并在应用启动时加载

- 增强ResetBannerImageCommand的错误处理和日志记录- 添加完整路径检查和备用恢复方案- 优化文件删除和默认图片恢复逻辑
@coderabbitai
Copy link

coderabbitaibot commentedNov 2, 2025
edited
Loading

总体说明

此次变更为主页添加了横幅图像管理功能。通过在视图中添加右键菜单以支持更改或重置横幅图像,并在视图模型中实现相应的业务逻辑,包括图像初始化、文件选择和状态恢复。

变更详情

文件群组 / 文件变更摘要
UI 视图更新
BetterGenshinImpact/View/Pages/HomePage.xaml
为 Border 元素添加 ContextMenu,包含"更改横幅"和"重置横幅"两个菜单项;将横幅背景的 ImageSource 从静态资源切换为 BannerImageSource 数据绑定
视图模型业务逻辑
BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs
添加 BannerImageSource 可观察属性、InitializeBannerImage 初始化方法、ChangeBannerImage 文件选择命令及 ResetBannerImage 重置命令;包含完整的错误处理和用户反馈机制

流程图

sequenceDiagram    participant User    participant ContextMenu as 右键菜单    participant ViewModel as HomePageViewModel    participant FileDialog as 文件对话框    participant UI as 界面    User->>ContextMenu: 右键点击横幅    alt 更改横幅        ContextMenu->>ViewModel: 触发 ChangeBannerImageCommand        ViewModel->>FileDialog: 打开文件选择对话框        FileDialog-->>ViewModel: 返回选定的图像路径        ViewModel->>ViewModel: 复制图像到自定义路径        ViewModel->>ViewModel: 更新 BannerImageSource 属性        ViewModel->>UI: 刷新横幅显示    else 重置横幅        ContextMenu->>ViewModel: 触发 ResetBannerImageCommand        ViewModel->>ViewModel: 删除自定义图像        ViewModel->>ViewModel: 恢复 BannerImageSource 为默认值        ViewModel->>UI: 刷新横幅显示    end
Loading

代码审查工作量评估

🎯 3 (中等复杂度) | ⏱️ ~20-25 分钟

需要额外关注的区域:

  • ChangeBannerImage 方法中的文件 I/O 操作和异常处理逻辑
  • 自定义图像路径的配置(常量定义)和持久化机制
  • InitializeBannerImage 初始化的时序和构造函数中的调用顺序
  • 错误恢复路径的完整性验证(尤其是文件缺失的降级方案)

诗歌

🐰跳呀跳,新功能来到
横幅换装任意挑,菜单轻轻一点妙
图像闪闪亮,重置回原样
兔兔为你庆祝,代码又升了一个样! 🎨✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 0.00% which is insufficient. The required threshold is 80.00%.You can run@coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title Check✅ Passed标题"增加首页图片更换功能"(添加首页横幅图片更换功能)与本次变更的主要内容完全相符。变更内容包括在HomePage.xaml中添加上下文菜单用于改变和重置横幅图片,以及在HomePageViewModel.cs中添加相应的BannerImageSource属性和ChangeBannerImage、ResetBannerImage等命令来实现图片更换功能。标题简洁明确,准确反映了功能添加的核心目的,足以让团队成员快速理解主要变更内容。
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment@coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitaicoderabbitaibot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs (1)

523-640:建议提取图片加载逻辑到辅助方法

图片加载逻辑在多个地方重复(InitializeBannerImage、ChangeBannerImage、ResetBannerImage),建议提取为辅助方法以提高可维护性并确保加载模式的一致性。

示例重构:

privateImageSourceLoadImageFromUri(Uriuri){varbitmap=newBitmapImage();bitmap.BeginInit();bitmap.UriSource=uri;bitmap.CacheOption=BitmapCacheOption.OnLoad;bitmap.EndInit();returnbitmap;}

然后在各处使用:

BannerImageSource=LoadImageFromUri(newUri(path));
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and betweend14de17 and7b946d6.

📒 Files selected for processing (2)
  • BetterGenshinImpact/View/Pages/HomePage.xaml (2 hunks)
  • BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs (5 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs (1)
BetterGenshinImpact/View/PickerWindow.xaml.cs (1)
  • ImageSource (124-162)
🔇 Additional comments (4)
BetterGenshinImpact/View/Pages/HomePage.xaml (2)

29-34:右键菜单实现正确!

上下文菜单的实现合理,命令绑定正确,为用户提供了便捷的背景图片管理功能。


38-38:绑定实现正确!

ImageSource 正确绑定到视图模型的 BannerImageSource 属性,支持动态图片切换。

BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs (2)

79-83:属性和常量定义良好!

BannerImageSource 属性使用 ObservableProperty 正确声明,图片路径常量定义清晰合理。


616-638:备用恢复机制设计良好!

备用方案正确使用了BitmapCacheOption.OnLoad,双重异常处理提供了良好的容错能力。一旦主路径按照前面的建议修复,这个备用机制将进一步增强健壮性。

Comment on lines +525 to +547
privatevoidInitializeBannerImage()
{
try
{
// 检查是否存在自定义图片
if(File.Exists(CustomBannerImagePath))
{
BannerImageSource=newBitmapImage(newUri(Path.GetFullPath(CustomBannerImagePath)));
_logger.LogInformation("已加载自定义背景图片");
}
else
{
// 使用默认图片
BannerImageSource=newBitmapImage(newUri(DefaultBannerImagePath,UriKind.Absolute));
_logger.LogInformation("已加载默认背景图片");
}
}
catch(Exceptionex)
{
_logger.LogError(ex,"初始化背景图片失败,使用默认图片");
BannerImageSource=newBitmapImage(newUri(DefaultBannerImagePath,UriKind.Absolute));
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

⚠️ Potential issue |🔴 Critical

修复 BitmapImage 文件锁定问题

当前的图片加载方式会锁定文件句柄,导致无法删除或替换自定义图片。在 WPF 中加载图片时,应使用BitmapCacheOption.OnLoad 将图片加载到内存后立即释放文件句柄。

应用此修复:

 private void InitializeBannerImage() {     try     {         // 检查是否存在自定义图片         if (File.Exists(CustomBannerImagePath))         {-            BannerImageSource = new BitmapImage(new Uri(Path.GetFullPath(CustomBannerImagePath)));+            var bitmap = new BitmapImage();+            bitmap.BeginInit();+            bitmap.UriSource = new Uri(Path.GetFullPath(CustomBannerImagePath));+            bitmap.CacheOption = BitmapCacheOption.OnLoad;+            bitmap.EndInit();+            BannerImageSource = bitmap;             _logger.LogInformation("已加载自定义背景图片");         }         else         {             // 使用默认图片-            BannerImageSource = new BitmapImage(new Uri(DefaultBannerImagePath, UriKind.Absolute));+            var bitmap = new BitmapImage();+            bitmap.BeginInit();+            bitmap.UriSource = new Uri(DefaultBannerImagePath, UriKind.Absolute);+            bitmap.CacheOption = BitmapCacheOption.OnLoad;+            bitmap.EndInit();+            BannerImageSource = bitmap;             _logger.LogInformation("已加载默认背景图片");         }     }     catch (Exception ex)     {         _logger.LogError(ex, "初始化背景图片失败,使用默认图片");-        BannerImageSource = new BitmapImage(new Uri(DefaultBannerImagePath, UriKind.Absolute));+        var bitmap = new BitmapImage();+        bitmap.BeginInit();+        bitmap.UriSource = new Uri(DefaultBannerImagePath, UriKind.Absolute);+        bitmap.CacheOption = BitmapCacheOption.OnLoad;+        bitmap.EndInit();+        BannerImageSource = bitmap;     } }
🤖 Prompt for AI Agents
In BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs around lines525-547, the BitmapImage is created directly from a file URI which leaves thefile handle open; change the custom-image loading to open a FileStream, callBitmapImage.BeginInit(), set BitmapCacheOption.OnLoad, set StreamSource to theFileStream (or use a MemoryStream), call EndInit(), then close/dispose theFileStream and call Freeze() on the BitmapImage so the file handle is releasedand the image is immutable; keep the default-image path creation as-is but applyFreeze() after initialization for consistency.

Comment on lines +549 to +589
[RelayCommand]
privatevoidChangeBannerImage()
{
try
{
varopenFileDialog=newOpenFileDialog
{
Title="选择背景图片",
Filter="图片文件|*.jpg;*.jpeg;*.png;*.bmp;*.gif|所有文件|*.*",
Multiselect=false
};

if(openFileDialog.ShowDialog()==true)
{
varselectedFile=openFileDialog.FileName;
_logger.LogInformation("用户选择了图片: {ImagePath}",selectedFile);

// 确保目标目录存在
vardirectory=Path.GetDirectoryName(CustomBannerImagePath);
if(!string.IsNullOrEmpty(directory)&&!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
_logger.LogInformation("创建了自定义图片目录: {Directory}",directory);
}

// 复制图片到自定义路径
File.Copy(selectedFile,CustomBannerImagePath,true);
_logger.LogInformation("图片已复制到: {CustomPath}",CustomBannerImagePath);

// 更新UI
BannerImageSource=newBitmapImage(newUri(Path.GetFullPath(CustomBannerImagePath)));
Toast.Success("背景图片更换成功!");
_logger.LogInformation("背景图片更换成功");
}
}
catch(Exceptionex)
{
_logger.LogError(ex,"更换背景图片失败");
Toast.Error($"更换背景图片失败:{ex.Message}");
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

⚠️ Potential issue |🔴 Critical

修复文件复制和图片加载的文件锁定问题

存在两个问题:

  1. 第 579 行创建 BitmapImage 时未使用BitmapCacheOption.OnLoad,会锁定新图片文件
  2. 第 575 行复制文件时,如果旧的自定义图片正被BannerImageSource 锁定,复制操作会失败

应用此修复:

 [RelayCommand] private void ChangeBannerImage() {     try     {         var openFileDialog = new OpenFileDialog         {             Title = "选择背景图片",             Filter = "图片文件|*.jpg;*.jpeg;*.png;*.bmp;*.gif|所有文件|*.*",             Multiselect = false         };          if (openFileDialog.ShowDialog() == true)         {             var selectedFile = openFileDialog.FileName;             _logger.LogInformation("用户选择了图片: {ImagePath}", selectedFile);              // 确保目标目录存在             var directory = Path.GetDirectoryName(CustomBannerImagePath);             if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))             {                 Directory.CreateDirectory(directory);                 _logger.LogInformation("创建了自定义图片目录: {Directory}", directory);             }+            // 先释放当前图片的文件锁,切换到默认图片+            if (File.Exists(Path.GetFullPath(CustomBannerImagePath)))+            {+                var tempBitmap = new BitmapImage();+                tempBitmap.BeginInit();+                tempBitmap.UriSource = new Uri(DefaultBannerImagePath, UriKind.Absolute);+                tempBitmap.CacheOption = BitmapCacheOption.OnLoad;+                tempBitmap.EndInit();+                BannerImageSource = tempBitmap;+            }+             // 复制图片到自定义路径             File.Copy(selectedFile, CustomBannerImagePath, true);             _logger.LogInformation("图片已复制到: {CustomPath}", CustomBannerImagePath);              // 更新UI-            BannerImageSource = new BitmapImage(new Uri(Path.GetFullPath(CustomBannerImagePath)));+            var bitmap = new BitmapImage();+            bitmap.BeginInit();+            bitmap.UriSource = new Uri(Path.GetFullPath(CustomBannerImagePath));+            bitmap.CacheOption = BitmapCacheOption.OnLoad;+            bitmap.EndInit();+            BannerImageSource = bitmap;             Toast.Success("背景图片更换成功!");             _logger.LogInformation("背景图片更换成功");         }     }     catch (Exception ex)     {         _logger.LogError(ex, "更换背景图片失败");         Toast.Error($"更换背景图片失败: {ex.Message}");     } }
📝 Committable suggestion

‼️IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
[RelayCommand]
privatevoidChangeBannerImage()
{
try
{
varopenFileDialog=newOpenFileDialog
{
Title="选择背景图片",
Filter="图片文件|*.jpg;*.jpeg;*.png;*.bmp;*.gif|所有文件|*.*",
Multiselect=false
};
if(openFileDialog.ShowDialog()==true)
{
varselectedFile=openFileDialog.FileName;
_logger.LogInformation("用户选择了图片: {ImagePath}",selectedFile);
// 确保目标目录存在
vardirectory=Path.GetDirectoryName(CustomBannerImagePath);
if(!string.IsNullOrEmpty(directory)&&!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
_logger.LogInformation("创建了自定义图片目录: {Directory}",directory);
}
// 复制图片到自定义路径
File.Copy(selectedFile,CustomBannerImagePath,true);
_logger.LogInformation("图片已复制到: {CustomPath}",CustomBannerImagePath);
// 更新UI
BannerImageSource=newBitmapImage(newUri(Path.GetFullPath(CustomBannerImagePath)));
Toast.Success("背景图片更换成功!");
_logger.LogInformation("背景图片更换成功");
}
}
catch(Exceptionex)
{
_logger.LogError(ex,"更换背景图片失败");
Toast.Error($"更换背景图片失败:{ex.Message}");
}
}
[RelayCommand]
privatevoidChangeBannerImage()
{
try
{
varopenFileDialog=newOpenFileDialog
{
Title="选择背景图片",
Filter="图片文件|*.jpg;*.jpeg;*.png;*.bmp;*.gif|所有文件|*.*",
Multiselect=false
};
if(openFileDialog.ShowDialog()==true)
{
varselectedFile=openFileDialog.FileName;
_logger.LogInformation("用户选择了图片: {ImagePath}",selectedFile);
// 确保目标目录存在
vardirectory=Path.GetDirectoryName(CustomBannerImagePath);
if(!string.IsNullOrEmpty(directory)&&!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
_logger.LogInformation("创建了自定义图片目录: {Directory}",directory);
}
// 先释放当前图片的文件锁,切换到默认图片
if(File.Exists(Path.GetFullPath(CustomBannerImagePath)))
{
vartempBitmap=newBitmapImage();
tempBitmap.BeginInit();
tempBitmap.UriSource=newUri(DefaultBannerImagePath,UriKind.Absolute);
tempBitmap.CacheOption=BitmapCacheOption.OnLoad;
tempBitmap.EndInit();
BannerImageSource=tempBitmap;
}
// 复制图片到自定义路径
File.Copy(selectedFile,CustomBannerImagePath,true);
_logger.LogInformation("图片已复制到: {CustomPath}",CustomBannerImagePath);
// 更新UI
varbitmap=newBitmapImage();
bitmap.BeginInit();
bitmap.UriSource=newUri(Path.GetFullPath(CustomBannerImagePath));
bitmap.CacheOption=BitmapCacheOption.OnLoad;
bitmap.EndInit();
BannerImageSource=bitmap;
Toast.Success("背景图片更换成功!");
_logger.LogInformation("背景图片更换成功");
}
}
catch(Exceptionex)
{
_logger.LogError(ex,"更换背景图片失败");
Toast.Error($"更换背景图片失败:{ex.Message}");
}
}

Comment on lines +591 to +615
[RelayCommand]
privatevoidResetBannerImage()
{
try
{
// 获取自定义图片的完整路径
varcustomImageFullPath=Path.GetFullPath(CustomBannerImagePath);
_logger.LogInformation("尝试恢复默认背景图片,自定义图片路径: {CustomPath}",customImageFullPath);

if(File.Exists(customImageFullPath))
{
File.Delete(customImageFullPath);
_logger.LogInformation("已删除自定义背景图片: {CustomPath}",customImageFullPath);
}
else
{
_logger.LogInformation("自定义背景图片不存在: {CustomPath}",customImageFullPath);
}

// 恢复为默认图片
_logger.LogInformation("正在恢复为默认背景图片,默认路径: {DefaultPath}",DefaultBannerImagePath);
BannerImageSource=newBitmapImage(newUri(DefaultBannerImagePath,UriKind.Absolute));
Toast.Success("已恢复为默认背景图片!");
_logger.LogInformation("背景图片已恢复为默认");
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

⚠️ Potential issue |🔴 Critical

修复恢复默认图片时的文件锁定和一致性问题

存在两个问题:

  1. 第 612 行创建 BitmapImage 未使用BitmapCacheOption.OnLoad,与备用方案(第 623-627 行)不一致
  2. 第 602 行删除文件前,需要先释放当前BannerImageSource 对该文件的锁定

应用此修复:

 [RelayCommand] private void ResetBannerImage() {     try     {         // 获取自定义图片的完整路径         var customImageFullPath = Path.GetFullPath(CustomBannerImagePath);         _logger.LogInformation("尝试恢复默认背景图片,自定义图片路径: {CustomPath}", customImageFullPath);+        // 先切换到默认图片,释放自定义图片的文件锁+        var defaultBitmap = new BitmapImage();+        defaultBitmap.BeginInit();+        defaultBitmap.UriSource = new Uri(DefaultBannerImagePath, UriKind.Absolute);+        defaultBitmap.CacheOption = BitmapCacheOption.OnLoad;+        defaultBitmap.EndInit();+        BannerImageSource = defaultBitmap;+        _logger.LogInformation("已切换到默认背景图片");+         if (File.Exists(customImageFullPath))         {             File.Delete(customImageFullPath);             _logger.LogInformation("已删除自定义背景图片: {CustomPath}", customImageFullPath);         }         else         {             _logger.LogInformation("自定义背景图片不存在: {CustomPath}", customImageFullPath);         }-        // 恢复为默认图片-        _logger.LogInformation("正在恢复为默认背景图片,默认路径: {DefaultPath}", DefaultBannerImagePath);-        BannerImageSource = new BitmapImage(new Uri(DefaultBannerImagePath, UriKind.Absolute));         Toast.Success("已恢复为默认背景图片!");         _logger.LogInformation("背景图片已恢复为默认");     }
📝 Committable suggestion

‼️IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
[RelayCommand]
privatevoidResetBannerImage()
{
try
{
// 获取自定义图片的完整路径
varcustomImageFullPath=Path.GetFullPath(CustomBannerImagePath);
_logger.LogInformation("尝试恢复默认背景图片,自定义图片路径: {CustomPath}",customImageFullPath);
if(File.Exists(customImageFullPath))
{
File.Delete(customImageFullPath);
_logger.LogInformation("已删除自定义背景图片: {CustomPath}",customImageFullPath);
}
else
{
_logger.LogInformation("自定义背景图片不存在: {CustomPath}",customImageFullPath);
}
// 恢复为默认图片
_logger.LogInformation("正在恢复为默认背景图片,默认路径: {DefaultPath}",DefaultBannerImagePath);
BannerImageSource=newBitmapImage(newUri(DefaultBannerImagePath,UriKind.Absolute));
Toast.Success("已恢复为默认背景图片!");
_logger.LogInformation("背景图片已恢复为默认");
}
[RelayCommand]
privatevoidResetBannerImage()
{
try
{
// 获取自定义图片的完整路径
varcustomImageFullPath=Path.GetFullPath(CustomBannerImagePath);
_logger.LogInformation("尝试恢复默认背景图片,自定义图片路径: {CustomPath}",customImageFullPath);
// 先切换到默认图片,释放自定义图片的文件锁
vardefaultBitmap=newBitmapImage();
defaultBitmap.BeginInit();
defaultBitmap.UriSource=newUri(DefaultBannerImagePath,UriKind.Absolute);
defaultBitmap.CacheOption=BitmapCacheOption.OnLoad;
defaultBitmap.EndInit();
BannerImageSource=defaultBitmap;
_logger.LogInformation("已切换到默认背景图片");
if(File.Exists(customImageFullPath))
{
File.Delete(customImageFullPath);
_logger.LogInformation("已删除自定义背景图片: {CustomPath}",customImageFullPath);
}
else
{
_logger.LogInformation("自定义背景图片不存在: {CustomPath}",customImageFullPath);
}
Toast.Success("已恢复为默认背景图片!");
_logger.LogInformation("背景图片已恢复为默认");
}

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

@coderabbitaicoderabbitai[bot]coderabbitai[bot] left review comments

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

1 participant

@Aether-1013

[8]ページ先頭

©2009-2025 Movatter.jp