以下是对半导体可靠性测试机上位机系统的更详细 UI 设计和代码实现,基于 .NET Core + WPF + Prism + MVVM + MaterialDesignThemes,涵盖首页、配置界面
以下是对半导体可靠性测试机上位机系统的更详细 UI 设计和代码实现,基于 .NET Core + WPF + Prism + MVVM + MaterialDesignThemes,涵盖首页、配置界面、监控界面、日志界面和硬件控制界面。每个页面都会提供完整的 XAML 和 ViewModel 代码,并附带中文解释,确保界面大气、现代、用户友好。代码将使用 MaterialDesignThemes 美化界面,LiveCharts 绘制曲线,Prism 实现模块化导航,Autofac 管理依赖。以下按页面逐一展开。
一、UI 设计总体原则
-
风格:采用 MaterialDesignThemes,界面现代化,配色柔和,按钮和控件有动画效果。
-
布局:使用 Grid 和 StackPanel 实现自适应布局,确保不同分辨率下显示正常。
-
交互:支持鼠标点击、键盘导航,界面响应快速,异步加载数据避免卡顿。
-
提示:每个页面包含帮助按钮,点击显示操作指引。
-
图表:使用 LiveCharts 绘制实时曲线,支持动态更新。
二、项目结构与依赖
确保项目已添加以下 NuGet 包:
-
Prism.Unity(模块化和导航)
-
MaterialDesignThemes(UI 美化)
-
LiveCharts.Wpf(图表)
-
Autofac(依赖注入)
-
Serilog.Sinks.File 和 Serilog.Sinks.Console(日志)
-
Microsoft.EntityFrameworkCore.Sqlite(数据库)
-
NumSharp(计算)
appsettings.json(示例配置)
json
{
"Storage": {
"Type": "SQLite",
"ConnectionString": "Data Source=testdata.db"
},
"Hardware": {
"PowerSupply": { "Type": "TektronixPowerSupply", "Port": "COM1" },
"Oven": { "Type": "CustomOven", "Address": "192.168.1.100", "Protocol": "TCP" }
}
}
Bootstrapper.cs(Prism 启动配置,已在上一回答中提供,略)
三、UI 页面详细设计与代码
3.1 主窗口
主窗口包含导航栏和内容区域,使用 Prism 的 Region 动态加载各模块视图。
MainWindow.xaml
xaml
<Window x:Class="SemiconductorTestSystem.UI.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
Title="半导体可靠性测试系统" Height="720" Width="1280" WindowStartupLocation="CenterScreen">
<Grid>
<!-- 导航栏 -->
<materialDesign:Card Background="{DynamicResource MaterialDesignPaper}" Margin="0,0,0,10">
<StackPanel Orientation="Horizontal" Height="60" VerticalAlignment="Top">
<Button Content="首页" Margin="10" Style="{StaticResource MaterialDesignRaisedButton}"
Command="{Binding NavigateCommand}" CommandParameter="HomeView"/>
<Button Content="配置" Margin="10" Style="{StaticResource MaterialDesignRaisedButton}"
Command="{Binding NavigateCommand}" CommandParameter="ConfigView"/>
<Button Content="监控" Margin="10" Style="{StaticResource MaterialDesignRaisedButton}"
Command="{Binding NavigateCommand}" CommandParameter="MonitorView"/>
<Button Content="日志" Margin="10" Style="{StaticResource MaterialDesignRaisedButton}"
Command="{Binding NavigateCommand}" CommandParameter="LogView"/>
<Button Content="硬件控制" Margin="10" Style="{StaticResource MaterialDesignRaisedButton}"
Command="{Binding NavigateCommand}" CommandParameter="HardwareControlView"/>
</StackPanel>
</materialDesign:Card>
<!-- 内容区域 -->
<ContentControl prism:RegionManager.RegionName="MainRegion" Margin="10,70,10,10"/>
</Grid>
</Window>
MainWindowViewModel.cs
csharp
using Prism.Commands;
using Prism.Mvvm;
using Prism.Regions;
namespace SemiconductorTestSystem.UI.ViewModels
{
public class MainWindowViewModel : BindableBase
{
private readonly IRegionManager _regionManager;
public DelegateCommand<string> NavigateCommand { get; private set; }
public MainWindowViewModel(IRegionManager regionManager)
{
_regionManager = regionManager;
NavigateCommand = new DelegateCommand<string>(Navigate);
}
private void Navigate(string viewName)
{
_regionManager.RequestNavigate("MainRegion", viewName);
}
}
}
中文解释:
-
主窗口使用 MaterialDesign 的 Card 组件包装导航栏,增加立体感。
-
导航按钮使用 MaterialDesignRaisedButton 样式,点击触发 Prism 导航。
-
内容区域通过 ContentControl 的 Region 动态加载视图。
-
窗口大小设置为 1280x720,居中显示,适配大多数屏幕。
3.2 首页
功能:显示多个通道信息(通道名称、状态、测试模式等),点击通道显示数据表格和实时曲线,展示实验进度。
HomeView.xaml
xaml
<UserControl x:Class="SemiconductorTestSystem.UI.Modules.Home.Views.HomeView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:lc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf">
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- 通道列表 -->
<materialDesign:Card Grid.Column="0" Padding="10">
<StackPanel>
<TextBlock Text="通道列表" Style="{StaticResource MaterialDesignHeadline6TextBlock}" Margin="0,0,0,10"/>
<ListBox ItemsSource="{Binding Channels}" SelectedItem="{Binding SelectedChannel}" Height="600">
<ListBox.ItemTemplate>
<DataTemplate>
<materialDesign:Card Margin="5" Padding="10">
<StackPanel>
<TextBlock Text="{Binding ChannelName}" FontWeight="Bold"/>
<TextBlock Text="{Binding Status}"/>
<TextBlock Text="{Binding TestMode}"/>
</StackPanel>
</materialDesign:Card>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</materialDesign:Card>
<!-- 数据展示 -->
<materialDesign:Card Grid.Column="1" Margin="10,0,0,0" Padding="10">
<StackPanel>
<TextBlock Text="通道数据" Style="{StaticResource MaterialDesignHeadline6TextBlock}" Margin="0,0,0,10"/>
<DataGrid ItemsSource="{Binding ChannelData}" AutoGenerateColumns="True" Height="200" Margin="0,0,0,10"/>
<lc:CartesianChart Series="{Binding SeriesCollection}" Height="300" Margin="0,0,0,10">
<lc:CartesianChart.AxisX>
<lc:Axis Title="时间 (s)"/>
</lc:CartesianChart.AxisX>
<lc:CartesianChart.AxisY>
<lc:Axis Title="温度 (°C)"/>
</lc:CartesianChart.AxisY>
</lc:CartesianChart>
<StackPanel Orientation="Horizontal">
<TextBlock Text="实验进度: " FontWeight="Bold"/>
<TextBlock Text="{Binding TestProgress}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="测试模式: " FontWeight="Bold"/>
<TextBlock Text="{Binding TestMode}"/>
</StackPanel>
<Button Content="帮助" Style="{StaticResource MaterialDesignFloatingActionMiniButton}"
Command="{Binding ShowHelpCommand}" HorizontalAlignment="Right" Margin="0,10,0,0"/>
</StackPanel>
</materialDesign:Card>
</Grid>
</UserControl>
HomeViewModel.cs
csharp
using Prism.Commands;
using Prism.Mvvm;
using Prism.Regions;
using LiveCharts;
using LiveCharts.Wpf;
using SemiconductorTestSystem.Core.Models;
using SemiconductorTestSystem.Core.Services;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Windows;
namespace SemiconductorTestSystem.UI.Modules.Home.ViewModels
{
public class HomeViewModel : BindableBase, INavigationAware
{
private readonly ITestController _testController;
private Channel _selectedChannel;
private ObservableCollection<Channel> _channels;
private ObservableCollection<TestData> _channelData;
private SeriesCollection _seriesCollection;
private string _testProgress;
private string _testMode;
public DelegateCommand ShowHelpCommand { get; private set; }
public HomeViewModel(ITestController testController)
{
_testController = testController;
Channels = new ObservableCollection<Channel>();
ChannelData = new ObservableCollection<TestData>();
SeriesCollection = new SeriesCollection();
ShowHelpCommand = new DelegateCommand(ShowHelp);
LoadChannelsAsync();
}
public Channel SelectedChannel
{
get => _selectedChannel;
set
{
SetProperty(ref _selectedChannel, value);
UpdateChannelDataAsync();
}
}
public ObservableCollection<Channel> Channels
{
get => _channels;
set => SetProperty(ref _channels, value);
}
public ObservableCollection<TestData> ChannelData
{
get => _channelData;
set => SetProperty(ref _channelData, value);
}
public SeriesCollection SeriesCollection
{
get => _seriesCollection;
set => SetProperty(ref _seriesCollection, value);
}
public string TestProgress
{
get => _testProgress;
set => SetProperty(ref _testProgress, value);
}
public string TestMode
{
get => _testMode;
set => SetProperty(ref _testMode, value);
}
private async void LoadChannelsAsync()
{
var channels = await _testController.GetChannelsAsync();
Channels.Clear();
foreach (var channel in channels)
{
Channels.Add(channel);
}
}
private async void UpdateChannelDataAsync()
{
if (SelectedChannel != null)
{
var data = await _testController.GetChannelDataAsync(SelectedChannel.Id);
ChannelData.Clear();
foreach (var item in data)
{
ChannelData.Add(item);
}
SeriesCollection.Clear();
SeriesCollection.Add(new LineSeries
{
Title = "温度",
Values = new ChartValues<double>(data.Select(d => d.Temperature))
});
TestProgress = $"已完成 {data.Count / 100.0:P0}";
TestMode = SelectedChannel.TestMode;
}
}
private void ShowHelp()
{
MessageBox.Show("首页帮助:\n1. 左侧选择通道查看数据。\n2. 右侧显示数据表格和曲线。\n3. 实验进度和测试模式实时更新。",
"帮助", MessageBoxButton.OK, MessageBoxImage.Information);
}
public void OnNavigatedTo(NavigationContext navigationContext) { }
public bool IsNavigationTarget(NavigationContext navigationContext) => true;
public void OnNavigatedFrom(NavigationContext navigationContext) { }
}
}
中文解释:
-
布局:左侧使用 ListBox 显示通道列表,右侧显示数据表格(DataGrid)和曲线(LiveCharts)。
-
美化:通道列表和数据区域使用 MaterialDesign 的 Card 组件,增加层次感。
-
交互:选择通道后异步加载数据,更新表格和曲线;帮助按钮显示操作说明。
-
图表:LiveCharts 显示温度曲线,X 轴为时间,Y 轴为温度,标题和单位清晰。
-
异步:数据加载使用 async/await,确保 UI 不卡顿。
3.3 配置界面
功能:设置实验流程(如升温、升压、延时等),支持添加、删除、调整步骤顺序。
ConfigView.xaml
xaml
<UserControl x:Class="SemiconductorTestSystem.UI.Modules.Config.Views.ConfigView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- 工具栏 -->
<materialDesign:Card Padding="10">
<StackPanel Orientation="Horizontal">
<ComboBox ItemsSource="{Binding StepTypes}" SelectedItem="{Binding SelectedStepType}"
Width="150" Margin="10" materialDesign:HintAssist.Hint="步骤类型"/>
<TextBox Text="{Binding StepValue}" Width="100" Margin="10" materialDesign:HintAssist.Hint="参数值"/>
<Button Content="添加步骤" Style="{StaticResource MaterialDesignRaisedButton}"
Command="{Binding AddStepCommand}" Margin="10"/>
<Button Content="保存配置" Style="{StaticResource MaterialDesignRaisedButton}"
Command="{Binding SaveConfigCommand}" Margin="10"/>
<Button Content="帮助" Style="{StaticResource MaterialDesignFloatingActionMiniButton}"
Command="{Binding ShowHelpCommand}" Margin="10"/>
</StackPanel>
</materialDesign:Card>
<!-- 步骤列表 -->
<materialDesign:Card Grid.Row="1" Margin="0,10,0,0" Padding="10">
<ListBox ItemsSource="{Binding TestSteps}" Height="550">
<ListBox.ItemTemplate>
<DataTemplate>
<materialDesign:Card Margin="5" Padding="10">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Type}" Width="150"/>
<TextBlock Text="{Binding Value}" Width="100"/>
<Button Content="删除" Style="{StaticResource MaterialDesignFlatButton}"
Command="{Binding DataContext.DeleteStepCommand, RelativeSource={RelativeSource AncestorType=ListBox}}"
CommandParameter="{Binding}"/>
</StackPanel>
</materialDesign:Card>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</materialDesign:Card>
</Grid>
</UserControl>
ConfigViewModel.cs
csharp
using Prism.Commands;
using Prism.Mvvm;
using Prism.Regions;
using SemiconductorTestSystem.Core.Models;
using SemiconductorTestSystem.Core.Services;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
namespace SemiconductorTestSystem.UI.Modules.Config.ViewModels
{
public class ConfigViewModel : BindableBase, INavigationAware
{
private readonly ITestController _testController;
private ObservableCollection<TestStep> _testSteps;
private string _selectedStepType;
private double _stepValue;
public DelegateCommand AddStepCommand { get; private set; }
public DelegateCommand<TestStep> DeleteStepCommand { get; private set; }
public DelegateCommand SaveConfigCommand { get; private set; }
public DelegateCommand ShowHelpCommand { get; private set; }
public ConfigViewModel(ITestController testController)
{
_testController = testController;
TestSteps = new ObservableCollection<TestStep>();
StepTypes = new ObservableCollection<string> { "Temperature", "Voltage", "Delay" };
AddStepCommand = new DelegateCommand(AddStep);
DeleteStepCommand = new DelegateCommand<TestStep>(DeleteStep);
SaveConfigCommand = new DelegateCommand(SaveConfig);
ShowHelpCommand = new DelegateCommand(ShowHelp);
}
public ObservableCollection<TestStep> TestSteps
{
get => _testSteps;
set => SetProperty(ref _testSteps, value);
}
public ObservableCollection<string> StepTypes { get; private set; }
public string SelectedStepType
{
get => _selectedStepType;
set => SetProperty(ref _selectedStepType, value);
}
public double StepValue
{
get => _stepValue;
set => SetProperty(ref _stepValue, value);
}
private void AddStep()
{
if (!string.IsNullOrEmpty(SelectedStepType))
{
TestSteps.Add(new TestStep { Type = SelectedStepType, Value = StepValue });
}
}
private void DeleteStep(TestStep step)
{
TestSteps.Remove(step);
}
private async void SaveConfig()
{
var config = new TestConfig { Steps = TestSteps.ToList() };
await _testController.SaveConfigAsync(config);
MessageBox.Show("配置已保存!", "成功", MessageBoxButton.OK, MessageBoxImage.Information);
}
private void ShowHelp()
{
MessageBox.Show("配置界面帮助:\n1. 选择步骤类型和参数值添加实验步骤。\n2. 点击删除移除步骤。\n3. 保存配置后可用于实验控制。",
"帮助", MessageBoxButton.OK, MessageBoxImage.Information);
}
public void OnNavigatedTo(NavigationContext navigationContext) { }
public bool IsNavigationTarget(NavigationContext navigationContext) => true;
public void OnNavigatedFrom(NavigationContext navigationContext) { }
}
}
中文解释:
-
布局:顶部工具栏用于添加步骤,包含步骤类型(ComboBox)、参数值(TextBox)和按钮;下方 ListBox 显示步骤列表。
-
交互:支持动态添加/删除步骤,保存配置到 TestController;帮助按钮提供指引。
-
美化:使用 MaterialDesign 控件,步骤列表以 Card 形式展示,删除按钮为 Flat 样式,减少视觉干扰。
-
功能:支持灵活配置实验流程(如先升温后升压,或加延时)。
3.4 监控界面
功能:实时查看硬件状态(温箱、通道、辅控板、老化板、电源),颜色指示状态。
MonitorView.xaml
xaml
<UserControl x:Class="SemiconductorTestSystem.UI.Modules.Monitor.Views.MonitorView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes">
<Grid Margin="10">
<materialDesign:Card Padding="10">
<StackPanel>
<TextBlock Text="硬件状态监控" Style="{StaticResource MaterialDesignHeadline6TextBlock}" Margin="0,0,0,10"/>
<DataGrid ItemsSource="{Binding Devices}" AutoGenerateColumns="False" Height="550">
<DataGrid.Columns>
<DataGridTextColumn Header="设备ID" Binding="{Binding DeviceId}" Width="150"/>
<DataGridTextColumn Header="设备名称" Binding="{Binding DeviceName}" Width="200"/>
<DataGridTemplateColumn Header="状态" Width="100">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<materialDesign:Chip Content="{Binding Status}"
Background="{Binding Status, Converter={StaticResource StatusToColorConverter}}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="消息" Binding="{Binding StatusMessage}" Width="*"/>
</DataGrid.Columns>
</DataGrid>
<Button Content="帮助" Style="{StaticResource MaterialDesignFloatingActionMiniButton}"
Command="{Binding ShowHelpCommand}" HorizontalAlignment="Right" Margin="0,10,0,0"/>
</StackPanel>
</materialDesign:Card>
</Grid>
</UserControl>
StatusToColorConverter.cs(状态颜色转换器)
csharp
using SemiconductorTestSystem.Hardware.Interfaces;
using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;
namespace SemiconductorTestSystem.UI.Converters
{
public class StatusToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is DeviceStatus status)
{
return status switch
{
DeviceStatus.Idle => Brushes.Gray,
DeviceStatus.Running => Brushes.Green,
DeviceStatus.Error => Brushes.Red,
DeviceStatus.Disconnected => Brushes.Orange,
_ => Brushes.Gray
};
}
return Brushes.Gray;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
MonitorViewModel.cs
csharp
using Prism.Commands;
using Prism.Mvvm;
using Prism.Regions;
using SemiconductorTestSystem.Core.Services;
using SemiconductorTestSystem.Hardware.Interfaces;
using System.Collections.ObjectModel;
using System.Windows;
namespace SemiconductorTestSystem.UI.Modules.Monitor.ViewModels
{
public class MonitorViewModel : BindableBase, INavigationAware
{
private readonly IHardwareService _hardwareService;
private ObservableCollection<IHardwareDevice> _devices;
public DelegateCommand ShowHelpCommand { get; private set; }
public MonitorViewModel(IHardwareService hardwareService)
{
_hardwareService = hardwareService;
Devices = new ObservableCollection<IHardwareDevice>();
ShowHelpCommand = new DelegateCommand(ShowHelp);
LoadDevices();
}
public ObservableCollection<IHardwareDevice> Devices
{
get => _devices;
set => SetProperty(ref _devices, value);
}
private void LoadDevices()
{
Devices.Clear();
foreach (var device in _hardwareService.GetAllDevices())
{
Devices.Add(device);
device.StatusChanged += (s, e) =>
{
RaisePropertyChanged(nameof(Devices));
};
}
}
private void ShowHelp()
{
MessageBox.Show("监控界面帮助:\n1. 查看所有硬件的实时状态。\n2. 状态颜色说明:绿色-运行,灰色-空闲,红色-错误,橙色-断开。",
"帮助", MessageBoxButton.OK, MessageBoxImage.Information);
}
public void OnNavigatedTo(NavigationContext navigationContext) { }
public bool IsNavigationTarget(NavigationContext navigationContext) => true;
public void OnNavigatedFrom(NavigationContext navigationContext) { }
}
}
中文解释:
-
布局:使用 DataGrid 显示硬件列表,包含设备 ID、名称、状态和消息。
-
美化:状态列使用 Chip 控件,颜色通过 StatusToColorConverter 动态转换(绿色表示运行,红色表示错误等)。
-
交互:硬件状态变化通过事件触发界面更新;帮助按钮提供指引。
-
功能:实时监控温箱、通道、电源等硬件状态,异步更新确保流畅。
3.5 日志界面
功能:显示设备和实验日志,支持筛选和导出。
LogView.xaml
xaml
<UserControl x:Class="SemiconductorTestSystem.UI.Modules.Log.Views.LogView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes">
<Grid Margin="10">
<materialDesign:Card Padding="10">
<StackPanel>
<TextBlock Text="日志查看" Style="{StaticResource MaterialDesignHeadline6TextBlock}" Margin="0,0,0,10"/>
<StackPanel Orientation="Horizontal" Margin="0,0,0,10">
<TextBox Text="{Binding FilterText, UpdateSourceTrigger=PropertyChanged}" Width="200"
materialDesign:HintAssist.Hint="筛选日志"/>
<Button Content="导出日志" Style="{StaticResource MaterialDesignRaisedButton}"
Command="{Binding ExportLogCommand}" Margin="10,0,0,0"/>
<Button Content="帮助" Style="{StaticResource MaterialDesignFloatingActionMiniButton}"
Command="{Binding ShowHelpCommand}" Margin="10,0,0,0"/>
</StackPanel>
<DataGrid ItemsSource="{Binding Logs}" AutoGenerateColumns="False" Height="500">
<DataGrid.Columns>
<DataGridTextColumn Header="时间" Binding="{Binding Timestamp}" Width="150"/>
<DataGridTextColumn Header="级别" Binding="{Binding Level}" Width="100"/>
<DataGridTextColumn Header="消息" Binding="{Binding Message}" Width="*"/>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
</materialDesign:Card>
</Grid>
</UserControl>
LogViewModel.cs
csharp
using Prism.Commands;
using Prism.Mvvm;
using Prism.Regions;
using SemiconductorTestSystem.Core.Services;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Windows;
namespace SemiconductorTestSystem.UI.Modules.Log.ViewModels
{
public class LogViewModel : BindableBase, INavigationAware
{
private readonly ILogService _logService;
private ObservableCollection<LogEntry> _logs;
private string _filterText;
public DelegateCommand ExportLogCommand { get; private set; }
public DelegateCommand ShowHelpCommand { get; private set; }
public LogViewModel(ILogService logService)
{
_logService = logService;
Logs = new ObservableCollection<LogEntry>();
ExportLogCommand = new DelegateCommand(ExportLog);
ShowHelpCommand = new DelegateCommand(ShowHelp);
LoadLogs();
}
public ObservableCollection<LogEntry> Logs
{
get => _logs;
set => SetProperty(ref _logs, value);
}
public string FilterText
{
get => _filterText;
set
{
SetProperty(ref _filterText, value);
FilterLogs();
}
}
private void LoadLogs()
{
// 模拟从日志服务加载
Logs.Add(new LogEntry { Timestamp = DateTime.Now, Level = "INFO", Message = "系统启动" });
Logs.Add(new LogEntry { Timestamp = DateTime.Now.AddSeconds(-10), Level = "ERROR", Message = "设备连接失败" });
}
private void FilterLogs()
{
if (string.IsNullOrEmpty(FilterText))
{
LoadLogs();
}
else
{
var filtered = Logs.Where(l => l.Message.Contains(FilterText, StringComparison.OrdinalIgnoreCase)).ToList();
Logs.Clear();
foreach (var log in filtered)
{
Logs.Add(log);
}
}
}
private void ExportLog()
{
using var writer = new StreamWriter("logs/exported_log.txt");
foreach (var log in Logs)
{
writer.WriteLine($"{log.Timestamp} [{log.Level}] {log.Message}");
}
MessageBox.Show("日志已导出到 exported_log.txt", "成功", MessageBoxButton.OK, MessageBoxImage.Information);
}
private void ShowHelp()
{
MessageBox.Show("日志界面帮助:\n1. 使用筛选框搜索日志。\n2. 点击导出日志保存到文件。\n3. 日志包含时间、级别和消息。",
"帮助", MessageBoxButton.OK, MessageBoxImage.Information);
}
public void OnNavigatedTo(NavigationContext navigationContext) { }
public bool IsNavigationTarget(NavigationContext navigationContext) => true;
public void OnNavigatedFrom(NavigationContext navigationContext) { }
}
public class LogEntry
{
public DateTime Timestamp { get; set; }
public string Level { get; set; }
public string Message { get; set; }
}
}
中文解释:
-
布局:顶部包含筛选框和导出按钮,下方 DataGrid 显示日志。
-
美化:日志表格使用 MaterialDesign 的 Card 包装,筛选框支持实时更新。
-
交互:支持日志筛选(实时响应)和导出到文件;帮助按钮提供指引。
-
功能:展示设备和实验日志,未来可与 Serilog 集成实时读取。
3.6 硬件控制界面
功能:显示硬件信息,选择硬件查看状态和执行操作(如设置电源电压)。
HardwareControlView.xaml
xaml
<UserControl x:Class="SemiconductorTestSystem.UI.Modules.HardwareControl.Views.HardwareControlView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes">
<Grid Margin="10">
<materialDesign:Card Padding="10">
<StackPanel>
<TextBlock Text="硬件控制" Style="{StaticResource MaterialDesignHeadline6TextBlock}" Margin="0,0,0,10"/>
<ComboBox ItemsSource="{Binding Devices}" DisplayMemberPath="DeviceName"
SelectedItem="{Binding SelectedDevice}" Width="200" Margin="10"
materialDesign:HintAssist.Hint="选择硬件"/>
<StackPanel Orientation="Horizontal" Margin="0,10,0,10">
<TextBox Text="{Binding ParameterName}" Width="150" materialDesign:HintAssist.Hint="参数名"/>
<TextBox Text="{Binding ParameterValue}" Width="100" materialDesign:HintAssist.Hint="参数值"/>
<Button Content="设置" Style="{StaticResource MaterialDesignRaisedButton}"
Command="{Binding SetParameterCommand}" Margin="10,0,0,0"/>
<Button Content="读取" Style="{StaticResource MaterialDesignRaisedButton}"
Command="{Binding ReadParameterCommand}" Margin="10,0,0,0"/>
</StackPanel>
<TextBlock Text="{Binding ParameterResult}" Margin="0,0,0,10"/>
<Button Content="帮助" Style="{StaticResource MaterialDesignFloatingActionMiniButton}"
Command="{Binding ShowHelpCommand}" HorizontalAlignment="Right"/>
</StackPanel>
</materialDesign:Card>
</Grid>
</UserControl>
HardwareControlViewModel.cs
csharp
using Prism.Commands;
using Prism.Mvvm;
using Prism.Regions;
using SemiconductorTestSystem.Core.Services;
using SemiconductorTestSystem.Hardware.Interfaces;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Windows;
namespace SemiconductorTestSystem.UI.Modules.HardwareControl.ViewModels
{
public class HardwareControlViewModel : BindableBase, INavigationAware
{
private readonly IHardwareService _hardwareService;
private ObservableCollection<IHardwareDevice> _devices;
private IHardwareDevice _selectedDevice;
private string _parameterName;
private string _parameterValue;
private string _parameterResult;
public DelegateCommand SetParameterCommand { get; private set; }
public DelegateCommand ReadParameterCommand { get; private set; }
public DelegateCommand ShowHelpCommand { get; private set; }
public HardwareControlViewModel(IHardwareService hardwareService)
{
_hardwareService = hardwareService;
Devices = new ObservableCollection<IHardwareDevice>();
SetParameterCommand = new DelegateCommand(async () => await SetParameterAsync());
ReadParameterCommand = new DelegateCommand(async () => await ReadParameterAsync());
ShowHelpCommand = new DelegateCommand(ShowHelp);
LoadDevices();
}
public ObservableCollection<IHardwareDevice> Devices
{
get => _devices;
set => SetProperty(ref _devices, value);
}
public IHardwareDevice SelectedDevice
{
get => _selectedDevice;
set => SetProperty(ref _selectedDevice, value);
}
public string ParameterName
{
get => _parameterName;
set => SetProperty(ref _parameterName, value);
}
public string ParameterValue
{
get => _parameterValue;
set => SetProperty(ref _parameterValue, value);
}
public string ParameterResult
{
get => _parameterResult;
set => SetProperty(ref _parameterResult, value);
}
private void LoadDevices()
{
Devices.Clear();
foreach (var device in _hardwareService.GetAllDevices())
{
Devices.Add(device);
}
}
private async Task SetParameterAsync()
{
if (SelectedDevice != null && !string.IsNullOrEmpty(ParameterName) && !string.IsNullOrEmpty(ParameterValue))
{
await SelectedDevice.SetParameterAsync(ParameterName, ParameterValue);
ParameterResult = $"设置 {ParameterName} = {ParameterValue} 成功";
}
}
private async Task ReadParameterAsync()
{
if (SelectedDevice != null && !string.IsNullOrEmpty(ParameterName))
{
var result = await SelectedDevice.ReadParameterAsync(ParameterName);
ParameterResult = $"读取 {ParameterName} = {result}";
}
}
private void ShowHelp()
{
MessageBox.Show("硬件控制界面帮助:\n1. 选择硬件并输入参数名和值。\n2. 点击设置发送参数,点击读取获取参数值。\n3. 支持电源、温箱等硬件操作。",
"帮助", MessageBoxButton.OK, MessageBoxImage.Information);
}
public void OnNavigatedTo(NavigationContext navigationContext) { }
public bool IsNavigationTarget(NavigationContext navigationContext) => true;
public void OnNavigatedFrom(NavigationContext navigationContext) { }
}
}
中文解释:
-
布局:ComboBox 选择硬件,TextBox 输入参数名和值,按钮执行设置/读取操作。
-
美化:使用 MaterialDesign 控件,界面简洁,参数结果显示在 TextBlock 中。
-
交互:异步设置和读取硬件参数,实时显示结果;帮助按钮提供指引。
-
功能:支持动态选择硬件(如电源、温箱),执行调试操作。
四、UI 设计要点总结
-
一致性:所有页面使用 MaterialDesignThemes,保持统一的现代化风格。
-
响应性:异步加载数据(async/await),确保高频数据采集不卡顿。
-
模块化:每个页面作为一个 Prism 模块,独立开发和维护。
-
用户体验:帮助按钮提供操作指引,颜色和动画增强交互性。
-
扩展性:支持动态添加新页面,Prism 导航灵活。
五、后续补充
如果需要以下内容,请告诉我,我可以进一步扩展:
-
更详细的业务逻辑:如 TestController 的具体实现,涵盖 HTRB、HTGB 等测试。
-
计算模块:热阻、结构函数等公式的详细实现。
-
多设备优化:支持 200+ 设备的高效管理。
-
云端部署:集成 Azure 或 AWS 实现远程监控。
-
深度学习:使用 ML.NET 分析实验数据。
请确认具体需求,我会提供更详细的代码或分篇说明!
更多推荐
所有评论(0)