新增窗口

This commit is contained in:
辉鸭蛋
2025-09-06 20:43:00 +08:00
parent ec63a803b5
commit 348fe9494c
6 changed files with 252 additions and 42 deletions

View File

@@ -17,9 +17,11 @@ using BetterGenshinImpact.Service.Notification;
using BetterGenshinImpact.Service.Notifier;
using BetterGenshinImpact.View;
using BetterGenshinImpact.View.Pages;
using BetterGenshinImpact.View.Windows;
using BetterGenshinImpact.ViewModel;
using BetterGenshinImpact.ViewModel.Pages;
using BetterGenshinImpact.ViewModel.Pages.View;
using BetterGenshinImpact.ViewModel.Windows;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
@@ -114,6 +116,8 @@ public partial class App : Application
services.AddView<SchedulerPage, SchedulerViewModel>();
services.AddView<GearTaskListPage, GearTaskListPageViewModel>();
services.AddView<GearTriggerPage, GearTriggerPageViewModel>();
services.AddTransient<TaskDefinitionEditWindow>();
services.AddTransient<TaskDefinitionEditWindowViewModel>();
// 一条龙 ViewModels

View File

@@ -134,13 +134,6 @@
Content="新建"
Icon="{ui:SymbolIcon Add24}"
Margin="0,0,4,0" />
<ui:Button Command="{Binding SaveToJsonCommand}"
Content="保存"
Icon="{ui:SymbolIcon Save24}"
Margin="0,0,4,0" />
<ui:Button Command="{Binding LoadFromJsonCommand}"
Content="加载"
Icon="{ui:SymbolIcon Open24}" />
</StackPanel>
<!-- 任务定义列表 -->
@@ -159,6 +152,20 @@
dd:DragDrop.DropHandler="{Binding}"
dd:DragDrop.UseDefaultDragAdorner="True"
Padding="4">
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Header="新增任务定义"
Command="{Binding AddTaskDefinitionCommand}"
Icon="{ui:SymbolIcon Add24}" />
<Separator />
<MenuItem Header="编辑选中项"
Command="{Binding EditSelectedTaskDefinitionCommand}"
Icon="{ui:SymbolIcon Edit24}" />
<MenuItem Header="删除选中项"
Command="{Binding DeleteSelectedTaskDefinitionCommand}"
Icon="{ui:SymbolIcon Delete24}" />
</ContextMenu>
</ListBox.ContextMenu>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />

View File

@@ -0,0 +1,73 @@
<ui:FluentWindow x:Class="BetterGenshinImpact.View.Windows.TaskDefinitionEditWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
Width="450"
Height="280"
MinWidth="400"
MinHeight="250"
ui:Design.Background="{DynamicResource ApplicationBackgroundBrush}"
ui:Design.Foreground="{DynamicResource TextFillColorPrimaryBrush}"
ExtendsContentIntoTitleBar="True"
FontFamily="{DynamicResource TextThemeFontFamily}"
WindowStartupLocation="CenterOwner"
WindowStyle="SingleBorderWindow">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- 内容部分 -->
<Grid Grid.Row="1" Margin="12,12,12,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- 名称输入 -->
<StackPanel Grid.Row="0" Margin="5,5,5,15">
<ui:TextBlock Text="名称:" Margin="0,0,0,5" FontWeight="Medium" />
<ui:TextBox x:Name="NameTextBox"
Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"
PlaceholderText="请输入任务定义名称" />
</StackPanel>
<!-- 描述输入 -->
<StackPanel Grid.Row="1" Margin="5,0,5,5">
<ui:TextBlock Text="描述:" Margin="0,0,0,5" FontWeight="Medium" />
<ui:TextBox Text="{Binding Description, UpdateSourceTrigger=PropertyChanged}"
PlaceholderText="请输入任务定义描述(可选)" />
</StackPanel>
</Grid>
<!-- 按钮部分 -->
<Grid Grid.Row="2" Margin="12">
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
<ui:Button Name="BtnOk"
Margin="5"
Appearance="Primary"
Command="{Binding ConfirmCommand}"
Content="确定"
IsDefault="True"
MinWidth="80" />
<ui:Button Name="BtnCancel"
Margin="5"
Command="{Binding CancelCommand}"
Content="取消"
IsCancel="True"
MinWidth="80" />
</StackPanel>
</Grid>
<!-- 标题栏 -->
<ui:TitleBar Name="MyTitleBar" Grid.Row="0" Title="任务定义编辑">
<ui:TitleBar.Icon>
<ui:ImageIcon Source="pack://application:,,,/Resources/Images/logo.png" />
</ui:TitleBar.Icon>
</ui:TitleBar>
</Grid>
</ui:FluentWindow>

View File

@@ -0,0 +1,42 @@
using BetterGenshinImpact.Helpers.Ui;
using BetterGenshinImpact.ViewModel.Windows;
using System;
using System.Windows;
using Wpf.Ui.Controls;
namespace BetterGenshinImpact.View.Windows;
public partial class TaskDefinitionEditWindow : FluentWindow
{
public TaskDefinitionEditWindowViewModel ViewModel { get; }
public TaskDefinitionEditWindow(TaskDefinitionEditWindowViewModel viewModel)
{
ViewModel = viewModel;
DataContext = viewModel;
InitializeComponent();
// 设置窗口关闭事件
ViewModel.RequestClose += (sender, result) =>
{
DialogResult = result;
Close();
};
// 窗口加载和初始化事件
this.Loaded += TaskDefinitionEditWindowLoaded;
this.SourceInitialized += TaskDefinitionEditWindow_SourceInitialized;
}
private void TaskDefinitionEditWindow_SourceInitialized(object? sender, EventArgs e)
{
// 应用与主窗口相同的背景主题
WindowHelper.TryApplySystemBackdrop(this);
}
private void TaskDefinitionEditWindowLoaded(object sender, RoutedEventArgs e)
{
// 自动聚焦到名称输入框
NameTextBox.Focus();
}
}

View File

@@ -14,6 +14,9 @@ using BetterGenshinImpact.Service;
using System.Threading.Tasks;
using System.Collections.Specialized;
using GongSolutions.Wpf.DragDrop;
using BetterGenshinImpact.View.Windows;
using BetterGenshinImpact.ViewModel.Windows;
using Microsoft.Extensions.DependencyInjection;
namespace BetterGenshinImpact.ViewModel.Pages;
@@ -214,15 +217,31 @@ public partial class GearTaskListPageViewModel : ViewModel
[RelayCommand]
private async Task AddTaskDefinition()
{
var newTask = new GearTaskDefinitionViewModel($"新任务组 {TaskDefinitions.Count + 1}", "新创建的任务组");
// 设置新任务的order为当前最大值+1
newTask.Order = TaskDefinitions.Count > 0 ? TaskDefinitions.Max(t => t.Order) + 1 : 0;
TaskDefinitions.Add(newTask);
SetupTaskDefinitionPropertyChanged(newTask);
SelectedTaskDefinition = newTask;
var editViewModel = App.GetService<TaskDefinitionEditWindowViewModel>();
if (editViewModel == null) return;
// 自动保存到文件
await _storageService.SaveTaskDefinitionAsync(newTask);
editViewModel.Name = $"新任务组{TaskDefinitions.Count + 1}";
editViewModel.Description = "";
var editWindow = App.GetService<TaskDefinitionEditWindow>();
if (editWindow == null) return;
editWindow.ViewModel.Name = editViewModel.Name;
editWindow.ViewModel.Description = editViewModel.Description;
editWindow.Owner = Application.Current.MainWindow;
if (editWindow.ShowDialog() == true)
{
var newTask = new GearTaskDefinitionViewModel(editWindow.ViewModel.Name, editWindow.ViewModel.Description);
// 设置新任务的order为当前最大值+1
newTask.Order = TaskDefinitions.Count > 0 ? TaskDefinitions.Max(t => t.Order) + 1 : 0;
TaskDefinitions.Add(newTask);
SetupTaskDefinitionPropertyChanged(newTask);
SelectedTaskDefinition = newTask;
// 自动保存到文件
await _storageService.SaveTaskDefinitionAsync(newTask);
}
}
/// <summary>
@@ -250,6 +269,51 @@ public partial class GearTaskListPageViewModel : ViewModel
}
}
/// <summary>
/// 编辑选中的任务定义
/// </summary>
[RelayCommand]
private async Task EditSelectedTaskDefinition()
{
if (SelectedTaskDefinition == null) return;
var editViewModel = App.GetService<TaskDefinitionEditWindowViewModel>();
if (editViewModel == null) return;
editViewModel.Name = SelectedTaskDefinition.Name;
editViewModel.Description = SelectedTaskDefinition.Description;
var editWindow = App.GetService<TaskDefinitionEditWindow>();
if (editWindow == null) return;
editWindow.ViewModel.Name = editViewModel.Name;
editWindow.ViewModel.Description = editViewModel.Description;
editWindow.Owner = Application.Current.MainWindow;
if (editWindow.ShowDialog() == true)
{
SelectedTaskDefinition.Name = editWindow.ViewModel.Name;
SelectedTaskDefinition.Description = editWindow.ViewModel.Description;
SelectedTaskDefinition.ModifiedTime = DateTime.Now;
// 自动保存到文件
await _storageService.SaveTaskDefinitionAsync(SelectedTaskDefinition);
_logger.LogInformation("编辑了任务定义: {Name}", SelectedTaskDefinition.Name);
}
}
/// <summary>
/// 删除选中的任务定义
/// </summary>
[RelayCommand]
private async Task DeleteSelectedTaskDefinition()
{
if (SelectedTaskDefinition == null) return;
await DeleteTaskDefinition(SelectedTaskDefinition);
}
/// <summary>
/// 重命名任务定义
/// </summary>
@@ -375,32 +439,9 @@ public partial class GearTaskListPageViewModel : ViewModel
}
/// <summary>
/// 保存所有任务定义到JSON文件
/// 从JSON文件重新加载所有任务定义内部使用
/// </summary>
[RelayCommand]
private async Task SaveToJson()
{
try
{
foreach (var taskDefinition in TaskDefinitions)
{
await _storageService.SaveTaskDefinitionAsync(taskDefinition);
}
_logger.LogInformation("所有任务定义已保存到JSON文件");
MessageBox.Show("保存成功!", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (Exception ex)
{
_logger.LogError(ex, "保存任务定义到JSON文件时发生错误");
MessageBox.Show($"保存失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
/// <summary>
/// 从JSON文件重新加载所有任务定义
/// </summary>
[RelayCommand]
private async Task LoadFromJson()
private async Task LoadFromJsonInternal()
{
try
{
@@ -414,12 +455,10 @@ public partial class GearTaskListPageViewModel : ViewModel
}
_logger.LogInformation("从JSON文件重新加载了 {Count} 个任务定义", loadedTasks.Count);
MessageBox.Show($"加载成功!共加载 {loadedTasks.Count} 个任务定义", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (Exception ex)
{
_logger.LogError(ex, "从JSON文件加载任务定义时发生错误");
MessageBox.Show($"加载失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
}
}

View File

@@ -0,0 +1,45 @@
using System;
using System.ComponentModel.DataAnnotations;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
namespace BetterGenshinImpact.ViewModel.Windows;
public partial class TaskDefinitionEditWindowViewModel : ObservableValidator
{
[ObservableProperty]
[Required(ErrorMessage = "名称不能为空")]
private string _name = "";
[ObservableProperty]
private string _description = "";
public event EventHandler<bool>? RequestClose;
public TaskDefinitionEditWindowViewModel()
{
}
public TaskDefinitionEditWindowViewModel(string name, string description = "")
{
Name = name;
Description = description;
}
[RelayCommand]
private void Confirm()
{
if (string.IsNullOrWhiteSpace(Name))
{
return;
}
RequestClose?.Invoke(this, true);
}
[RelayCommand]
private void Cancel()
{
RequestClose?.Invoke(this, false);
}
}