Files
DMS/DMS.WPF/App.xaml.cs
David P.G 958593b35d 1 feat: 实现触发器-菜单联动功能和事件系统
2
    3 - 实现触发器与菜单联动功能,现在可以同时创建触发器及其关联的菜单项
    4 - 添加触发器更改事件系统,用于通知UI和其他组件触发器状态的变化
    5 - 优化触发器管理服务,改进了添加、修改和删除触发器的逻辑
    6 - 将CreateTriggerAsync方法重命名为AddTriggerAsync,使其语义更准确
    7 - 修改UpdateTriggerAsync方法的参数和返回值类型,提高一致性
    8 - 添加CreateTriggerWithMenuAsync方法用于同时创建触发器和菜单
    9 - 在应用层重构触发器管理逻辑,增加事务支持确保数据一致性
   10 - 更新菜单管理服务,改进并发安全处理
   11 - 调整数据存储服务,使其同步触发器和菜单更新
   12 - 更新触发器对话框和列表视图模型,提升用户体验
   13 - 在依赖注入容器中注册触发器服务
   14 - 修复设备数据服务中的异步调用问题,确保菜单项的正确处理
   15 - 添加缺失的触发器项映射配置
   16 - 创建TriggerChangedEventArgs类处理触发器更改事件
2025-10-19 20:34:20 +08:00

417 lines
20 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Windows;
using AutoMapper;
using AutoMapper.Internal;
using DMS.Application.Configurations;
using DMS.Application.Interfaces;
using DMS.Application.Interfaces.Database;
using DMS.Application.Interfaces.Management;
using DMS.Application.Services;
using DMS.Application.Services.Database;
using DMS.Application.Services.Management;
using DMS.Application.Services.Processors;
using DMS.Application.Services.Triggers;
using DMS.Application.Services.Triggers.Impl;
using DMS.Core.Interfaces;
using DMS.Core.Interfaces.Repositories;
using DMS.Core.Interfaces.Repositories.Triggers;
using DMS.Core.Interfaces.Services;
using DMS.Infrastructure.Configuration;
using DMS.Infrastructure.Data;
using DMS.Infrastructure.Interfaces;
using DMS.Infrastructure.Interfaces.Services;
using DMS.Infrastructure.Repositories;
using DMS.Infrastructure.Services;
using DMS.Infrastructure.Services.Mqtt;
using DMS.Infrastructure.Services.OpcUa;
using DMS.Infrastructure.Services.S7;
using DMS.WPF.Converters;
using DMS.WPF.Factories;
using DMS.WPF.Helper;
using DMS.WPF.Interfaces;
using DMS.WPF.Logging;
using DMS.WPF.Services;
using DMS.WPF.ViewModels;
using DMS.WPF.ViewModels.Dialogs;
using DMS.WPF.ItemViewModel;
using DMS.WPF.Views;
using LiveChartsCore;
using LiveChartsCore.SkiaSharpView;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using NLog;
using NLog.Web;
using SkiaSharp;
using SqlSugar;
using ILogger = Microsoft.Extensions.Logging.ILogger;
using LogLevel = Microsoft.Extensions.Logging.LogLevel;
namespace DMS.WPF;
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : System.Windows.Application
{
public IServiceProvider Services { get; }
public new static App Current => (App)System.Windows.Application.Current;
public IHost Host { get; }
private readonly ILogger<App> _logger;
public App()
{
Host = Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder()
.ConfigureServices((context, services) => { ConfigureServices(services); })
.ConfigureLogging(loggingBuilder => { ConfigureLogging(loggingBuilder); })
.Build();
Services = Host.Services;
_logger = Host.Services.GetRequiredService<ILogger<App>>();
}
protected override async void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
LiveCharts.Configure(config => config.HasGlobalSKTypeface(SKFontManager.Default.MatchCharacter('汉')));
ShutdownMode = ShutdownMode.OnLastWindowClose;
ThemeHelper.InitializeTheme();
await Host.StartAsync();
try
{
Host.Services.GetRequiredService<GrowlNotificationService>();
Host.Services.GetRequiredService<IDeviceMonitoringService>();
DeviceItem.EventService = Host.Services.GetRequiredService<IEventService>();
// 初始化数据处理链
var dataProcessingService = Host.Services.GetRequiredService<IDataProcessingService>();
dataProcessingService.AddProcessor(Host.Services.GetRequiredService<ValueConvertProcessor>());
dataProcessingService.AddProcessor(Host.Services.GetRequiredService<UpdateViewProcessor>());
dataProcessingService.AddProcessor(Host.Services.GetRequiredService<MqttPublishProcessor>());
dataProcessingService.AddProcessor(Host.Services.GetRequiredService<UpdateDbVariableProcessor>());
dataProcessingService.AddProcessor(Host.Services.GetRequiredService<HistoryProcessor>());
// 添加报警处理器
dataProcessingService.AddProcessor(Host.Services.GetRequiredService<DMS.Application.Services.Processors.AlarmProcessor>());
// 添加触发器处理器
dataProcessingService.AddProcessor(Host.Services.GetRequiredService<TriggerProcessor>());
}
catch (Exception exception)
{
var notificationService = Host.Services.GetRequiredService<INotificationService>();
notificationService.ShowError($"加载数据时发生错误,如果是连接字符串不正确,可以在设置界面更改:{exception.Message}", exception);
}
// 订阅报警事件
var alarmService = Host.Services.GetRequiredService<DMS.Application.Interfaces.IAlarmService>();
var alarmEventHandler = Host.Services.GetRequiredService<DMS.Application.EventHandlers.AlarmEventHandler>();
alarmService.OnAlarmTriggered += alarmEventHandler.HandleAlarm;
var splashWindow = Host.Services.GetRequiredService<SplashWindow>();
splashWindow.Show();
}
protected override async void OnExit(ExitEventArgs e)
{
_logger.LogInformation("应用程序正在关闭,开始清理资源...");
try
{
// 获取服务管理器
var opcUaServiceManager = Host.Services.GetService<IOpcUaServiceManager>();
var s7ServiceManager = Host.Services.GetService<IS7ServiceManager>();
var mqttServiceManager = Host.Services.GetService<IMqttServiceManager>();
// 优雅地关闭OPC UA服务
if (opcUaServiceManager != null)
{
_logger.LogInformation("正在关闭OPC UA服务...");
opcUaServiceManager.Dispose();
_logger.LogInformation("OPC UA服务已关闭");
}
// 优雅地关闭S7服务
if (s7ServiceManager != null)
{
_logger.LogInformation("正在关闭S7服务...");
s7ServiceManager.Dispose();
_logger.LogInformation("S7服务已关闭");
}
// 优雅地关闭MQTT服务
if (mqttServiceManager != null)
{
_logger.LogInformation("正在关闭MQTT服务...");
mqttServiceManager.Dispose();
_logger.LogInformation("MQTT服务已关闭");
}
// 停止后台服务
_logger.LogInformation("正在停止后台服务...");
await Host.StopAsync();
_logger.LogInformation("后台服务已停止");
// 释放Host资源
_logger.LogInformation("正在释放Host资源...");
Host.Dispose();
_logger.LogInformation("Host资源已释放");
// 关闭NLog
_logger.LogInformation("正在关闭NLog...");
LogManager.Shutdown();
_logger.LogInformation("NLog已关闭");
}
catch (Exception ex)
{
_logger.LogError(ex, "关闭应用程序时发生错误: {ErrorMessage}", ex.Message);
}
_logger.LogInformation("应用程序已完全关闭");
base.OnExit(e);
}
private void ConfigureServices(IServiceCollection services)
{
// 注册NLogLogger作为Microsoft.Extensions.Logging.ILogger的实现
services.AddSingleton<ILogger, NLogLogger>();
services.AddSingleton<ILoggerFactory, NLogLoggerFactory>();
services.AddSingleton<GrowlNotificationService>();
services.AddSingleton<INotificationService, NotificationService>();
// 注册核心服务
services.AddAutoMapper(cfg =>
{
// 最终解决方案根据异常信息的建议设置此标记以忽略重复的Profile加载。
// 注意:此属性位于 Internal() 方法下。
cfg.Internal()
.AllowAdditiveTypeMapCreation = true;
cfg.AddProfile(new DMS.Application.Profiles.MappingProfile());
cfg.AddProfile(new DMS.Infrastructure.Profiles.MappingProfile());
cfg.AddProfile(new DMS.WPF.Profiles.MappingProfile());
});
// 注册数据处理服务和处理器
// services.AddHostedService<OpcUaBackgroundService>();
//注册OpcUa相关的服务
services.Configure<OpcUaServiceOptions>(options => { });
services.AddSingleton<IOpcUaServiceManager, OpcUaServiceManager>();
services.AddHostedService<OptimizedOpcUaBackgroundService>();
// 注册S7相关的服务
services.AddSingleton<IS7ServiceFactory, S7ServiceFactory>();
services.AddSingleton<IS7ServiceManager, S7ServiceManager>();
services.AddSingleton<IChannelBus, ChannelBus>();
services.AddSingleton<IMessenger, Messenger>();
services.AddHostedService<OptimizedS7BackgroundService>();
services.AddSingleton<IDataProcessingService, DataProcessingService>();
services.AddHostedService(provider =>
(DataProcessingService)provider.GetRequiredService<IDataProcessingService>());
services.AddSingleton<ValueConvertProcessor>();
services.AddSingleton<UpdateViewProcessor>();
services.AddSingleton<UpdateDbVariableProcessor>();
services.AddSingleton<HistoryProcessor>();
services.AddSingleton<MqttPublishProcessor>();
// 注册报警服务和处理器
services.AddSingleton<DMS.Application.Interfaces.IAlarmService, DMS.Application.Services.AlarmService>();
services.AddSingleton<DMS.Application.Services.Processors.AlarmProcessor>();
services.AddSingleton<DMS.Application.EventHandlers.AlarmEventHandler>();
services.AddSingleton<TriggerProcessor>(); // 注册触发器处理器
// 注册Core中的仓库
services.AddSingleton<AppSettings>();
services.AddSingleton<SqlSugarDbContext>();
services.AddSingleton<IInitializeRepository, InitializeRepository>();
services.AddSingleton<IDeviceRepository, DeviceRepository>();
services.AddSingleton<IVariableTableRepository, VariableTableRepository>();
services.AddSingleton<IVariableRepository, VariableRepository>();
services.AddSingleton<IMqttServerRepository, MqttServerRepository>();
services.AddSingleton<IMqttAliasRepository, MqttAliasRepository>();
services.AddSingleton<IMenuRepository, MenuRepository>();
services.AddSingleton<IVariableHistoryRepository, VariableHistoryRepository>();
services.AddSingleton<IUserRepository, UserRepository>();
services.AddSingleton<INlogRepository, NlogRepository>();
services.AddSingleton<IRepositoryManager, RepositoryManager>();
services.AddSingleton<IAlarmHistoryRepository, AlarmHistoryRepository>(); // 添加这行
services.AddSingleton<ITriggerRepository, TriggerRepository>(); // 注册触发器仓储
services.AddSingleton<ITriggerVariableRepository, TriggerVariableRepository>(); // 注册触发器与变量关联仓储
services.AddSingleton<IEmailAccountRepository, EmailAccountRepository>();
services.AddSingleton<IEmailMessageRepository, EmailMessageRepository>();
services.AddSingleton<IEmailTemplateRepository, EmailTemplateRepository>();
services.AddSingleton<IEmailLogRepository, EmailLogRepository>();
services.AddSingleton<IExcelService, ExcelService>();
services.AddTransient<IOpcUaService, OpcUaService>();
services.AddTransient<IMqttService, MqttService>();
services.AddTransient<IMqttServiceFactory, MqttServiceFactory>();
services.AddTransient<IEmailService, EmailService>();
// 注册App服务
services.AddSingleton<IInitializeService, InitializeService>();
services.AddSingleton<IDeviceAppService, DeviceAppService>();
services.AddSingleton<IVariableAppService, VariableAppService>();
services.AddSingleton<IHistoryAppService, HistoryAppService>();
services.AddSingleton<IVariableTableAppService, VariableTableAppService>();
services.AddSingleton<IMenuAppService, MenuAppService>();
services.AddSingleton<IAppCenterService, AppCenterService>();
services.AddSingleton<INavigationService, NavigationService>();
services.AddSingleton<IDialogService, DialogService>();
services.AddSingleton<IAppStorageService, AppStorageService>();
services.AddSingleton<IDeviceManagementService, DeviceManagementService>();
services.AddSingleton<IVariableTableManagementService, VariableTableManagementService>();
services.AddSingleton<IVariableManagementService, VariableManagementService>();
services.AddSingleton<IMenuManagementService, MenuManagementService>();
services.AddSingleton<IMqttManagementService, MqttManagementService>();
services.AddSingleton<IMqttAliasAppService, MqttAliasAppService>();
services.AddSingleton<IMqttAliasManagementService, MqttAliasManagementService>();
services.AddSingleton<ILogManagementService, LogManagementService>();
services.AddSingleton<ITriggerAppService, TriggerAppService>(); // 注册触发器应用服务
services.AddSingleton<ITriggerManagementService, TriggerManagementService>(); // 注册触发器管理服务
services.AddSingleton<ITriggerEvaluationService, TriggerEvaluationService>(); // 注册触发器评估服务
services.AddSingleton<ITriggerActionExecutor, TriggerActionExecutor>(); // 注册触发器动作执行器
services.AddSingleton<ITriggerVariableManagementService, TriggerVariableManagementService>(); // 注册触发器变量管理服务
services.AddSingleton<ITriggerVariableAppService, TriggerVariableAppService>(); // 注册触发器变量应用服务
services.AddSingleton<IDataLoaderService, DataLoaderService>();
services.AddSingleton<INlogAppService, NlogAppService>();
services.AddSingleton<IDeviceMonitoringService, DeviceMonitoringService>();
// 注册MQTT服务管理器
services.AddSingleton<IMqttServiceManager, MqttServiceManager>();
services.AddSingleton<IMqttAliasAppService, MqttAliasAppService>();
services.AddHostedService<MqttBackgroundService>();
// 注册WPF中的服务
services.AddSingleton<IMqttAppService, MqttAppService>();
services.AddSingleton<IEmailAppService, EmailAppService>();
services.AddSingleton<EmailFunctionalityTestService, EmailFunctionalityTestService>();
// 注册转换器 (Converters)
services.AddTransient<EnumToVisibilityConverter>();
services.AddTransient<NullableTimeSpanToSecondsConverter>();
services.AddTransient<BooleanToBrushConverter>();
services.AddTransient<BoolToVisibilityConverter>();
services.AddTransient<CountToVisibilityConverter>();
services.AddTransient<BoolToStringConverter>();
services.AddTransient<BoolToColorConverter>();
// 注册事件服务
services.AddSingleton<DMS.Application.Interfaces.IEventService, DMS.Application.Services.EventService>();
// 注册新的数据服务
services.AddSingleton<IDeviceDataService, DeviceDataService>();
services.AddSingleton<IVariableDataService, VariableDataService>();
services.AddSingleton<IVariableTableDataService, VariableTableDataService>();
services.AddSingleton<IMenuDataService, MenuDataService>();
services.AddSingleton<IMqttDataService, MqttDataService>();
services.AddSingleton<IMqttAliasDataService, MqttAliasDataService>();
services.AddSingleton<ILogDataService, LogDataService>();
services.AddSingleton<ITriggerDataService, TriggerDataService>(); // 注册触发器数据服务
services.AddSingleton<IDataEventService, DataEventService>();
services.AddSingleton<IDataStorageService, DataStorageService>();
services.AddSingleton<IEmailDataService, EmailDataService>();
// 注册主数据服务
services.AddSingleton<IWPFDataService, WPFDataService>();
services.AddSingleton<IEmailAppService, EmailAppService>();
services.AddSingleton<EmailFunctionalityTestService, EmailFunctionalityTestService>();
// 注册视图模型
services.AddSingleton<SplashViewModel>();
services.AddSingleton<MainViewModel>();
services.AddSingleton<HomeViewModel>();
services.AddSingleton<DevicesViewModel>();
services.AddSingleton<DataTransformViewModel>();
services.AddSingleton<SettingViewModel>();
services.AddSingleton<LogHistoryViewModel>();
services.AddTransient<VariableTableViewModel>();
services.AddSingleton<DeviceDetailViewModel>();
services.AddSingleton<MqttsViewModel>();
services.AddSingleton<LogHistoryViewModel>();
services.AddScoped<MqttServerDetailViewModel>();
services.AddScoped<TriggerDetailViewModel>();
services.AddSingleton<VariableHistoryViewModel>();
services.AddSingleton<EmailManagementViewModel>();
services.AddSingleton<TriggersViewModel>(); // 注册 TriggersViewModel
// 注册对话框视图模型
services.AddTransient<DeviceDialogViewModel>();
services.AddTransient<ConfirmDialogViewModel>();
services.AddTransient<VariableTableDialogViewModel>();
services.AddTransient<ImportExcelDialogViewModel>();
services.AddTransient<ImportOpcUaDialogViewModel>();
services.AddTransient<VariableDialogViewModel>();
services.AddTransient<PollLevelDialogViewModel>();
services.AddTransient<IsActiveDialogViewModel>();
services.AddTransient<MqttDialogViewModel>();
services.AddTransient<MqttSelectionDialogViewModel>();
services.AddTransient<MqttAliasBatchEditDialogViewModel>();
services.AddTransient<HistorySettingsDialogViewModel>();
services.AddTransient<AlarmSettingsDialogViewModel>();
services.AddTransient<EmailAccountDialogViewModel>();
services.AddTransient<EmailTemplateDialogViewModel>();
services.AddTransient<TriggerDialogViewModel>(); // 注册 TriggerEditorViewModel
// 注册工厂
services.AddTransient<IVariableItemViewModelFactory, VariableItemViewModelFactory>();
// 注册View视图
services.AddSingleton<SplashWindow>();
services.AddSingleton<SettingView>();
services.AddSingleton<MainView>();
services.AddSingleton<HomeView>();
services.AddSingleton<DevicesView>();
services.AddSingleton<VariableTableView>();
services.AddSingleton<VariableHistoryView>();
services.AddSingleton<LogHistoryView>();
services.AddScoped<DeviceDetailView>();
services.AddScoped<MqttsView>();
services.AddSingleton<EmailManagementView>();
services.AddSingleton<TriggersView>(); // 注册 TriggersView
services.AddSingleton<TriggerDetailView>(); // 注册 TriggersView
}
private void ConfigureLogging(ILoggingBuilder loggingBuilder)
{
LogManager.Setup()
.LoadConfigurationFromFile("Configurations/nlog.config");
loggingBuilder.ClearProviders();
loggingBuilder.SetMinimumLevel(LogLevel.Trace);
// loggingBuilder.addn; // 添加NLog作为日志提供者
// // 捕获未处理的异常并记录
// AppDomain.CurrentDomain.UnhandledException += (sender, args) =>
// {
// var ex = args.ExceptionObject as Exception;
// if (ex != null)
// {
// // 可以使用一个专用的 Logger 来记录未处理异常
// LogManager.GetLogger("UnhandledExceptionLogger")
// .Fatal($"应用程序发生未处理的异常:{ex}");
// }
// };
//
// // 捕获 Dispatcher 线程上的未处理异常 (UI 线程)
// this.DispatcherUnhandledException += (sender, args) =>
// {
// LogManager.GetLogger("DispatcherExceptionLogger")
// .Fatal($"UI 线程发生未处理的异常:{args.Exception}");
// // 标记为已处理,防止应用程序崩溃 (生产环境慎用,可能掩盖问题)
// // args.Handled = true;
// };
//
// // 如果您使用 Task (异步方法) 并且没有正确 await可能会导致异常丢失
// // 可以通过以下方式捕获 Task 中的异常。
// TaskScheduler.UnobservedTaskException += (sender, args) =>
// {
// LogManager.GetLogger("UnobservedTaskExceptionLogger")
// .Fatal($"异步任务发生未观察到的异常:{args.Exception}");
// // args.SetObserved(); // 标记为已观察,防止进程终止
// };
}
}