feat(wpf): 添加Ploss和Qfod数据表格视图

This commit is contained in:
ssss
2026-07-06 13:37:34 +08:00
parent cee3536507
commit cf4f24fde3
10 changed files with 411 additions and 9 deletions

View File

@@ -74,6 +74,9 @@ public partial class App : Application
// Chart ViewModels 使用 Transient每次导航创建新实例 // Chart ViewModels 使用 Transient每次导航创建新实例
services.AddTransient<PlossChartViewModel>(); services.AddTransient<PlossChartViewModel>();
services.AddTransient<QfodChartViewModel>(); services.AddTransient<QfodChartViewModel>();
// Table ViewModels 使用 Transient每次导航创建新实例
services.AddTransient<PlossTableViewModel>();
services.AddTransient<QfodTableViewModel>();
services.AddSingleton<ImportViewModel>(); services.AddSingleton<ImportViewModel>();
// 注册 Views // 注册 Views
@@ -81,6 +84,8 @@ public partial class App : Application
services.AddTransient<ScenarioListView>(); services.AddTransient<ScenarioListView>();
services.AddTransient<PlossChartView>(); services.AddTransient<PlossChartView>();
services.AddTransient<QfodChartView>(); services.AddTransient<QfodChartView>();
services.AddTransient<PlossTableView>();
services.AddTransient<QfodTableView>();
services.AddTransient<ImportView>(); services.AddTransient<ImportView>();
}) })
.Build(); .Build();

View File

@@ -62,6 +62,12 @@
<DataTemplate DataType="{x:Type viewmodels:QfodChartViewModel}"> <DataTemplate DataType="{x:Type viewmodels:QfodChartViewModel}">
<views:QfodChartView/> <views:QfodChartView/>
</DataTemplate> </DataTemplate>
<DataTemplate DataType="{x:Type viewmodels:PlossTableViewModel}">
<views:PlossTableView/>
</DataTemplate>
<DataTemplate DataType="{x:Type viewmodels:QfodTableViewModel}">
<views:QfodTableView/>
</DataTemplate>
</ContentControl.Resources> </ContentControl.Resources>
</ContentControl> </ContentControl>
</Grid> </Grid>

View File

@@ -17,3 +17,15 @@ public record NavigateToPlossChartMessage(Guid ScenarioId);
/// </summary> /// </summary>
/// <param name="ScenarioId">场景 ID</param> /// <param name="ScenarioId">场景 ID</param>
public record NavigateToQfodChartMessage(Guid ScenarioId); public record NavigateToQfodChartMessage(Guid ScenarioId);
/// <summary>
/// 导航到 Ploss 表格消息
/// </summary>
/// <param name="ScenarioId">场景 ID</param>
public record NavigateToPlossTableMessage(Guid ScenarioId);
/// <summary>
/// 导航到 Qfod 表格消息
/// </summary>
/// <param name="ScenarioId">场景 ID</param>
public record NavigateToQfodTableMessage(Guid ScenarioId);

View File

@@ -2,6 +2,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging; using CommunityToolkit.Mvvm.Messaging;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using System.Windows;
using WCTDataMiner.Core.Services; using WCTDataMiner.Core.Services;
using WCTDataMiner.Wpf.Messages; using WCTDataMiner.Wpf.Messages;
@@ -12,7 +13,9 @@ namespace WCTDataMiner.Wpf.ViewModels;
/// </summary> /// </summary>
public partial class MainViewModel : ObservableObject, public partial class MainViewModel : ObservableObject,
IRecipient<NavigateToPlossChartMessage>, IRecipient<NavigateToPlossChartMessage>,
IRecipient<NavigateToQfodChartMessage> IRecipient<NavigateToQfodChartMessage>,
IRecipient<NavigateToPlossTableMessage>,
IRecipient<NavigateToQfodTableMessage>
{ {
private readonly ImportViewModel _importViewModel; private readonly ImportViewModel _importViewModel;
private readonly ScenarioListViewModel _scenarioListViewModel; private readonly ScenarioListViewModel _scenarioListViewModel;
@@ -59,6 +62,8 @@ public partial class MainViewModel : ObservableObject,
// 注册导航消息订阅 // 注册导航消息订阅
WeakReferenceMessenger.Default.Register<NavigateToPlossChartMessage>(this); WeakReferenceMessenger.Default.Register<NavigateToPlossChartMessage>(this);
WeakReferenceMessenger.Default.Register<NavigateToQfodChartMessage>(this); WeakReferenceMessenger.Default.Register<NavigateToQfodChartMessage>(this);
WeakReferenceMessenger.Default.Register<NavigateToPlossTableMessage>(this);
WeakReferenceMessenger.Default.Register<NavigateToQfodTableMessage>(this);
} }
/// <summary> /// <summary>
@@ -120,9 +125,12 @@ public partial class MainViewModel : ObservableObject,
/// </summary> /// </summary>
public void Receive(NavigateToPlossChartMessage message) public void Receive(NavigateToPlossChartMessage message)
{ {
var vm = _serviceProvider.GetRequiredService<PlossChartViewModel>(); Application.Current.Dispatcher.InvokeAsync(() =>
vm.ScenarioId = message.ScenarioId; {
CurrentView = vm; var vm = _serviceProvider.GetRequiredService<PlossChartViewModel>();
vm.ScenarioId = message.ScenarioId;
CurrentView = vm;
});
} }
/// <summary> /// <summary>
@@ -130,8 +138,37 @@ public partial class MainViewModel : ObservableObject,
/// </summary> /// </summary>
public void Receive(NavigateToQfodChartMessage message) public void Receive(NavigateToQfodChartMessage message)
{ {
var vm = _serviceProvider.GetRequiredService<QfodChartViewModel>(); Application.Current.Dispatcher.InvokeAsync(() =>
vm.ScenarioId = message.ScenarioId; {
CurrentView = vm; var vm = _serviceProvider.GetRequiredService<QfodChartViewModel>();
vm.ScenarioId = message.ScenarioId;
CurrentView = vm;
});
}
/// <summary>
/// 接收导航到 Ploss 表格消息
/// </summary>
public void Receive(NavigateToPlossTableMessage message)
{
Application.Current.Dispatcher.InvokeAsync(() =>
{
var vm = _serviceProvider.GetRequiredService<PlossTableViewModel>();
vm.ScenarioId = message.ScenarioId;
CurrentView = vm;
});
}
/// <summary>
/// 接收导航到 Qfod 表格消息
/// </summary>
public void Receive(NavigateToQfodTableMessage message)
{
Application.Current.Dispatcher.InvokeAsync(() =>
{
var vm = _serviceProvider.GetRequiredService<QfodTableViewModel>();
vm.ScenarioId = message.ScenarioId;
CurrentView = vm;
});
} }
} }

View File

@@ -0,0 +1,87 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.Extensions.Logging;
using System.Collections.ObjectModel;
using WCTDataMiner.Core.Models;
using WCTDataMiner.Core.Services;
using WCTDataMiner.Wpf.Messages;
namespace WCTDataMiner.Wpf.ViewModels;
/// <summary>
/// Ploss 数据表格 ViewModel
/// </summary>
public partial class PlossTableViewModel : ObservableObject
{
private readonly ScenarioService _scenarioService;
private readonly ILogger<PlossTableViewModel> _logger;
[ObservableProperty]
private Guid _scenarioId;
[ObservableProperty]
private ObservableCollection<PlossRecord> _records = new();
[ObservableProperty]
private bool _isLoading;
[ObservableProperty]
private string _loadingMessage = "";
public PlossTableViewModel(
ScenarioService scenarioService,
ILogger<PlossTableViewModel> logger)
{
_scenarioService = scenarioService;
_logger = logger;
}
/// <summary>
/// ScenarioId 属性变更时自动触发数据加载
/// </summary>
partial void OnScenarioIdChanged(Guid value)
{
if (value != Guid.Empty)
{
_ = LoadDataAsync().ContinueWith(t =>
{
if (t.Exception != null)
{
_logger.LogError(t.Exception, "LoadDataAsync 失败: ScenarioId={ScenarioId}", value);
}
}, TaskContinuationOptions.OnlyOnFaulted);
}
}
public async Task LoadDataAsync()
{
if (IsLoading) return; // 防并发
IsLoading = true;
LoadingMessage = "正在加载数据...";
try
{
var records = await _scenarioService.GetPlossRecordsByScenarioIdAsync(ScenarioId);
Records = new ObservableCollection<PlossRecord>(records);
_logger.LogInformation("加载 Ploss 表格数据成功: ScenarioId={ScenarioId}, 记录数={Count}", ScenarioId, records.Count);
LoadingMessage = "";
}
catch (Exception ex)
{
_logger.LogError(ex, "加载 Ploss 表格数据失败: ScenarioId={ScenarioId}", ScenarioId);
LoadingMessage = $"加载失败: {ex.Message}";
}
finally
{
IsLoading = false;
}
}
[RelayCommand]
private void SwitchToChart()
{
WeakReferenceMessenger.Default.Send(new NavigateToPlossChartMessage(ScenarioId));
}
}

View File

@@ -0,0 +1,87 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.Extensions.Logging;
using System.Collections.ObjectModel;
using WCTDataMiner.Core.Models;
using WCTDataMiner.Core.Services;
using WCTDataMiner.Wpf.Messages;
namespace WCTDataMiner.Wpf.ViewModels;
/// <summary>
/// Qfod 数据表格 ViewModel
/// </summary>
public partial class QfodTableViewModel : ObservableObject
{
private readonly ScenarioService _scenarioService;
private readonly ILogger<QfodTableViewModel> _logger;
[ObservableProperty]
private Guid _scenarioId;
[ObservableProperty]
private ObservableCollection<QfodRecord> _records = new();
[ObservableProperty]
private bool _isLoading;
[ObservableProperty]
private string _loadingMessage = "";
public QfodTableViewModel(
ScenarioService scenarioService,
ILogger<QfodTableViewModel> logger)
{
_scenarioService = scenarioService;
_logger = logger;
}
/// <summary>
/// ScenarioId 属性变更时自动触发数据加载
/// </summary>
partial void OnScenarioIdChanged(Guid value)
{
if (value != Guid.Empty)
{
_ = LoadDataAsync().ContinueWith(t =>
{
if (t.Exception != null)
{
_logger.LogError(t.Exception, "LoadDataAsync 失败: ScenarioId={ScenarioId}", value);
}
}, TaskContinuationOptions.OnlyOnFaulted);
}
}
public async Task LoadDataAsync()
{
if (IsLoading) return; // 防并发
IsLoading = true;
LoadingMessage = "正在加载数据...";
try
{
var records = await _scenarioService.GetQfodRecordsByScenarioIdAsync(ScenarioId);
Records = new ObservableCollection<QfodRecord>(records);
_logger.LogInformation("加载 Qfod 表格数据成功: ScenarioId={ScenarioId}, 记录数={Count}", ScenarioId, records.Count);
LoadingMessage = "";
}
catch (Exception ex)
{
_logger.LogError(ex, "加载 Qfod 表格数据失败: ScenarioId={ScenarioId}", ScenarioId);
LoadingMessage = $"加载失败: {ex.Message}";
}
finally
{
IsLoading = false;
}
}
[RelayCommand]
private void SwitchToChart()
{
WeakReferenceMessenger.Default.Send(new NavigateToQfodChartMessage(ScenarioId));
}
}

View File

@@ -0,0 +1,79 @@
<UserControl x:Class="WCTDataMiner.Wpf.Views.PlossTableView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="400" d:DesignWidth="900">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- 标题区域 -->
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,10">
<TextBlock Text="Ploss 数据表格" FontSize="18" FontWeight="Bold"/>
<TextBlock Text="{Binding ScenarioId, StringFormat=' - 场景 {0}'}" FontSize="14" Foreground="Gray" Margin="10,5,0,0"/>
</StackPanel>
<!-- 操作按钮 -->
<StackPanel Grid.Row="1" Orientation="Horizontal" Margin="0,0,0,10">
<Button Content="切换到图表" Command="{Binding SwitchToChartCommand}" Padding="10,5" Margin="0,0,10,0"/>
<TextBlock Text="{Binding Records.Count, StringFormat='共 {0} 条记录'}" VerticalAlignment="Center" Foreground="Gray"/>
<!-- 加载状态/错误消息显示 -->
<TextBlock Text="{Binding LoadingMessage}" VerticalAlignment="Center" Foreground="Orange" Margin="20,0,0,0"/>
</StackPanel>
<!-- 数据表格 -->
<DataGrid Grid.Row="2"
ItemsSource="{Binding Records}"
AutoGenerateColumns="False"
IsReadOnly="True"
GridLinesVisibility="Horizontal"
AlternatingRowBackground="#F9F9F9"
CanUserAddRows="False"
HeadersVisibility="Column"
HorizontalScrollBarVisibility="Auto"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.VirtualizationMode="Recycling"
EnableRowVirtualization="True"
EnableColumnVirtualization="True">
<DataGrid.Columns>
<DataGridTextColumn Header="PowLoss" Binding="{Binding PowLoss}" Width="80"/>
<DataGridTextColumn Header="DeltaP" Binding="{Binding DeltaP}" Width="80"/>
<DataGridTextColumn Header="Field1" Binding="{Binding Field1}" Width="70"/>
<DataGridTextColumn Header="Field2" Binding="{Binding Field2}" Width="70"/>
<DataGridTextColumn Header="Field3" Binding="{Binding Field3}" Width="70"/>
<DataGridTextColumn Header="Field4" Binding="{Binding Field4}" Width="70"/>
<DataGridTextColumn Header="Field5" Binding="{Binding Field5}" Width="70"/>
<DataGridTextColumn Header="Field6" Binding="{Binding Field6}" Width="70"/>
<DataGridTextColumn Header="Ploss" Binding="{Binding Field7}" Width="80">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Blue"/>
<Setter Property="FontWeight" Value="Bold"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Threshold" Binding="{Binding Field8}" Width="80">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Red"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Trigger" Binding="{Binding Field9}" Width="70"/>
<DataGridTextColumn Header="Result" Binding="{Binding Field10}" Width="70"/>
<DataGridTextColumn Header="Margin" Binding="{Binding Margin}" Width="80"/>
<DataGridTextColumn Header="Field11" Binding="{Binding Field11}" Width="70"/>
<DataGridTextColumn Header="Field12" Binding="{Binding Field12}" Width="70"/>
<DataGridTextColumn Header="Field13" Binding="{Binding Field13}" Width="70"/>
<DataGridTextColumn Header="Field14" Binding="{Binding Field14}" Width="70"/>
<DataGridTextColumn Header="Field15" Binding="{Binding Field15}" Width="70"/>
<DataGridTextColumn Header="Field16" Binding="{Binding Field16}" Width="70"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</UserControl>

View File

@@ -0,0 +1,14 @@
using System.Windows.Controls;
namespace WCTDataMiner.Wpf.Views;
/// <summary>
/// PlossTableView.xaml 的交互逻辑
/// </summary>
public partial class PlossTableView : UserControl
{
public PlossTableView()
{
InitializeComponent();
}
}

View File

@@ -0,0 +1,61 @@
<UserControl x:Class="WCTDataMiner.Wpf.Views.QfodTableView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="400" d:DesignWidth="600">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- 标题区域 -->
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,10">
<TextBlock Text="Qfod 数据表格" FontSize="18" FontWeight="Bold"/>
<TextBlock Text="{Binding ScenarioId, StringFormat=' - 场景 {0}'}" FontSize="14" Foreground="Gray" Margin="10,5,0,0"/>
</StackPanel>
<!-- 操作按钮 -->
<StackPanel Grid.Row="1" Orientation="Horizontal" Margin="0,0,0,10">
<Button Content="切换到图表" Command="{Binding SwitchToChartCommand}" Padding="10,5" Margin="0,0,10,0"/>
<TextBlock Text="{Binding Records.Count, StringFormat='共 {0} 条记录'}" VerticalAlignment="Center" Foreground="Gray"/>
<!-- 加载状态/错误消息显示 -->
<TextBlock Text="{Binding LoadingMessage}" VerticalAlignment="Center" Foreground="Orange" Margin="20,0,0,0"/>
</StackPanel>
<!-- 数据表格 -->
<DataGrid Grid.Row="2"
ItemsSource="{Binding Records}"
AutoGenerateColumns="False"
IsReadOnly="True"
GridLinesVisibility="Horizontal"
AlternatingRowBackground="#F9F9F9"
CanUserAddRows="False"
HeadersVisibility="Column"
HorizontalScrollBarVisibility="Auto"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.VirtualizationMode="Recycling"
EnableRowVirtualization="True"
EnableColumnVirtualization="True">
<DataGrid.Columns>
<DataGridTextColumn Header="ChargerIdx" Binding="{Binding ChargerIndex}" Width="100"/>
<DataGridTextColumn Header="CoilIdx" Binding="{Binding CoilIndex}" Width="80"/>
<DataGridTextColumn Header="DeltaQ" Binding="{Binding DeltaQ}" Width="80">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Blue"/>
<Setter Property="FontWeight" Value="Bold"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="CurrentQ" Binding="{Binding CurrentQ}" Width="80"/>
<DataGridTextColumn Header="RawQ" Binding="{Binding RawQ}" Width="80"/>
<DataGridTextColumn Header="FodType" Binding="{Binding FodType}" Width="80"/>
<DataGridTextColumn Header="FieldF" Binding="{Binding FieldF}" Width="80"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</UserControl>

View File

@@ -0,0 +1,14 @@
using System.Windows.Controls;
namespace WCTDataMiner.Wpf.Views;
/// <summary>
/// QfodTableView.xaml 的交互逻辑
/// </summary>
public partial class QfodTableView : UserControl
{
public QfodTableView()
{
InitializeComponent();
}
}