更新任务选择窗口,调整任务添加逻辑,支持单个任务选择和目录结构保持

This commit is contained in:
辉鸭蛋
2025-09-08 00:32:52 +08:00
parent df062088fc
commit 6f70ebc4c4
3 changed files with 183 additions and 181 deletions

View File

@@ -32,17 +32,18 @@ public partial class PathingTaskSelectionWindow : FluentWindow
/// 选中的任务
/// </summary>
public PathingTaskInfo? SelectedTask { get; private set; }
/// <summary>
/// 选中的任务
/// </summary>
public GearTaskViewModel? SelectedGearTask { get; private set; }
/// <summary>
/// 对话框结果
/// </summary>
public bool DialogResult { get; private set; }
/// <summary>
/// 添加的任务列表
/// </summary>
public List<GearTaskViewModel> AddedTasks { get; private set; } = new();
/// <summary>
/// 目录到符号图标的转换器
/// </summary>
@@ -64,10 +65,10 @@ public partial class PathingTaskSelectionWindow : FluentWindow
/// <summary>
/// 任务添加事件处理
/// </summary>
private void OnTaskAdded(List<GearTaskViewModel> tasks)
private void OnTaskAdded(GearTaskViewModel? task)
{
AddedTasks.AddRange(tasks);
SelectedGearTask = task;
// 添加任务后自动关闭窗口
CloseWithResult();
}
@@ -185,101 +186,101 @@ public class NullToVisibilityConverter : IValueConverter
}
}
/// <summary>
/// 字符串到ImageSource的转换器处理空字符串情况支持WebP格式
/// </summary>
public class StringToImageSourceConverter : IValueConverter
{
private static readonly HttpClient HttpClient = new();
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is string url && !string.IsNullOrEmpty(url))
{
try
{
// 检查是否为WebP格式或其他需要特殊处理的格式
if (url.Contains(".webp", StringComparison.OrdinalIgnoreCase))
{
return LoadWebPImage(url);
}
else
{
// 对于其他格式使用原有的BitmapImage
return new BitmapImage(new Uri(url));
}
}
catch (Exception e)
{
Debug.WriteLine(e);
return null;
}
}
return null;
}
private static BitmapSource? LoadWebPImage(string url)
{
try
{
byte[] imageData;
if (url.StartsWith("http", StringComparison.OrdinalIgnoreCase))
{
// 从网络加载
imageData = HttpClient.GetByteArrayAsync(url).Result;
}
else
{
// 从本地文件加载
imageData = File.ReadAllBytes(url);
}
using var image = Image.Load<Rgba32>(imageData);
// 转换为WPF可用的BitmapSource
var bitmap = new WriteableBitmap(image.Width, image.Height, 96, 96, PixelFormats.Bgra32, null);
bitmap.Lock();
try
{
var backBuffer = bitmap.BackBuffer;
var stride = bitmap.BackBufferStride;
image.ProcessPixelRows(accessor =>
{
for (int y = 0; y < accessor.Height; y++)
{
var pixelRow = accessor.GetRowSpan(y);
var targetPtr = backBuffer + y * stride;
for (int x = 0; x < pixelRow.Length; x++)
{
var pixel = pixelRow[x];
// 转换RGBA到BGRA
var bgra = (pixel.A << 24) | (pixel.R << 16) | (pixel.G << 8) | pixel.B;
System.Runtime.InteropServices.Marshal.WriteInt32(targetPtr + x * 4, bgra);
}
}
});
}
finally
{
bitmap.AddDirtyRect(new Int32Rect(0, 0, image.Width, image.Height));
bitmap.Unlock();
}
return bitmap;
}
catch (Exception e)
{
Debug.WriteLine($"Failed to load WebP image: {e}");
return null;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
// /// <summary>
// /// 字符串到ImageSource的转换器处理空字符串情况支持WebP格式
// /// </summary>
// public class StringToImageSourceConverter : IValueConverter
// {
// private static readonly HttpClient HttpClient = new();
//
// public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
// {
// if (value is string url && !string.IsNullOrEmpty(url))
// {
// try
// {
// // 检查是否为WebP格式或其他需要特殊处理的格式
// if (url.Contains(".webp", StringComparison.OrdinalIgnoreCase))
// {
// return LoadWebPImage(url);
// }
// else
// {
// // 对于其他格式使用原有的BitmapImage
// return new BitmapImage(new Uri(url));
// }
// }
// catch (Exception e)
// {
// Debug.WriteLine(e);
// return null;
// }
// }
// return null;
// }
//
// private static BitmapSource? LoadWebPImage(string url)
// {
// try
// {
// byte[] imageData;
//
// if (url.StartsWith("http", StringComparison.OrdinalIgnoreCase))
// {
// // 从网络加载
// imageData = HttpClient.GetByteArrayAsync(url).Result;
// }
// else
// {
// // 从本地文件加载
// imageData = File.ReadAllBytes(url);
// }
//
// using var image = Image.Load<Rgba32>(imageData);
//
// // 转换为WPF可用的BitmapSource
// var bitmap = new WriteableBitmap(image.Width, image.Height, 96, 96, PixelFormats.Bgra32, null);
//
// bitmap.Lock();
// try
// {
// var backBuffer = bitmap.BackBuffer;
// var stride = bitmap.BackBufferStride;
//
// image.ProcessPixelRows(accessor =>
// {
// for (int y = 0; y < accessor.Height; y++)
// {
// var pixelRow = accessor.GetRowSpan(y);
// var targetPtr = backBuffer + y * stride;
//
// for (int x = 0; x < pixelRow.Length; x++)
// {
// var pixel = pixelRow[x];
// // 转换RGBA到BGRA
// var bgra = (pixel.A << 24) | (pixel.R << 16) | (pixel.G << 8) | pixel.B;
// System.Runtime.InteropServices.Marshal.WriteInt32(targetPtr + x * 4, bgra);
// }
// }
// });
// }
// finally
// {
// bitmap.AddDirtyRect(new Int32Rect(0, 0, image.Width, image.Height));
// bitmap.Unlock();
// }
//
// return bitmap;
// }
// catch (Exception e)
// {
// Debug.WriteLine($"Failed to load WebP image: {e}");
// return null;
// }
// }
//
// public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
// {
// throw new NotImplementedException();
// }
// }

View File

@@ -371,14 +371,9 @@ public partial class GearTaskListPageViewModel : ViewModel
pathingSelectionWindow.ShowDialog();
if (pathingSelectionWindow.DialogResult && pathingSelectionWindow.SelectedTask != null)
if (pathingSelectionWindow.DialogResult && pathingSelectionWindow.SelectedGearTask != null)
{
var selectedTask = pathingSelectionWindow.SelectedTask;
newTask = new GearTaskViewModel(selectedTask.Name)
{
TaskType = "Pathing",
Path = selectedTask.RelativePath
};
newTask = pathingSelectionWindow.SelectedGearTask;
}
else
{

View File

@@ -71,7 +71,7 @@ public partial class PathingTaskSelectionViewModel : ViewModel
LoadPathingTasks();
}
public Action<List<GearTaskViewModel>>? OnTaskAdded { get; set; }
public Action<GearTaskViewModel?>? OnTaskAdded { get; set; }
// /// <summary>
// /// 加载图标字典
@@ -415,7 +415,7 @@ public partial class PathingTaskSelectionViewModel : ViewModel
};
// 触发添加事件或通过其他方式返回给调用方
OnTaskAdded?.Invoke([gearTaskViewModel]);
OnTaskAdded?.Invoke(gearTaskViewModel);
}
}
@@ -427,8 +427,8 @@ public partial class PathingTaskSelectionViewModel : ViewModel
{
if (SelectedTask?.IsDirectory == true)
{
var tasks = GetAllFolderTasksInDirectoryWithStructure(SelectedTask);
OnTaskAdded?.Invoke(tasks);
var task = GetAllFolderTasksInDirectoryWithStructure(SelectedTask);
OnTaskAdded?.Invoke(task);
}
}
@@ -440,23 +440,29 @@ public partial class PathingTaskSelectionViewModel : ViewModel
{
if (SelectedTask?.IsDirectory == true)
{
var rootGearTaskViewModel = new GearTaskViewModel
{
Name = SelectedTask.Name,
IsDirectory = true
};
// 逐个添加添加目录下所有JSON文件作为独立任务
var taskInfos = GetAllJsonFilesInDirectory(SelectedTask);
var tasks = new List<GearTaskViewModel>();
foreach (var taskInfo in taskInfos)
{
var gearTaskViewModel = new GearTaskViewModel
{
Name = Path.GetFileNameWithoutExtension(taskInfo.Name),
TaskType = "Pathing",
Path = @$"{{pathingRepoFolder}}\{taskInfo.RelativePath}\",
IsDirectory = false
};
tasks.Add(gearTaskViewModel);
rootGearTaskViewModel.Children.Add(gearTaskViewModel);
}
if (tasks.Count > 0)
if (rootGearTaskViewModel.Children.Count > 0)
{
OnTaskAdded?.Invoke(tasks);
OnTaskAdded?.Invoke(rootGearTaskViewModel);
}
}
}
@@ -470,8 +476,8 @@ public partial class PathingTaskSelectionViewModel : ViewModel
if (SelectedTask?.IsDirectory == true)
{
// 保持目录结构添加所有子任务
var tasks = GetAllFileTasksInDirectoryWithStructure(SelectedTask);
OnTaskAdded?.Invoke(tasks);
var task = GetAllFileTasksInDirectoryWithStructure(SelectedTask);
OnTaskAdded?.Invoke(task);
}
}
@@ -504,88 +510,88 @@ public partial class PathingTaskSelectionViewModel : ViewModel
/// <summary>
/// 获取目录下所有json文件任务并保持结构
/// </summary>
private List<GearTaskViewModel> GetAllFileTasksInDirectoryWithStructure(PathingTaskInfo directory)
private GearTaskViewModel? GetAllFileTasksInDirectoryWithStructure(PathingTaskInfo node)
{
var tasks = new List<GearTaskViewModel>();
if (directory.Children is { Count: > 0 })
if (node.IsDirectory)
{
foreach (var child in directory.Children)
// 添加子目录作为组
var groupTask = new GearTaskViewModel
{
if (child.IsDirectory)
{
// 添加子目录作为组
var groupTask = new GearTaskViewModel
{
Name = child.Name,
IsDirectory = true
};
tasks.Add(groupTask);
Name = node.Name,
IsDirectory = true
};
// 递归添加子任务
tasks.AddRange(GetAllFileTasksInDirectoryWithStructure(child));
}
else if (child.FullPath.EndsWith(".json", StringComparison.OrdinalIgnoreCase))
foreach (var pathingTaskInfo in node.Children)
{
var gearTask = GetAllFileTasksInDirectoryWithStructure(pathingTaskInfo);
if (gearTask != null)
{
// 添加JSON文件作为任务
var fileTask = new GearTaskViewModel
{
Name = Path.GetFileNameWithoutExtension(child.Name),
Path = @$"{{pathingRepoFolder}}\{child.RelativePath}\",
IsDirectory = false
};
tasks.Add(fileTask);
groupTask.Children.Add(gearTask);
}
}
return groupTask;
}
else if (node.FullPath.EndsWith(".json", StringComparison.OrdinalIgnoreCase))
{
// 添加JSON文件作为任务
var fileTask = new GearTaskViewModel
{
Name = Path.GetFileNameWithoutExtension(node.Name),
TaskType = "Pathing",
Path = @$"{{pathingRepoFolder}}\{node.RelativePath}\",
IsDirectory = false
};
return fileTask;
}
return tasks;
return null;
}
/// <summary>
/// 获取目录下所有文件夹任务并保持结构
/// </summary>
private List<GearTaskViewModel> GetAllFolderTasksInDirectoryWithStructure(PathingTaskInfo directory)
private GearTaskViewModel? GetAllFolderTasksInDirectoryWithStructure(PathingTaskInfo directory)
{
var tasks = new List<GearTaskViewModel>();
if (directory.Children is { Count: > 0 })
{
foreach (var child in directory.Children)
// 判断 directory 的子节点是否是文件
var hasJsonFile = directory.Children.Any(grandChild => !grandChild.IsDirectory && grandChild.FullPath.EndsWith(".json", StringComparison.OrdinalIgnoreCase));
if (hasJsonFile)
{
if (child.IsDirectory)
// 添加子目录作为任务
var groupTask = new GearTaskViewModel
{
// 判断 child 的子节点是否是文件
var hasJsonFile = child.Children.Any(grandChild => !grandChild.IsDirectory && grandChild.FullPath.EndsWith(".json", StringComparison.OrdinalIgnoreCase));
if (hasJsonFile)
Name = directory.Name,
TaskType = "Pathing",
Path = @$"{{pathingRepoFolder}}\{directory.RelativePath}\",
IsDirectory = false
};
return groupTask;
}
else
{
// 添加子目录作为组
var groupTask = new GearTaskViewModel
{
Name = directory.Name,
IsDirectory = true
};
foreach (var pathingTaskInfo in directory.Children)
{
var gearTask = GetAllFolderTasksInDirectoryWithStructure(pathingTaskInfo);
if (gearTask != null)
{
// 添加子目录作为任务
var groupTask = new GearTaskViewModel
{
Name = child.Name,
TaskType = "Pathing",
Path = @$"{{pathingRepoFolder}}\{child.RelativePath}\",
IsDirectory = false
};
tasks.Add(groupTask);
}
else
{
// 添加子目录作为组
var groupTask = new GearTaskViewModel
{
Name = child.Name,
IsDirectory = true
};
tasks.Add(groupTask);
// 递归添加子任务
tasks.AddRange(GetAllFolderTasksInDirectoryWithStructure(child));
groupTask.Children.Add(gearTask);
}
}
return groupTask;
}
}
return tasks;
else
{
return null;
}
}
}