以下是为 WPF C# 上位机量身定制的完整内容,已按您的要求整理:


1. 完整 Demo 工程结构(WPF版)

IndustrialMonitor.WPF/
├── IndustrialMonitor/                          # 主启动项目
│   ├── App.xaml
│   ├── App.xaml.cs
│   ├── MainWindow.xaml                         # 主窗口 (Shell)
│   ├── MainWindow.xaml.cs
│   │
│   ├── Core/                                   # 核心领域模型
│   │   ├── Models/
│   │   ├── Events/                             # Prism EventAggregator 事件
│   │   └── Interfaces/
│   │
│   ├── Services/                               # 服务层
│   │   ├── Device/
│   │   ├── LinkageService.cs                   # 联动引擎
│   │   ├── AlarmService.cs                     # 报警中心
│   │   ├── LoggingService.cs
│   │   ├── DataAcquisitionService.cs
│   │   └── EmailService.cs
│   │
│   ├── Views/                                  # WPF 视图
│   │   ├── DashboardView.xaml                  # 主监控仪表盘
│   │   ├── LinkageRuleEditorView.xaml          # 联动规则配置界面
│   │   ├── AlarmCenterView.xaml                # 报警中心
│   │   ├── HistoryView.xaml
│   │   └── DeviceListView.xaml
│   │
│   ├── ViewModels/                             # MVVM
│   │   ├── MainViewModel.cs
│   │   ├── DashboardViewModel.cs
│   │   ├── LinkageRuleViewModel.cs
│   │   └── AlarmCenterViewModel.cs
│   │
│   ├── Controls/                               # 自定义控件(Gauge、TrendChart等)
│   ├── Helpers/
│   ├── Assets/                                 # 图片、图标
│   └── Properties/
│
├── IndustrialMonitor.Core/                     # 共享类库(可选)
├── IndustrialMonitor.Tests/
└── packages/

推荐 NuGet 包

  • Prism.Wpf(模块化 + EventAggregator)
  • CommunityToolkit.Mvvm
  • Serilog + Serilog.Sinks.SQLite + Serilog.Sinks.MSSqlServer
  • OxyPlot.Wpf
  • MailKit(邮件推送)

2. 联动规则可视化配置界面(WPF版)

LinkageRuleEditorView.xaml

<UserControl x:Class="IndustrialMonitor.Views.LinkageRuleEditorView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Grid Margin="10">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <!-- 工具栏 -->
        <StackPanel Grid.Row="0" Orientation="Horizontal" Margin="0,0,0,8">
            <Button Content="新增规则" Width="100" Margin="5" Command="{Binding AddRuleCommand}"/>
            <Button Content="保存所有规则" Width="120" Margin="5" Command="{Binding SaveAllCommand}"/>
            <Button Content="删除选中" Width="100" Margin="5" Command="{Binding DeleteRuleCommand}"/>
        </StackPanel>

        <!-- 规则列表 -->
        <DataGrid Grid.Row="1" ItemsSource="{Binding Rules}" 
                  SelectedItem="{Binding SelectedRule}"
                  AutoGenerateColumns="False" IsReadOnly="False">
            <DataGrid.Columns>
                <DataGridTextColumn Header="规则名称" Binding="{Binding RuleName}" Width="180"/>
                <DataGridTextColumn Header="源设备" Binding="{Binding SourceDeviceName}" Width="120"/>
                <DataGridTextColumn Header="条件描述" Binding="{Binding ConditionDescription}" Width="250"/>
                <DataGridTextColumn Header="动作数量" Binding="{Binding Actions.Count}" Width="80"/>
                <DataGridCheckBoxColumn Header="启用" Binding="{Binding IsEnabled}" Width="60"/>
            </DataGrid.Columns>
        </DataGrid>

        <!-- 选中规则详细编辑 -->
        <GroupBox Grid.Row="2" Header="规则详细编辑" Margin="0,10,0,0" 
                  DataContext="{Binding SelectedRule}">
            <StackPanel Margin="8">
                <TextBlock Text="规则名称"/>
                <TextBox Text="{Binding RuleName, UpdateSourceTrigger=PropertyChanged}"/>

                <TextBlock Text="条件表达式" Margin="0,8,0,4"/>
                <TextBox Text="{Binding ConditionExpression}" Height="80" AcceptsReturn="True"
                         VerticalScrollBarVisibility="Auto"/>

                <Button Content="添加联动动作" Margin="0,8" Command="{Binding AddActionCommand}"/>
            </StackPanel>
        </GroupBox>
    </Grid>
</UserControl>

ViewModel 关键代码(LinkageRuleViewModel.cs)

public partial class LinkageRuleViewModel : ObservableObject
{
    [ObservableProperty] private ObservableCollection<LinkageRule> rules = new();
    [ObservableProperty] private LinkageRule? selectedRule;

    [RelayCommand]
    private void AddRule()
    {
        var newRule = new LinkageRule 
        { 
            RuleName = $"联动规则 {rules.Count + 1}",
            IsEnabled = true 
        };
        rules.Add(newRule);
        SelectedRule = newRule;
    }

    [RelayCommand]
    private async Task SaveAll()
    {
        await _linkageService.SaveRulesAsync(rules.ToList());
        Log.Information("联动规则保存成功,共 {Count} 条", rules.Count);
    }
}

3. Serilog + SQLite 完整建表与查询代码

Serilog 配置(App.xaml.cs)

private void ConfigureLogging()
{
    Log.Logger = new LoggerConfiguration()
        .MinimumLevel.Information()
        .Enrich.FromLogContext()
        .Enrich.WithMachineName()
        .WriteTo.SQLite(
            path: "Data/IndustrialMonitor.db",
            tableName: "SystemLogs",
            storeTimestampInUtc: true)
        .WriteTo.File("Logs/log_.txt", rollingInterval: RollingInterval.Day)
        .CreateLogger();
}

SQLite 表结构(自动创建)

-- 系统日志表
CREATE TABLE IF NOT EXISTS SystemLogs (
    Id INTEGER PRIMARY KEY AUTOINCREMENT,
    Timestamp TEXT NOT NULL,
    Level TEXT NOT NULL,
    Message TEXT,
    DeviceId TEXT,
    RuleName TEXT,
    Parameter TEXT,
    Value REAL,
    Exception TEXT,
    Properties TEXT
);

-- 报警记录表
CREATE TABLE IF NOT EXISTS AlarmLogs (
    Id INTEGER PRIMARY KEY AUTOINCREMENT,
    AlarmTime TEXT NOT NULL,
    DeviceId TEXT,
    AlarmType TEXT,
    Description TEXT,
    Severity INTEGER,
    Value REAL,
    Threshold REAL,
    IsConfirmed INTEGER DEFAULT 0,
    ConfirmTime TEXT,
    ConfirmedBy TEXT
);

查询示例

public async Task<List<AlarmLog>> GetAlarmsAsync(DateTime start, DateTime end, int severity = 0)
{
    using var conn = new SQLiteConnection("Data Source=Data/IndustrialMonitor.db");
    string sql = "SELECT * FROM AlarmLogs WHERE AlarmTime BETWEEN @start AND @end";
    
    if (severity > 0)
        sql += " AND Severity >= @severity";
    
    sql += " ORDER BY AlarmTime DESC LIMIT 500";

    return await conn.QueryAsync<AlarmLog>(sql, new { start, end, severity });
}

4. 报警中心与邮件/短信推送实现

AlarmService.cs

public class AlarmService
{
    private readonly Serilog.ILogger _logger;
    private readonly IEmailService _emailService;

    public event EventHandler<AlarmEventArgs>? OnNewAlarm;

    public void RaiseAlarm(AlarmEventArgs alarm)
    {
        _logger.Warning("【{Severity}报警】{Device} - {Desc} | 当前值:{Value}", 
            alarm.Severity, alarm.DeviceId, alarm.Description, alarm.Value);

        OnNewAlarm?.Invoke(this, alarm);

        // 高危报警邮件推送
        if (alarm.Severity >= AlarmSeverity.High)
            _emailService.SendAlarmAsync(alarm);

        SaveToDatabase(alarm);
    }

    private void SaveToDatabase(AlarmEventArgs alarm)
    {
        // 使用 Dapper 或 EF Core 写入 AlarmLogs 表
    }
}

邮件推送(MailKit)

public async Task SendAlarmAsync(AlarmEventArgs alarm)
{
    var message = new MimeMessage();
    message.From.Add(new MailboxAddress("工业监控系统", "monitor@yourcompany.com"));
    message.To.Add(new MailboxAddress("值班工程师", "engineer@yourcompany.com"));
    message.Subject = $"【紧急】{alarm.DeviceId} {alarm.Description}";

    message.Body = new TextPart("html")
    {
        Text = $"""
            <h2 style="color:red">报警信息</h2>
            <p><strong>时间:</strong>{DateTime.Now:yyyy-MM-dd HH:mm:ss}</p>
            <p><strong>设备:</strong>{alarm.DeviceId}</p>
            <p><strong>描述:</strong>{alarm.Description}</p>
            <p><strong>当前值:</strong>{alarm.Value}</p>
            """
    };

    using var client = new SmtpClient();
    await client.ConnectAsync("smtp.exmail.qq.com", 465, true);
    await client.AuthenticateAsync("xxx@exmail.qq.com", "password");
    await client.SendAsync(message);
    await client.DisconnectAsync(true);
}

短信推送:可接入阿里云/腾讯云短信服务,封装类似方法即可。


需要我继续补充以下任意部分?

  • DashboardView + OxyPlot 实时曲线 完整代码
  • Prism EventAggregator 事件定义与使用示例
  • MainWindow.xaml 整体布局
  • ValueTask 高频采集服务 完整实现

请告诉我优先需要哪一块,我会立即输出!

更多推荐