我将为半导体可靠性测试机上位机系统提供更详细的模块化实现,重点包括监控界面、日志界面、流程配置界面的具体代码,以及多设备管理、历史数据查询、云端部署和深度学习模型的设计与实现。本文将基于 .NET Core 8.0、WPF、MVVM 模式、Prism 框架、LiveCharts2、Entity Framework Core、Serilog 等技术栈,结合异步编程和高性能优化,确保代码可落地且易扩展。由于内容较多,我将分模块展开,并提供具体代码示例和实现细节。


一、监控界面(MonitorView)实现

1.1 功能描述

监控界面用于实时显示硬件状态,包括:

  • 温箱:温度、湿度、运行状态。

  • 通道:电压、电流、温度等参数。

  • 辅控板:蜂鸣器、PLC、接触器等状态。

  • 老化板:工位数据、热阻等。

  • 电源:输出电压、电流、开关状态。 支持动态刷新、异常告警、仪表盘和表格展示。

1.2 MonitorView.xaml

xaml

<UserControl x:Class="ReliabilityTestSystem.UI.Modules.MonitorModule.Views.MonitorView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:lc="clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF"
             xmlns:prism="http://prismlibrary.com/">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!-- 硬件选择 -->
        <StackPanel Orientation="Horizontal" Margin="5">
            <ComboBox ItemsSource="{Binding HardwareTypes}" 
                      SelectedItem="{Binding SelectedHardwareType}" 
                      Width="150" Margin="5"/>
            <Button Content="刷新" Command="{Binding RefreshCommand}" Margin="5"/>
            <Button Content="帮助" Command="{Binding ShowHelpCommand}" Margin="5" 
                    ToolTip="查看监控界面操作指南"/>
        </StackPanel>

        <!-- 硬件状态展示 -->
        <TabControl Grid.Row="1" ItemsSource="{Binding HardwareGroups}">
            <TabControl.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Name}"/>
                </DataTemplate>
            </TabControl.ItemTemplate>
            <TabControl.ContentTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="Auto"/>
                        </Grid.ColumnDefinitions>
                        
                        <!-- 数据表格 -->
                        <DataGrid ItemsSource="{Binding Devices}" 
                                  AutoGenerateColumns="False" 
                                  Margin="5">
                            <DataGrid.Columns>
                                <DataGridTextColumn Header="设备ID" Binding="{Binding Id}"/>
                                <DataGridTextColumn Header="名称" Binding="{Binding Name}"/>
                                <DataGridTextColumn Header="状态" Binding="{Binding Status}"/>
                                <DataGridTextColumn Header="参数" Binding="{Binding Parameters}"/>
                            </DataGrid.Columns>
                        </DataGrid>

                        <!-- 仪表盘 -->
                        <StackPanel Grid.Column="1" Margin="5">
                            <lc:GaugeChart Total="100" 
                                           Value="{Binding SelectedDevice.Temperature}"
                                           LabelFormatter="{Binding LabelFormatter}"
                                           Height="150" Width="150"
                                           Margin="5"/>
                            <TextBlock Text="{Binding SelectedDevice.Name}" 
                                       FontWeight="Bold" Margin="5"/>
                        </StackPanel>
                    </Grid>
                </DataTemplate>
            </TabControl.ContentTemplate>
        </TabControl>
    </Grid>
</UserControl>

1.3 MonitorViewModel.cs

csharp

using LiveChartsCore;
using LiveChartsCore.SkiaSharpView;
using Prism.Commands;
using Prism.Mvvm;
using ReliabilityTestSystem.Core.Models;
using ReliabilityTestSystem.Core.Services;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using System.Timers;

namespace ReliabilityTestSystem.UI.Modules.MonitorModule.ViewModels
{
    public class MonitorViewModel : BindableBase
    {
        private readonly IHardwareService _hardwareService;
        private ObservableCollection<string> _hardwareTypes;
        private string _selectedHardwareType;
        private ObservableCollection<HardwareGroup> _hardwareGroups;
        private Timer _refreshTimer;
        private Func<double, string> _labelFormatter = value => $"{value:F1} °C";

        public MonitorViewModel(IHardwareService hardwareService)
        {
            _hardwareService = hardwareService;
            RefreshCommand = new DelegateCommand(async () => await RefreshAsync());
            ShowHelpCommand = new DelegateCommand(ShowHelp);
            HardwareTypes = new ObservableCollection<string> { "温箱", "通道", "辅控板", "老化板", "电源" };
            SelectedHardwareType = HardwareTypes.First();
            HardwareGroups = new ObservableCollection<HardwareGroup>();

            // 设置定时刷新(每秒)
            _refreshTimer = new Timer(1000);
            _refreshTimer.Elapsed += async (s, e) => await RefreshAsync();
            _refreshTimer.Start();

            Task.Run(() => InitializeAsync());
        }

        public ObservableCollection<string> HardwareTypes
        {
                get => _hardwareTypes;
                set => SetProperty(ref _hardwareTypes, value);
            }

        public string SelectedHardwareType
        {
            get => _selectedHardwareType;
            set
            {
                SetProperty(ref _selectedHardwareType, value);
                Task.Run(() => await LoadHardwareGroupsAsync());
            }
        }

        public ObservableCollection<HardwareGroup> HardwareGroups
        {
                get => _hardwareGroups;
                set => SetProperty(ref _hardwareGroups, value);
            }

        public DelegateCommand RefreshCommand { get; private set; }
        public DelegateCommand ShowHelpCommand { get; private set; }
        public Func<double, string> LabelFormatter => _labelFormatter;

        private async Task InitializeAsync()
        {
            await LoadHardwareGroupsAsync();
        }

        private async Task LoadHardwareGroupsAsync()
        {
            var devices = await _hardwareService.GetDevicesByTypeAsync(SelectedHardwareType);
            var groups = devices.GroupBy(d => d.Category)
                                .Select(g => new HardwareGroup
                                {
                                    Name = g.Key,
                                    Devices = new ObservableCollection<Device>(g.ToList()),
                                    SelectedDevice = g.FirstOrDefault()
                                });

            HardwareGroups.Clear();
            foreach (var group of groups)
            {
                HardwareGroups.Add(group);
            }
        }

        private async Task RefreshAsync()
        {
            await LoadHardwareGroupsAsync();
        }

        private void ShowHelp()
        {
            Application.Current.Dispatcher.Invoke(() => MessageBox.Show(
                "监控界面操作指南:选择硬件类型,查看设备状态,点击刷新更新数据。"));
        }
    }

    public class HardwareGroup : BindableBase
    {
        private Device _selectedDevice;

        public string Name { get; set; }
        public ObservableCollection<Device> Devices { get; set; }

        public Device SelectedDevice
        {
            get => _selectedDevice;
            set => SetProperty(ref _selectedDevice, value);
        }
    }
}

1.4 IHardwareService.cs

硬件服务接口,用于获取设备状态(具体实现依赖硬件驱动层)。

csharp

namespace ReliabilityTestSystem.Core.Services
{
    public interface IHardwareService
    {
        Task<IEnumerable<Device>> GetDevicesByTypeAsync(string type);
    }

    public class Device
    {
        public string Id { get; set; }
        public string Name { get; set; }
        public string Status { get; set; }
        public string Parameters { get; set; }
        public string Category { get; set; }
        public double Temperature { get; set; }
    }
}

二、日志界面(LogView)实现

2.1 功能描述

日志界面展示系统和实验的日志流,支持:

  • 实时日志流显示。

  • 日志过滤(按时间、级别、节点)。

  • 日志订阅与导出。

  • 使用 Serilog 记录日志,确保高性能。

2.2 LogView.xaml

xaml

<UserControl x:Class="ReliabilityTestSystem.UI.Modules.LogModule.Views.LogView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:prism="http://prismlibrary.com/">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!-- 过滤器 -->
        <StackPanel Orientation="Horizontal" Margin="5">
            <ComboBox ItemsSource="{Binding LogLevels}" 
                      SelectedItem="{Binding SelectedLogLevel}" 
                      Width="100" Margin="5"/>
            <TextBox Text="{Binding FilterText}" Width="200" Margin="5"/>
            <Button Content="导出" Command="{Binding ExportLogsCommand}" Margin="5"/>
            <Button Content="帮助" Command="{Binding ShowHelpCommand}" Margin="5"
                    ToolTip="查看日志界面操作指南"/>
        </StackPanel>

        <!-- 日志列表 -->
        <DataGrid Grid.Row="1" ItemsSource="{Binding Logs}" 
                  AutoGenerateColumns="False" Margin="5">
            <DataGrid.Columns>
                <DataGridTextColumn Header="时间" Binding="{Binding Timestamp, StringFormat={}{0:yyyy-MM-dd HH:mm:ss}}"/>
                <DataGridTextColumn Header="级别" Binding="{Binding Level}"/>
                <DataGridTextColumn Header="消息" Binding="{Binding Message}" Width="*"/>
                <DataGridTextColumn Header="节点" Binding="{Binding Source}"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</UserControl>

2.3 LogViewModel.cs

csharp

using Prism.Commands;
using Prism.Mvvm;
using ReliabilityTestSystem.Core.Services;
using Serilog;
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace ReliabilityTestSystem.UI.Modules.LogModule.ViewModels
{
    public class LogViewModel : BindableBase
    {
        private readonly ILogService _logService;
        private ObservableCollection<LogEntry> _logs;
        private ObservableCollection<string> _logLevels;
        private string _selectedLogLevel;
        private string _filterText;

        public LogViewModel(ILogService logService)
        {
            _logService = logService;
            Logs = new ObservableCollection<LogEntry>();
            LogLevels = new ObservableCollection<string> { "All", "Information", "Warning", "Error" };
            SelectedLogLevel = LogLevels.First();
            ExportLogsCommand = new DelegateCommand(ExportLogs);
            ShowHelpCommand = new DelegateCommand(ShowHelp);

            // 订阅日志更新
            _logService.LogReceived += (s, e) => Application.Current.Dispatcher.Invoke(() => AddLog(e));
            Task.Run(() => LoadLogsAsync());
        }

        public ObservableCollection<LogEntry> Logs
        {
            get => _logs;
            set => SetProperty(ref _logs, value);
        }

        public ObservableCollection<string> LogLevels
        {
            get => _logLevels;
            set => SetProperty(ref _logLevels, value);
        }

        public string SelectedLogLevel
        {
            get => _selectedLogLevel;
            set
            {
                SetProperty(ref _selectedLogLevel, value);
                FilterLogs();
            }
        }

        public string FilterText
        {
            get => _filterText;
            set
            {
                SetProperty(ref _filterText, value);
                FilterLogs();
            }
        }

        public DelegateCommand ExportLogsCommand { get; private set; }
        public DelegateCommand ShowHelpCommand { get; private set; }

        private async Task LoadLogsAsync()
        {
            var logs = await _logService.GetRecentLogsAsync(1000);
            Application.Current.Dispatcher.Invoke(() =>
            {
                foreach (var log in logs)
                {
                    Logs.Add(log);
                }
            });
        }

        private void AddLog(LogEntry log)
        {
            if (Logs.Count > 1000) Logs.RemoveAt(0); // 限制日志数量
            Logs.Add(log);
        }

        private void FilterLogs()
        {
            var filtered = _logService.GetRecentLogsAsync(1000).Result
                .Where(l => (SelectedLogLevel == "All" || l.Level == SelectedLogLevel) &&
                            (string.IsNullOrEmpty(FilterText) || l.Message.Contains(FilterText, StringComparison.OrdinalIgnoreCase)));
            Application.Current.Dispatcher.Invoke(() =>
            {
                Logs.Clear();
                foreach (var log in filtered)
                {
                    Logs.Add(log);
                }
            });
        }

        private void ExportLogs()
        {
            var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), $"logs_{DateTime.Now:yyyyMMdd_HHmmss}.csv");
            using (var writer = new StreamWriter(path))
            {
                writer.WriteLine("Timestamp,Level,Message,Source");
                foreach (var log in Logs)
                {
                    writer.WriteLine($"\"{log.Timestamp}\",\"{log.Level}\",\"{log.Message}\",\"{log.Source}\"");
                }
            }
            MessageBox.Show($"日志已导出到 {path}");
        }

        private void ShowHelp()
        {
            MessageBox.Show("日志界面操作指南:选择日志级别或输入关键字过滤,点击导出保存日志。");
        }
    }

    public class LogEntry
    {
        public DateTime Timestamp { get; set; }
        public string Level { get; set; }
        public string Message { get; set; }
        public string Source { get; set; }
    }
}

2.4 ILogService.cs

日志服务接口,基于 Serilog。

csharp

namespace ReliabilityTestSystem.Core.Services
{
    public interface ILogService
    {
        event EventHandler<LogEntry> LogReceived;
        Task<IEnumerable<LogEntry>> GetRecentLogsAsync(int maxCount);
    }
}

三、流程配置界面(ConfigView)深入实现

3.1 功能描述

流程配置界面支持动态设置实验流程(如升温、升压、延时),包括:

  • 添加、删除、编辑测试步骤。

  • 支持复杂流程(条件分支、循环)。

  • 保存配置到数据库或文件。

  • 提供预览和验证功能。

3.2 ConfigView.xaml

xaml

<UserControl x:Class="ReliabilityTestSystem.UI.Modules.ConfigModule.Views.ConfigView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:prism="http://prismlibrary.com/">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <!-- 步骤编辑 -->
        <StackPanel Orientation="Horizontal" Margin="5">
            <ComboBox ItemsSource="{Binding StepTypes}" 
                      SelectedItem="{Binding SelectedStepType}" 
                      Width="150" Margin="5"/>
            <TextBox Text="{Binding StepParameter}" Width="200" Margin="5"/>
            <Button Content="添加步骤" Command="{Binding AddStepCommand}" Margin="5"/>
            <Button Content="帮助" Command="{Binding ShowHelpCommand}" Margin="5"
                    ToolTip="查看流程配置操作指南"/>
        </StackPanel>

        <!-- 步骤列表 -->
        <ListBox Grid.Row="1" ItemsSource="{Binding TestSteps}" Margin="5">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="Auto"/>
                        </Grid.ColumnDefinitions>
                        <TextBlock Text="{Binding Description}"/>
                        <Button Grid.Column="1" Content="删除" 
                                Command="{Binding DataContext.DeleteStepCommand, RelativeSource={RelativeSource AncestorType=ListBox}}"
                                CommandParameter="{Binding}"/>
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

        <!-- 操作按钮 -->
        <StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right" Margin="5">
            <Button Content="预览" Command="{Binding PreviewCommand}" Margin="5"/>
            <Button Content="保存" Command="{Binding SaveConfigCommand}" Margin="5"/>
        </StackPanel>
    </Grid>
</UserControl>

3.3 ConfigViewModel.cs

csharp

using Prism.Commands;
using Prism.Mvvm;
using ReliabilityTestSystem.Core.Models;
using ReliabilityTestSystem.Core.Services;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;

namespace ReliabilityTestSystem.UI.Modules.ConfigModule.ViewModels
{
    public class ConfigViewModel : BindableBase
    {
        private readonly IConfigService _configService;
        private ObservableCollection<TestStep> _testSteps;
        private ObservableCollection<string> _stepTypes;
        private string _selectedStepType;
        private string _stepParameter;

        public ConfigViewModel(IConfigService configService)
        {
            _configService = configService;
            TestSteps = new ObservableCollection<TestStep>();
            StepTypes = new ObservableCollection<string> { "升温", "升压", "延时", "循环", "条件" };
            SelectedStepType = StepTypes.First();
            AddStepCommand = new DelegateCommand(AddStep);
            DeleteStepCommand = new DelegateCommand<TestStep>(DeleteStep);
            PreviewCommand = new DelegateCommand(Preview);
            SaveConfigCommand = new DelegateCommand(async () => await SaveConfigAsync());
            ShowHelpCommand = new DelegateCommand(ShowHelp);
        }

        public ObservableCollection<TestStep> TestSteps
        {
            get => _testSteps;
            set => SetProperty(ref _testSteps, value);
        }

        public ObservableCollection<string> StepTypes
        {
            get => _stepTypes;
            set => SetProperty(ref _stepTypes, value);
        }

        public string SelectedStepType
        {
            get => _selectedStepType;
            set => SetProperty(ref _selectedStepType, value);
        }

        public string StepParameter
        {
            get => _stepParameter;
            set => SetProperty(ref _stepParameter, value);
        }

        public DelegateCommand AddStepCommand { get; private set; }
        public DelegateCommand<TestStep> DeleteStepCommand { get; private set; }
        public DelegateCommand PreviewCommand { get; private set; }
        public DelegateCommand SaveConfigCommand { get; private set; }
        public DelegateCommand ShowHelpCommand { get; private set; }

        private void AddStep()
        {
            if (!string.IsNullOrEmpty(SelectedStepType) && !string.IsNullOrEmpty(StepParameter))
            {
                var step = new TestStep
                {
                    StepType = SelectedStepType,
                    Parameter = StepParameter,
                    Description = $"{SelectedStepType}: {StepParameter}"
                };
                TestSteps.Add(step);
                StepParameter = string.Empty;
            }
        }

        private void DeleteStep(TestStep step)
        {
            TestSteps.Remove(step);
        }

        private void Preview()
        {
            var preview = string.Join("\n", TestSteps.Select(s => s.Description));
            MessageBox.Show($"流程预览:\n{preview}");
        }

        private async Task SaveConfigAsync()
        {
            await _configService.SaveTestConfigAsync(TestSteps.ToList());
            MessageBox.Show("配置已保存");
        }

        private void ShowHelp()
        {
            MessageBox.Show("流程配置操作指南:选择步骤类型,输入参数,添加或删除步骤,预览后保存。");
        }
    }
}

3.4 IConfigService.cs

配置服务接口。

csharp

namespace ReliabilityTestSystem.Core.Services
{
    public interface IConfigService
    {
        Task SaveTestConfigAsync(IList<TestStep> steps);
    }

    public class TestStep
    {
        public string StepType { get; set; }
        public string Parameter { get; set; }
        public string Description { get; set; }
    }
}

四、多设备管理实现

4.1 功能描述

支持动态发现和管理 200+ 设备,通过设备注册服务实现:

  • 自动扫描硬件(COM、TCP/IP 等协议)。

  • 动态加载驱动(反射或依赖注入)。

  • 设备状态实时更新。

4.2 IDeviceRegistry.cs

设备注册服务接口。

csharp

namespace ReliabilityTestSystem.Core.Services
{
    public interface IDeviceRegistry
    {
        Task DiscoverDevicesAsync();
        IEnumerable<IDeviceDriver> GetRegisteredDevices();
        event EventHandler<DeviceDiscoveredEventArgs> DeviceDiscovered;
    }

    public interface IDeviceDriver
    {
        string Id { get; }
        string Name { get; }
        Task InitializeAsync();
        Task<object> ReadDataAsync();
        Task SetParameterAsync(string parameter, object value);
    }

    public class DeviceDiscoveredEventArgs : EventArgs
    {
        public IDeviceDriver Device { get; set; }
    }
}

4.3 DeviceRegistry.cs

设备注册服务实现(使用反射加载驱动)。

csharp

using System.Reflection;

namespace ReliabilityTestSystem.Core.Services
{
    public class DeviceRegistry : IDeviceRegistry
    {
        private readonly List<IDeviceDriver> _devices = new List<IDeviceDriver>();
        public event EventHandler<DeviceDiscoveredEventArgs> DeviceDiscovered;

        public async Task DiscoverDevicesAsync()
        {
            // 扫描驱动程序集
            var driverTypes = Assembly.GetExecutingAssembly()
                .GetTypes()
                .Where(t => typeof(IDeviceDriver).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract);

            foreach (var type in driverTypes)
            {
                var driver = (IDeviceDriver)Activator.CreateInstance(type);
                await driver.InitializeAsync();
                _devices.Add(driver);
                DeviceDiscovered?.Invoke(this, new DeviceDiscoveredEventArgs { Device = driver });
            }
        }

        public IEnumerable<IDeviceDriver> GetRegisteredDevices() => _devices;
    }
}

4.4 示例驱动:PowerSupplyDriver.cs

电源驱动示例。

csharp

namespace ReliabilityTestSystem.Core.Drivers
{
    public class PowerSupplyDriver : IDeviceDriver
    {
        public string Id => Guid.NewGuid().ToString();
        public string Name => "特牛电源";

        public async Task InitializeAsync()
        {
            // 模拟初始化
            await Task.Delay(100);
        }

        public async Task<object> ReadDataAsync()
        {
            // 模拟读取电压和电流
            return new { Voltage = 5.0, Current = 1.2 };
        }

        public async Task SetParameterAsync(string parameter, object value)
        {
            // 模拟设置参数
            await Task.Delay(50);
        }
    }
}

4.5 集成到 MonitorViewModel

csharp

public MonitorViewModel(IHardwareService hardwareService, IDeviceRegistry deviceRegistry)
{
    _hardwareService = hardwareService;
    _deviceRegistry = deviceRegistry;
    deviceRegistry.DeviceDiscovered += (s, e) => RefreshAsync();
    Task.Run(() => deviceRegistry.DiscoverDevicesAsync());
}

五、历史数据查询实现

5.1 功能描述

历史数据查询界面支持:

  • 按时间范围、通道、实验类型查询。

  • 分页显示结果(EF Core)。

  • 导出 CSV 或查看曲线。

5.2 HistoryQueryView.xaml

xaml

<UserControl x:Class="ReliabilityTestSystem.UI.Modules.HistoryModule.Views.HistoryQueryView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:prism="http://prismlibrary.com/">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <!-- 查询条件 -->
        <StackPanel Orientation="Horizontal" Margin="5">
            <DatePicker SelectedDate="{Binding StartDate}" Margin="5"/>
            <DatePicker SelectedDate="{Binding EndDate}" Margin="5"/>
            <ComboBox ItemsSource="{Binding Channels}" 
                      SelectedItem="{Binding SelectedChannel}" 
                      Width="150" Margin="5"/>
            <Button Content="查询" Command="{Binding QueryCommand}" Margin="5"/>
            <Button Content="帮助" Command="{Binding ShowHelpCommand}" Margin="5"/>
        </StackPanel>

        <!-- 查询结果 -->
        <DataGrid Grid.Row="1" ItemsSource="{Binding QueryResults}" 
                  AutoGenerateColumns="True" Margin="5"/>

        <!-- 分页 -->
        <StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right" Margin="5">
            <Button Content="上一页" Command="{Binding PreviousPageCommand}" Margin="5"/>
            <TextBlock Text="{Binding CurrentPage}" Margin="5"/>
            <Button Content="下一页" Command="{Binding NextPageCommand}" Margin="5"/>
            <Button Content="导出" Command="{Binding ExportResultsCommand}" Margin="5"/>
        </StackPanel>
    </Grid>
</UserControl>

5.3 HistoryQueryViewModel.cs

csharp

using Microsoft.EntityFrameworkCore;
using Prism.Commands;
using Prism.Mvvm;
using ReliabilityTestSystem.Core.Data;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;

namespace ReliabilityTestSystem.UI.Modules.HistoryModule.ViewModels
{
    public class HistoryQueryViewModel : BindableBase
    {
        private readonly AppDbContext _dbContext;
        private ObservableCollection<object> _queryResults;
        private ObservableCollection<string> _channels;
        private string _selectedChannel;
        private DateTime? _startDate;
        private DateTime? _endDate;
        private int _currentPage = 1;
        private readonly int _pageSize = 100;

        public HistoryQueryViewModel(AppDbContext dbContext)
        {
            _dbContext = dbContext;
            QueryResults = new ObservableCollection<object>();
            Channels = new ObservableCollection<string> { "通道1", "通道2" }; // 模拟
            SelectedChannel = Channels.First();
            QueryCommand = new DelegateCommand(async () => await QueryAsync());
            PreviousPageCommand = new DelegateCommand(async () => await ChangePageAsync(-1));
            NextPageCommand = new DelegateCommand(async () => await ChangePageAsync(1));
            ExportResultsCommand = new DelegateCommand(ExportResults);
            ShowHelpCommand = new DelegateCommand(ShowHelp);
        }

        public ObservableCollection<object> QueryResults
        {
            get => _queryResults;
            set => SetProperty(ref _queryResults, value);
        }

        public ObservableCollection<string> Channels
        {
            get => _channels;
            set => SetProperty(ref _channels, value);
        }

        public string SelectedChannel
        {
            get => _selectedChannel;
            set => SetProperty(ref _selectedChannel, value);
        }

        public DateTime? StartDate
        {
            get => _startDate;
            set => SetProperty(ref _startDate, value);
        }

        public DateTime? EndDate
        {
            get => _endDate;
            set => SetProperty(ref _endDate, value);
        }

        public int CurrentPage
        {
            get => _currentPage;
            set => SetProperty(ref _currentPage, value);
        }

        public DelegateCommand QueryCommand { get; private set; }
        public DelegateCommand PreviousPageCommand { get; private set; }
        public DelegateCommand NextPageCommand { get; private set; }
        public DelegateCommand ExportResultsCommand { get; private set; }
        public DelegateCommand ShowHelpCommand { get; private set; }

        private async Task QueryAsync()
        {
            var query = _dbContext.TestData.AsQueryable();
            if (!string.IsNullOrEmpty(SelectedChannel))
                query = query.Where(d => d.Channel == SelectedChannel);
            if (StartDate.HasValue)
                query = query.Where(d => d.Timestamp >= StartDate.Value);
            if (EndDate.HasValue)
                query = query.Where(d => d.Timestamp <= EndDate.Value);

            var results = await query
                .OrderBy(d => d.Timestamp)
                .Skip((CurrentPage - 1) * _pageSize)
                .Take(_pageSize)
                .Select(d => new { d.Timestamp, d.Channel, d.Temperature, d.Voltage })
                .ToListAsync();

            QueryResults.Clear();
            foreach (var result in results)
            {
                QueryResults.Add(result);
            }
        }

        private async Task ChangePageAsync(int delta)
        {
            CurrentPage = Math.Max(1, CurrentPage + delta);
            await QueryAsync();
        }

        private void ExportResults()
        {
            // 类似 LogViewModel 的导出逻辑
        }

        private void ShowHelp()
        {
            MessageBox.Show("历史查询操作指南:选择时间范围和通道,点击查询显示结果。");
        }
    }
}

5.4 AppDbContext.cs

EF Core 数据库上下文。

csharp

using Microsoft.EntityFrameworkCore;

namespace ReliabilityTestSystem.Core.Data
{
    public class AppDbContext : DbContext
    {
        public DbSet<TestData> TestData { get; set; }

        public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
    }

    public class TestData
    {
        public int Id { get; set; }
        public DateTime Timestamp { get; set; }
        public string Channel { get; set; }
        public double Temperature { get; set; }
        public double Voltage { get; set; }
    }
}

六、云端部署与 SignalR 实现

6.1 功能描述

支持将实时数据同步到云端,使用 SignalR 实现:

  • 实时推送设备状态和实验数据。

  • 支持 Web 端或移动端查看。

6.2 SignalR 服务端

创建一个 ASP.NET Core 项目(ReliabilityTestSystem.Web)。

Startup.cs

csharp

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.SignalR;

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSignalR();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseRouting();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapHub<DataHub>("/dataHub");
        });
    }
}

DataHub.cs

csharp

using Microsoft.AspNetCore.SignalR;

namespace ReliabilityTestSystem.Web.Hubs
{
    public class DataHub : Hub
    {
        public async Task SendData(string channel, object data)
        {
            await Clients.All.SendAsync("ReceiveData", channel, data);
        }
    }
}

6.3 WPF 客户端集成 SignalR

安装 SignalR 客户端包:

bash

dotnet add package Microsoft.AspNetCore.SignalR.Client

SignalRService.cs

csharp

using Microsoft.AspNetCore.SignalR.Client;
using System.Threading.Tasks;

namespace ReliabilityTestSystem.Core.Services
{
    public class SignalRService
    {
        private readonly HubConnection _connection;

        public SignalRService()
        {
            _connection = new HubConnectionBuilder()
                .WithUrl("https://yourserver/dataHub")
                .Build();
        }

        public async Task StartAsync()
        {
            await _connection.StartAsync();
        }

        public async Task SendDataAsync(string channel, object data)
        {
            await _connection.InvokeAsync("SendData", channel, data);
        }
    }
}

在 ChannelDetailViewModel 中推送数据

csharp

public class ChannelDetailViewModel : BindableBase, INavigationAware
{
    private readonly SignalRService _signalRService;

    public ChannelDetailViewModel(SignalRService signalRService)
    {
        _signalRService = signalRService;
        Task.Run(() => _signalRService.StartAsync());
    }

    private void Timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        var time = DateTime.Now.Ticks;
        var temperature = 25 + Math.Sin(time / 10000000.0) * 2;
        var voltage = 5 + Math.Cos(time / 10000000.0) * 0.2;

        Application.Current.Dispatcher.Invoke(() =>
        {
            // 更新本地 UI
            ((ObservableCollection<double>)Series[0].Values).Add(temperature);
            ((ObservableCollection<double>)Series[1].Values).Add(voltage);
            ChannelData.Add(new { Time = DateTime.Now, Temperature = temperature, Voltage = voltage });

            // 推送至云端
            _signalRService.SendDataAsync(Channel.Name, new { Time = DateTime.Now, Temperature = temperature, Voltage = voltage });
        });
    }
}

七、深度学习模型集成(ML.NET)

7.1 功能描述

使用 ML.NET 预测老化板寿命,基于历史数据(温度、电压、电流等)训练模型。

7.2 安装 ML.NET

bash

dotnet add package Microsoft.ML

7.3 数据模型

csharp

public class AgingBoardData
{
    public float Temperature { get; set; }
    public float Voltage { get; set; }
    public float Current { get; set; }
    public float Lifetime { get; set; } // 目标:寿命(小时)
}

public class LifetimePrediction
{
    [ColumnName("Score")]
    public float Lifetime { get; set; }
}

7.4 训练模型

csharp

using Microsoft.ML;
using Microsoft.ML.Data;

namespace ReliabilityTestSystem.Core.ML
{
    public class LifetimePredictor
    {
        private readonly MLContext _mlContext = new MLContext();
        private ITransformer _model;

        public void TrainModel(IEnumerable<AgingBoardData> data)
        {
            var dataView = _mlContext.Data.LoadFromEnumerable(data);
            var pipeline = _mlContext.Transforms.Concatenate("Features", nameof(AgingBoardData.Temperature), nameof(AgingBoardData.Voltage), nameof(AgingBoardData.Current))
                .Append(_mlContext.Regression.Trainers.FastTree(labelColumnName: nameof(AgingBoardData.Lifetime)));

            _model = pipeline.Fit(dataView);
        }

        public float Predict(AgingBoardData input)
        {
            var predictionEngine = _mlContext.Model.CreatePredictionEngine<AgingBoardData, LifetimePrediction>(_model);
            return predictionEngine.Predict(input).Lifetime;
        }
    }
}

7.5 在 MonitorViewModel 中使用

csharp

public MonitorViewModel(IHardwareService hardwareService, LifetimePredictor predictor)
{
    _hardwareService = hardwareService;
    _predictor = predictor;

    // 训练模型(假设有历史数据)
    var trainingData = new List<AgingBoardData>
    {
        new AgingBoardData { Temperature = 25, Voltage = 5, Current = 1.2, Lifetime = 1000 },
        new AgingBoardData { Temperature = 30, Voltage = 5.5, Current = 1.5, Lifetime = 800 }
    };
    _predictor.TrainModel(trainingData);
}

private async Task RefreshAsync()
{
    var devices = await _hardwareService.GetDevicesByTypeAsync(SelectedHardwareType);
    foreach (var device in devices.Where(d => d.Category == "老化板"))
    {
        var prediction = _predictor.Predict(new AgingBoardData
        {
            Temperature = (float)device.Temperature,
            Voltage = 5.0f, // 模拟
            Current = 1.2f
        });
        device.Parameters += $", 预测寿命: {prediction:F1} 小时";
    }
    // 更新 UI
}

八、总结与后续扩展

8.1 本篇总结

  • 监控界面:实现了设备状态实时显示、仪表盘和表格。

  • 日志界面:支持实时日志流、过滤和导出。

  • 流程配置:动态设置实验步骤,包含预览和保存。

  • 多设备管理:通过反射动态发现和管理 200+ 设备。

  • 历史数据查询:使用 EF Core 实现分页查询。

  • 云端部署:集成 SignalR 实现实时数据推送。

  • 深度学习:使用 ML.NET 预测老化板寿命。

8.2 后续扩展

  • 分布式架构:支持多上位机协同,基于 gRPC 或 RabbitMQ。

  • 边缘计算:在设备端预处理数据,减少上位机负载。

  • 高级可视化:集成 3D 模型展示烘箱结构。

  • 自动化测试:为每个模块编写单元测试和 UI 测试。

8.3 下一步

请告诉我您希望深入的模块或功能,例如:

  • 具体实验(如 HTRB、HTGB)的 TestController 实现。

  • 硬件驱动层的完整代码(COM、TCP/IP 协议)。

  • 更多 ML.NET 模型(异常检测、热阻预测)。

  • 云端 Web 端可视化界面设计。

您需要哪部分的详细代码或设计?

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐