1 feat(mqtt): 实现MQTT服务器状态管理与事件系统
2
3 1. 在MqttServer和MqttServerDto模型中添加IsConnect属性,用于跟踪连接状态
4 2. 重构MqttManagementService服务,使用事件驱动方式管理服务器状态变化
5 3. 实现MqttServerChangedEventArgs事件参数类,支持区分不同变更类型
6 4. 在IEventService中添加OnMqttServerChanged事件,实现事件通知机制
7 5. 优化数据存储结构,将MqttServers从ObservableCollection改为ObservableDictionary
8 6. 更新MqttServiceManager以正确处理连接状态和事件触发
9 7. 在WPF层更新UI以响应服务器状态变化
10 8. 删除不再需要的Helper类(DataServicesHelper, MessageHelper, SiemensHelper)
11 9. 在NLog配置中添加调试器输出目标以便调试
12 10. 完善VariableHistoryViewModel防止空引用异常
This commit is contained in:
@@ -12,6 +12,7 @@ public class MqttServerDto
|
||||
public string ServerName { get; set; }
|
||||
public string ServerUrl { get; set; }
|
||||
public int Port { get; set; }
|
||||
public bool IsConnect { get; set; }
|
||||
public string Username { get; set; }
|
||||
public string Password { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace DMS.Application.Events
|
||||
/// <summary>
|
||||
/// 变更类型
|
||||
/// </summary>
|
||||
public DataChangeType ChangeType { get; }
|
||||
public ActionChangeType ChangeType { get; }
|
||||
|
||||
/// <summary>
|
||||
/// MQTT服务器DTO
|
||||
@@ -19,20 +19,22 @@ namespace DMS.Application.Events
|
||||
public MqttServerDto MqttServer { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 变更时间
|
||||
/// 发生变化的属性类型
|
||||
/// </summary>
|
||||
public DateTime ChangeTime { get; }
|
||||
public MqttServerPropertyType PropertyType { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="changeType">变更类型</param>
|
||||
/// <param name="mqttServer">MQTT服务器DTO</param>
|
||||
public MqttServerChangedEventArgs(DataChangeType changeType, MqttServerDto mqttServer)
|
||||
/// <param name="propertyType">发生变化的属性类型</param>
|
||||
public MqttServerChangedEventArgs(ActionChangeType changeType, MqttServerDto mqttServer, MqttServerPropertyType propertyType = MqttServerPropertyType.All)
|
||||
{
|
||||
ChangeType = changeType;
|
||||
MqttServer = mqttServer;
|
||||
ChangeTime = DateTime.Now;
|
||||
PropertyType = propertyType;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using DMS.Application.DTOs;
|
||||
using DMS.Core.Models;
|
||||
|
||||
namespace DMS.Application.Interfaces.Database;
|
||||
|
||||
@@ -27,8 +28,10 @@ public interface IMqttAppService
|
||||
/// </summary>
|
||||
Task UpdateMqttServerAsync(MqttServerDto mqttServerDto);
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 异步删除一个MQTT服务器。
|
||||
/// 异步根据ID删除一个MQTT服务器。
|
||||
/// </summary>
|
||||
Task DeleteMqttServerAsync(int id);
|
||||
Task<int> DeleteMqttServerAsync(int id);
|
||||
}
|
||||
@@ -67,6 +67,18 @@ public interface IEventService
|
||||
/// <param name="e">MQTT连接状态改变事件参数</param>
|
||||
void RaiseMqttConnectionChanged(object sender, MqttConnectionChangedEventArgs e);
|
||||
|
||||
/// <summary>
|
||||
/// MQTT服务器改变事件
|
||||
/// </summary>
|
||||
event EventHandler<MqttServerChangedEventArgs> OnMqttServerChanged;
|
||||
|
||||
/// <summary>
|
||||
/// 触发MQTT服务器改变事件
|
||||
/// </summary>
|
||||
/// <param name="sender">事件发送者</param>
|
||||
/// <param name="e">MQTT服务器改变事件参数</param>
|
||||
void RaiseMqttServerChanged(object sender, MqttServerChangedEventArgs e);
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
@@ -28,19 +28,4 @@ public interface IMqttManagementService
|
||||
/// 异步删除一个MQTT服务器。
|
||||
/// </summary>
|
||||
Task DeleteMqttServerAsync(int id);
|
||||
|
||||
/// <summary>
|
||||
/// 在内存中添加MQTT服务器
|
||||
/// </summary>
|
||||
void AddMqttServerToMemory(MqttServerDto mqttServerDto);
|
||||
|
||||
/// <summary>
|
||||
/// 在内存中更新MQTT服务器
|
||||
/// </summary>
|
||||
void UpdateMqttServerInMemory(MqttServerDto mqttServerDto);
|
||||
|
||||
/// <summary>
|
||||
/// 在内存中删除MQTT服务器
|
||||
/// </summary>
|
||||
void RemoveMqttServerFromMemory(int mqttServerId);
|
||||
}
|
||||
@@ -98,24 +98,23 @@ public class MqttAppService : IMqttAppService
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 异步删除一个MQTT服务器(事务性操作)。
|
||||
/// 异步根据ID删除一个MQTT服务器(事务性操作)。
|
||||
/// </summary>
|
||||
/// <param name="id">要删除MQTT服务器的ID。</param>
|
||||
/// <returns>表示异步操作的任务。</returns>
|
||||
/// <returns>如果删除成功则为 true,否则为 false。</returns>
|
||||
/// <exception cref="ApplicationException">如果删除MQTT服务器时发生错误。</exception>
|
||||
public async Task DeleteMqttServerAsync(int id)
|
||||
public async Task<int> DeleteMqttServerAsync(int id)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _repoManager.BeginTranAsync();
|
||||
await _repoManager.MqttServers.DeleteByIdAsync(id);
|
||||
await _repoManager.CommitAsync();
|
||||
return await _repoManager.MqttServers.DeleteByIdAsync(id);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await _repoManager.RollbackAsync();
|
||||
throw new ApplicationException("删除MQTT服务器时发生错误,操作已回滚。", ex);
|
||||
throw new ApplicationException($"删除MQTT服务器时发生错误,操作已回滚,错误信息:{ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -145,5 +145,20 @@ public class EventService : IEventService
|
||||
MqttConnectionChanged?.Invoke(sender, e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MQTT服务器改变事件
|
||||
/// </summary>
|
||||
public event EventHandler<MqttServerChangedEventArgs> OnMqttServerChanged;
|
||||
|
||||
/// <summary>
|
||||
/// 触发MQTT服务器改变事件
|
||||
/// </summary>
|
||||
/// <param name="sender">事件发送者</param>
|
||||
/// <param name="e">MQTT服务器改变事件参数</param>
|
||||
public void RaiseMqttServerChanged(object sender, MqttServerChangedEventArgs e)
|
||||
{
|
||||
OnMqttServerChanged?.Invoke(sender, e);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -14,16 +14,13 @@ public class MqttManagementService : IMqttManagementService
|
||||
{
|
||||
private readonly IMqttAppService _mqttAppService;
|
||||
private readonly IAppDataStorageService _appDataStorageService;
|
||||
private readonly IEventService _eventService;
|
||||
|
||||
/// <summary>
|
||||
/// 当MQTT服务器数据发生变化时触发
|
||||
/// </summary>
|
||||
public event EventHandler<MqttServerChangedEventArgs> MqttServerChanged;
|
||||
|
||||
public MqttManagementService(IMqttAppService mqttAppService,IAppDataStorageService appDataStorageService)
|
||||
public MqttManagementService(IMqttAppService mqttAppService, IAppDataStorageService appDataStorageService, IEventService eventService)
|
||||
{
|
||||
_mqttAppService = mqttAppService;
|
||||
_appDataStorageService = appDataStorageService;
|
||||
_eventService = eventService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -47,7 +44,19 @@ public class MqttManagementService : IMqttManagementService
|
||||
/// </summary>
|
||||
public async Task<int> CreateMqttServerAsync(MqttServerDto mqttServerDto)
|
||||
{
|
||||
return await _mqttAppService.CreateMqttServerAsync(mqttServerDto);
|
||||
var result = await _mqttAppService.CreateMqttServerAsync(mqttServerDto);
|
||||
|
||||
// 创建成功后,将MQTT服务器添加到内存中
|
||||
if (result > 0)
|
||||
{
|
||||
mqttServerDto.Id = result; // 假设返回的ID是新创建的
|
||||
if (_appDataStorageService.MqttServers.TryAdd(mqttServerDto.Id, mqttServerDto))
|
||||
{
|
||||
_eventService.RaiseMqttServerChanged(this, new MqttServerChangedEventArgs(ActionChangeType.Added, mqttServerDto));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -56,6 +65,10 @@ public class MqttManagementService : IMqttManagementService
|
||||
public async Task UpdateMqttServerAsync(MqttServerDto mqttServerDto)
|
||||
{
|
||||
await _mqttAppService.UpdateMqttServerAsync(mqttServerDto);
|
||||
|
||||
// 更新成功后,更新内存中的MQTT服务器
|
||||
_appDataStorageService.MqttServers.AddOrUpdate(mqttServerDto.Id, mqttServerDto, (key, oldValue) => mqttServerDto);
|
||||
_eventService.RaiseMqttServerChanged(this, new MqttServerChangedEventArgs(ActionChangeType.Updated, mqttServerDto));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -63,45 +76,18 @@ public class MqttManagementService : IMqttManagementService
|
||||
/// </summary>
|
||||
public async Task DeleteMqttServerAsync(int id)
|
||||
{
|
||||
await _mqttAppService.DeleteMqttServerAsync(id);
|
||||
}
|
||||
var mqttServer = await _mqttAppService.GetMqttServerByIdAsync(id); // 获取MQTT服务器信息用于内存删除
|
||||
var result = await _mqttAppService.DeleteMqttServerAsync(id);
|
||||
|
||||
/// <summary>
|
||||
/// 在内存中添加MQTT服务器
|
||||
/// </summary>
|
||||
public void AddMqttServerToMemory(MqttServerDto mqttServerDto)
|
||||
// 删除成功后,从内存中移除MQTT服务器
|
||||
if (result>0)
|
||||
{
|
||||
if (_appDataStorageService.MqttServers.TryAdd(mqttServerDto.Id, mqttServerDto))
|
||||
if (_appDataStorageService.MqttServers.TryRemove(id, out var mqttServerDto))
|
||||
{
|
||||
OnMqttServerChanged(new MqttServerChangedEventArgs(DataChangeType.Added, mqttServerDto));
|
||||
_eventService.RaiseMqttServerChanged(this, new MqttServerChangedEventArgs(ActionChangeType.Deleted, mqttServerDto));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在内存中更新MQTT服务器
|
||||
/// </summary>
|
||||
public void UpdateMqttServerInMemory(MqttServerDto mqttServerDto)
|
||||
{
|
||||
_appDataStorageService.MqttServers.AddOrUpdate(mqttServerDto.Id, mqttServerDto, (key, oldValue) => mqttServerDto);
|
||||
OnMqttServerChanged(new MqttServerChangedEventArgs(DataChangeType.Updated, mqttServerDto));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 在内存中删除MQTT服务器
|
||||
/// </summary>
|
||||
public void RemoveMqttServerFromMemory(int mqttServerId)
|
||||
{
|
||||
if (_appDataStorageService.MqttServers.TryRemove(mqttServerId, out var mqttServerDto))
|
||||
{
|
||||
OnMqttServerChanged(new MqttServerChangedEventArgs(DataChangeType.Deleted, mqttServerDto));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 触发MQTT服务器变更事件
|
||||
/// </summary>
|
||||
protected virtual void OnMqttServerChanged(MqttServerChangedEventArgs e)
|
||||
{
|
||||
MqttServerChanged?.Invoke(this, e);
|
||||
}
|
||||
}
|
||||
83
DMS.Core/Enums/MqttServerPropertyType.cs
Normal file
83
DMS.Core/Enums/MqttServerPropertyType.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
namespace DMS.Core.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// MQTT服务器属性类型枚举
|
||||
/// </summary>
|
||||
public enum MqttServerPropertyType
|
||||
{
|
||||
/// <summary>
|
||||
/// 服务器名称
|
||||
/// </summary>
|
||||
ServerName,
|
||||
|
||||
/// <summary>
|
||||
/// 服务器URL
|
||||
/// </summary>
|
||||
ServerUrl,
|
||||
|
||||
/// <summary>
|
||||
/// 端口
|
||||
/// </summary>
|
||||
Port,
|
||||
|
||||
/// <summary>
|
||||
/// 是否连接
|
||||
/// </summary>
|
||||
IsConnect,
|
||||
|
||||
/// <summary>
|
||||
/// 用户名
|
||||
/// </summary>
|
||||
Username,
|
||||
|
||||
/// <summary>
|
||||
/// 密码
|
||||
/// </summary>
|
||||
Password,
|
||||
|
||||
/// <summary>
|
||||
/// 是否激活
|
||||
/// </summary>
|
||||
IsActive,
|
||||
|
||||
/// <summary>
|
||||
/// 订阅主题
|
||||
/// </summary>
|
||||
SubscribeTopic,
|
||||
|
||||
/// <summary>
|
||||
/// 发布主题
|
||||
/// </summary>
|
||||
PublishTopic,
|
||||
|
||||
/// <summary>
|
||||
/// 客户端ID
|
||||
/// </summary>
|
||||
ClientId,
|
||||
|
||||
/// <summary>
|
||||
/// 消息格式
|
||||
/// </summary>
|
||||
MessageFormat,
|
||||
|
||||
/// <summary>
|
||||
/// 消息头
|
||||
/// </summary>
|
||||
MessageHeader,
|
||||
|
||||
/// <summary>
|
||||
/// 消息内容
|
||||
/// </summary>
|
||||
MessageContent,
|
||||
|
||||
/// <summary>
|
||||
/// 消息尾
|
||||
/// </summary>
|
||||
MessageFooter,
|
||||
|
||||
/// <summary>
|
||||
/// 所有属性
|
||||
/// </summary>
|
||||
All
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,8 @@ public class MqttServer
|
||||
public string Username { get; set; } // 用户名
|
||||
public string Password { get; set; } // 密码
|
||||
public bool IsActive { get; set; } // 是否启用
|
||||
public bool IsConnect { get; set; } // 是否启用
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// MQTT订阅主题。
|
||||
|
||||
@@ -189,7 +189,7 @@ namespace DMS.Infrastructure.Services.Mqtt
|
||||
|
||||
foreach (var mqttServerDto in mqttServerDtos)
|
||||
{
|
||||
// 将 MqttServerDto 转换为 MqttServer
|
||||
// 将 MqttServerDto 转换为 MqttServerConfig
|
||||
var mqttServer = new MqttServer
|
||||
{
|
||||
Id = mqttServerDto.Id,
|
||||
|
||||
@@ -12,17 +12,13 @@ namespace DMS.Infrastructure.Services.Mqtt
|
||||
/// <summary>
|
||||
/// MQTT服务器配置
|
||||
/// </summary>
|
||||
public MqttServer MqttServer { get; set; }
|
||||
public MqttServer MqttServerConfig { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// MQTT服务实例
|
||||
/// </summary>
|
||||
public IMqttService MqttService { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 连接状态
|
||||
/// </summary>
|
||||
public bool IsConnected { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 重连尝试次数
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using AutoMapper;
|
||||
using DMS.Application.DTOs;
|
||||
using DMS.Application.Events;
|
||||
using DMS.Application.Interfaces;
|
||||
using DMS.Core.Enums;
|
||||
using DMS.Core.Interfaces.Services;
|
||||
using DMS.Core.Models;
|
||||
using DMS.Infrastructure.Interfaces.Services;
|
||||
@@ -18,6 +22,8 @@ namespace DMS.Infrastructure.Services.Mqtt
|
||||
private readonly IDataProcessingService _dataProcessingService;
|
||||
private readonly IAppDataCenterService _appDataCenterService;
|
||||
private readonly IMqttServiceFactory _mqttServiceFactory;
|
||||
private readonly IEventService _eventService;
|
||||
private readonly IMapper _mapper;
|
||||
private readonly ConcurrentDictionary<int, MqttDeviceContext> _mqttContexts;
|
||||
private readonly SemaphoreSlim _semaphore;
|
||||
private bool _disposed = false;
|
||||
@@ -26,12 +32,16 @@ namespace DMS.Infrastructure.Services.Mqtt
|
||||
ILogger<MqttServiceManager> logger,
|
||||
IDataProcessingService dataProcessingService,
|
||||
IAppDataCenterService appDataCenterService,
|
||||
IMqttServiceFactory mqttServiceFactory)
|
||||
IMqttServiceFactory mqttServiceFactory,
|
||||
IEventService eventService,
|
||||
IMapper mapper)
|
||||
{
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_dataProcessingService = dataProcessingService ?? throw new ArgumentNullException(nameof(dataProcessingService));
|
||||
_appDataCenterService = appDataCenterService ?? throw new ArgumentNullException(nameof(appDataCenterService));
|
||||
_mqttServiceFactory = mqttServiceFactory ?? throw new ArgumentNullException(nameof(mqttServiceFactory));
|
||||
_eventService = eventService ?? throw new ArgumentNullException(nameof(eventService));
|
||||
_mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
|
||||
_mqttContexts = new ConcurrentDictionary<int, MqttDeviceContext>();
|
||||
_semaphore = new SemaphoreSlim(10, 10); // 默认最大并发连接数为10
|
||||
}
|
||||
@@ -56,13 +66,17 @@ namespace DMS.Infrastructure.Services.Mqtt
|
||||
|
||||
var context = new MqttDeviceContext
|
||||
{
|
||||
MqttServer = mqttServer,
|
||||
MqttServerConfig = mqttServer,
|
||||
MqttService = _mqttServiceFactory.CreateService(),
|
||||
IsConnected = false
|
||||
};
|
||||
|
||||
_mqttContexts.AddOrUpdate(mqttServer.Id, context, (key, oldValue) => context);
|
||||
_logger.LogInformation("已添加MQTT服务器 {MqttServerId} 到监控列表", mqttServer.Id);
|
||||
|
||||
// 使用AutoMapper触发MQTT服务器改变事件
|
||||
var mqttServerDto = _mapper.Map<MqttServerDto>(mqttServer);
|
||||
|
||||
_eventService.RaiseMqttServerChanged(this, new MqttServerChangedEventArgs(Core.Enums.ActionChangeType.Added, mqttServerDto));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -74,6 +88,11 @@ namespace DMS.Infrastructure.Services.Mqtt
|
||||
{
|
||||
await DisconnectMqttServerAsync(mqttServerId, cancellationToken);
|
||||
_logger.LogInformation("已移除MQTT服务器 {MqttServerId} 的监控", mqttServerId);
|
||||
|
||||
// 使用AutoMapper触发MQTT服务器删除事件
|
||||
var mqttServerDto = _mapper.Map<MqttServerDto>(context.MqttServerConfig);
|
||||
|
||||
_eventService.RaiseMqttServerChanged(this, new MqttServerChangedEventArgs(Core.Enums.ActionChangeType.Deleted, mqttServerDto));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +117,7 @@ namespace DMS.Infrastructure.Services.Mqtt
|
||||
/// </summary>
|
||||
public bool IsMqttServerConnected(int mqttServerId)
|
||||
{
|
||||
return _mqttContexts.TryGetValue(mqttServerId, out var context) && context.IsConnected;
|
||||
return _mqttContexts.TryGetValue(mqttServerId, out var context) && context.MqttService.IsConnected;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -136,7 +155,7 @@ namespace DMS.Infrastructure.Services.Mqtt
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("正在连接MQTT服务器 {ServerName} ({ServerUrl}:{Port})",
|
||||
context.MqttServer.ServerName, context.MqttServer.ServerUrl, context.MqttServer.Port);
|
||||
context.MqttServerConfig.ServerName, context.MqttServerConfig.ServerUrl, context.MqttServerConfig.Port);
|
||||
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
|
||||
@@ -145,40 +164,44 @@ namespace DMS.Infrastructure.Services.Mqtt
|
||||
using var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutToken.Token);
|
||||
|
||||
await context.MqttService.ConnectAsync(
|
||||
context.MqttServer.ServerUrl,
|
||||
context.MqttServer.Port,
|
||||
context.MqttServer.ClientId,
|
||||
context.MqttServer.Username,
|
||||
context.MqttServer.Password);
|
||||
context.MqttServerConfig.ServerUrl,
|
||||
context.MqttServerConfig.Port,
|
||||
context.MqttServerConfig.ClientId,
|
||||
context.MqttServerConfig.Username,
|
||||
context.MqttServerConfig.Password);
|
||||
|
||||
stopwatch.Stop();
|
||||
_logger.LogInformation("MQTT服务器 {ServerName} 连接耗时 {ElapsedMs} ms",
|
||||
context.MqttServer.ServerName, stopwatch.ElapsedMilliseconds);
|
||||
|
||||
context.MqttServerConfig.ServerName, stopwatch.ElapsedMilliseconds);
|
||||
if (context.MqttService.IsConnected)
|
||||
{
|
||||
context.IsConnected = true;
|
||||
context.ReconnectAttempts = 0; // 重置重连次数
|
||||
|
||||
context.MqttServerConfig.IsConnect=true;
|
||||
// 订阅主题
|
||||
if (!string.IsNullOrEmpty(context.MqttServer.SubscribeTopic))
|
||||
if (!string.IsNullOrEmpty(context.MqttServerConfig.SubscribeTopic))
|
||||
{
|
||||
await context.MqttService.SubscribeAsync(context.MqttServer.SubscribeTopic);
|
||||
await context.MqttService.SubscribeAsync(context.MqttServerConfig.SubscribeTopic);
|
||||
}
|
||||
|
||||
_logger.LogInformation("MQTT服务器 {ServerName} 连接成功", context.MqttServer.ServerName);
|
||||
_logger.LogInformation("MQTT服务器 {ServerName} 连接成功", context.MqttServerConfig.ServerName);
|
||||
|
||||
//
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("MQTT服务器 {ServerName} 连接失败", context.MqttServer.ServerName);
|
||||
context.MqttServerConfig.IsConnect = false;
|
||||
_logger.LogWarning("MQTT服务器 {ServerName} 连接失败", context.MqttServerConfig.ServerName);
|
||||
}
|
||||
//触发MQTT连接状态改变事件
|
||||
_eventService.RaiseMqttServerChanged(this, new MqttServerChangedEventArgs(ActionChangeType.Updated, _mapper.Map<MqttServerDto>(context.MqttServerConfig), MqttServerPropertyType.IsConnect));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "连接MQTT服务器 {ServerName} 时发生错误: {ErrorMessage}",
|
||||
context.MqttServer.ServerName, ex.Message);
|
||||
context.IsConnected = false;
|
||||
context.MqttServerConfig.ServerName, ex.Message);
|
||||
context.ReconnectAttempts++;
|
||||
context.MqttServerConfig.IsConnect = false;
|
||||
_eventService.RaiseMqttServerChanged(this, new MqttServerChangedEventArgs(ActionChangeType.Updated, _mapper.Map<MqttServerDto>(context.MqttServerConfig), MqttServerPropertyType.IsConnect));
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -196,15 +219,18 @@ namespace DMS.Infrastructure.Services.Mqtt
|
||||
|
||||
try
|
||||
{
|
||||
_logger.LogInformation("正在断开MQTT服务器 {ServerName} 的连接", context.MqttServer.ServerName);
|
||||
_logger.LogInformation("正在断开MQTT服务器 {ServerName} 的连接", context.MqttServerConfig.ServerName);
|
||||
await context.MqttService.DisconnectAsync();
|
||||
context.IsConnected = false;
|
||||
_logger.LogInformation("MQTT服务器 {ServerName} 连接已断开", context.MqttServer.ServerName);
|
||||
_logger.LogInformation("MQTT服务器 {ServerName} 连接已断开", context.MqttServerConfig.ServerName);
|
||||
|
||||
// 如果连接状态从连接变为断开,触发事件
|
||||
context.MqttServerConfig.IsConnect = false;
|
||||
_eventService.RaiseMqttServerChanged(this, new MqttServerChangedEventArgs(ActionChangeType.Updated, _mapper.Map<MqttServerDto>(context.MqttServerConfig), MqttServerPropertyType.IsConnect));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "断开MQTT服务器 {ServerName} 连接时发生错误: {ErrorMessage}",
|
||||
context.MqttServer.ServerName, ex.Message);
|
||||
context.MqttServerConfig.ServerName, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,26 +251,26 @@ namespace DMS.Infrastructure.Services.Mqtt
|
||||
return;
|
||||
}
|
||||
|
||||
if (!context.IsConnected)
|
||||
if (!context.MqttService.IsConnected)
|
||||
{
|
||||
_logger.LogWarning("MQTT服务器 {ServerName} 未连接,跳过发布", context.MqttServer.ServerName);
|
||||
_logger.LogWarning("MQTT服务器 {ServerName} 未连接,跳过发布", context.MqttServerConfig.ServerName);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var topic = context.MqttServer.PublishTopic;
|
||||
var topic = context.MqttServerConfig.PublishTopic;
|
||||
|
||||
var sendMsg = BuildSendMessage(variableMqtt);
|
||||
|
||||
await context.MqttService.PublishAsync(topic, sendMsg);
|
||||
_logger.LogDebug("成功向MQTT服务器 {ServerName} 发布变量 {VariableName} 的数据:{sendMsg}",
|
||||
context.MqttServer.ServerName, variableMqtt.Variable.Name,sendMsg);
|
||||
context.MqttServerConfig.ServerName, variableMqtt.Variable.Name, sendMsg);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "向MQTT服务器 {ServerName} 发布变量 {VariableName} 数据时发生错误: {ErrorMessage}",
|
||||
context.MqttServer.ServerName, variableMqtt.Variable.Name, ex.Message);
|
||||
context.MqttServerConfig.ServerName, variableMqtt.Variable.Name, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -253,8 +279,8 @@ namespace DMS.Infrastructure.Services.Mqtt
|
||||
StringBuilder sb = new StringBuilder();
|
||||
var now = DateTime.Now;
|
||||
var timestamp = ((DateTimeOffset)now).ToUnixTimeMilliseconds();
|
||||
sb.Append(variableMqtt.MqttServer.MessageHeader.Replace("{timestamp}",timestamp.ToString()));
|
||||
sb.Append(variableMqtt.MqttServer.MessageContent.Replace("{name}",variableMqtt.Alias).Replace("{value}",variableMqtt.Variable.DataValue));
|
||||
sb.Append(variableMqtt.MqttServer.MessageHeader.Replace("{timestamp}", timestamp.ToString()));
|
||||
sb.Append(variableMqtt.MqttServer.MessageContent.Replace("{name}", variableMqtt.Alias).Replace("{value}", variableMqtt.Variable.DataValue));
|
||||
sb.Append(variableMqtt.MqttServer.MessageFooter);
|
||||
|
||||
return sb.ToString();
|
||||
@@ -283,10 +309,10 @@ namespace DMS.Infrastructure.Services.Mqtt
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!context.IsConnected)
|
||||
if (!context.MqttService.IsConnected)
|
||||
{
|
||||
_logger.LogWarning("MQTT服务器 {ServerName} 未连接,跳过 {Count} 条消息",
|
||||
context.MqttServer.ServerName, group.Count());
|
||||
context.MqttServerConfig.ServerName, group.Count());
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -294,19 +320,19 @@ namespace DMS.Infrastructure.Services.Mqtt
|
||||
{
|
||||
foreach (var variableMqtt in group)
|
||||
{
|
||||
var topic = context.MqttServer.PublishTopic;
|
||||
var topic = context.MqttServerConfig.PublishTopic;
|
||||
var payload = variableMqtt.Variable?.DataValue?.ToString() ?? string.Empty;
|
||||
|
||||
await context.MqttService.PublishAsync(topic, payload);
|
||||
}
|
||||
|
||||
_logger.LogInformation("成功向MQTT服务器 {ServerName} 发布 {Count} 条变量数据",
|
||||
context.MqttServer.ServerName, group.Count());
|
||||
context.MqttServerConfig.ServerName, group.Count());
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "向MQTT服务器 {ServerName} 批量发布变量数据时发生错误: {ErrorMessage}",
|
||||
context.MqttServer.ServerName, ex.Message);
|
||||
context.MqttServerConfig.ServerName, ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -331,7 +357,7 @@ namespace DMS.Infrastructure.Services.Mqtt
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "断开MQTT服务器 {ServerName} 连接时发生错误",
|
||||
context.MqttServer?.ServerName ?? "Unknown");
|
||||
context.MqttServerConfig?.ServerName ?? "Unknown");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,11 @@
|
||||
xsi:type="Console"
|
||||
layout="${date:format=HH\:mm\:ss} ${level} ${threadid} ${message}${exception:format=tostring}"/>
|
||||
|
||||
<!-- 输出窗口日志 -->
|
||||
<target name="debugger"
|
||||
xsi:type="Debugger"
|
||||
layout="${date:format=HH\:mm\:ss} ${level} ${threadid} ${message}${exception:format=tostring}"/>
|
||||
|
||||
<!-- 数据库日志 -->
|
||||
<target name="database"
|
||||
xsi:type="Database"
|
||||
@@ -71,6 +76,7 @@
|
||||
|
||||
<rules>
|
||||
<logger name="*" minlevel="Trace" writeTo="logconsole"/>
|
||||
<logger name="*" minlevel="Trace" writeTo="debugger"/>
|
||||
<logger name="*" minlevel="Info" writeTo="logfile"/>
|
||||
<!-- 路由日志到数据库 -->
|
||||
<logger name="*" minlevel="Warning" writeTo="database"/>
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
|
||||
using DMS.Core.Enums;
|
||||
using DMS.Core.Models;
|
||||
using DMS.WPF.ViewModels;
|
||||
using DMS.WPF.ViewModels;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace DMS.WPF.Helper;
|
||||
|
||||
public class DataServicesHelper
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 从设备列表中找到变量表VarTable对象
|
||||
/// </summary>
|
||||
/// <param name="vtableId">VarTable的ID</param>
|
||||
/// <returns>如果找到择返回对象,否则返回null</returns>
|
||||
public static VariableTable FindVarTableForDevice(List<Device> devices, int vtableId)
|
||||
{
|
||||
VariableTable varTable = null;
|
||||
foreach (var device in devices)
|
||||
{
|
||||
varTable = device.VariableTables.FirstOrDefault(v => v.Id == vtableId);
|
||||
if (varTable != null)
|
||||
return varTable;
|
||||
}
|
||||
|
||||
return varTable;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static MenuBean FindMenusForDevice(Device device, IEnumerable<MenuBean> menus)
|
||||
{
|
||||
// if (menus == null)
|
||||
// {
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// foreach (var menu in menus)
|
||||
// {
|
||||
// // 检查当前菜单项是否匹配
|
||||
// if (menu.Type==MenuType.DeviceMenu && menu.DataId ==device.Id)
|
||||
// {
|
||||
// return menu;
|
||||
// }
|
||||
//
|
||||
// // 递归搜索子菜单
|
||||
// var foundInSubMenu = FindMenusForDevice(device, menu.Items);
|
||||
// if (foundInSubMenu != null)
|
||||
// {
|
||||
// return foundInSubMenu;
|
||||
// }
|
||||
// }
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 给菜单排序
|
||||
/// </summary>
|
||||
/// <param name="menu"></param>
|
||||
public static void SortMenus(MenuBean menu)
|
||||
{
|
||||
// if (menu.Items == null || menu.Items.Count() == 0)
|
||||
// return;
|
||||
// menu.Items.Sort((a, b) =>
|
||||
// a.Type.ToString().Length.CompareTo(b.Type.ToString().Length)
|
||||
// );
|
||||
// foreach (var menuItem in menu.Items)
|
||||
// {
|
||||
// SortMenus(menuItem);
|
||||
// }
|
||||
}
|
||||
|
||||
public static ViewModelBase GetMainViewModel(string name)
|
||||
{
|
||||
ViewModelBase navgateVM = App.Current.Services.GetRequiredService<HomeViewModel>();
|
||||
switch (name)
|
||||
{
|
||||
case "主页":
|
||||
navgateVM = App.Current.Services.GetRequiredService<HomeViewModel>();
|
||||
break;
|
||||
case "设备":
|
||||
navgateVM = App.Current.Services.GetRequiredService<DevicesViewModel>();
|
||||
break;
|
||||
case "Mqtt服务器":
|
||||
navgateVM = App.Current.Services.GetRequiredService<MqttsViewModel>();
|
||||
break;
|
||||
case "数据转换":
|
||||
navgateVM = App.Current.Services.GetRequiredService<DataTransformViewModel>();
|
||||
break;
|
||||
case "设置":
|
||||
navgateVM = App.Current.Services.GetRequiredService<SettingViewModel>();
|
||||
break;
|
||||
}
|
||||
|
||||
return navgateVM;
|
||||
}
|
||||
|
||||
public static MenuBean FindVarTableMenu(int varTableId, List<MenuBean> menus)
|
||||
{
|
||||
// if (menus == null)
|
||||
// {
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// foreach (var menu in menus)
|
||||
// {
|
||||
// // 检查当前菜单项是否匹配
|
||||
// if (menu.Type==MenuType.VariableTableMenu && menu.DataId ==varTableId)
|
||||
// {
|
||||
// return menu;
|
||||
// }
|
||||
//
|
||||
// // 递归搜索子菜单
|
||||
// var foundInSubMenu = FindVarTableMenu(varTableId, menu.Items);
|
||||
// if (foundInSubMenu != null)
|
||||
// {
|
||||
// return foundInSubMenu;
|
||||
// }
|
||||
// }
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using DMS.Core.Enums;
|
||||
using DMS.Message;
|
||||
using DMS.WPF.ViewModels;
|
||||
|
||||
namespace DMS.WPF.Helper;
|
||||
|
||||
public class MessageHelper
|
||||
{
|
||||
public static void Send<T>(T message) where T : class
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send<T>(message);
|
||||
}
|
||||
/// <summary>
|
||||
/// 发送加载消息
|
||||
/// </summary>
|
||||
/// <param name="loadType">加载的类型,如菜单</param>
|
||||
public static void SendLoadMessage(LoadTypes loadType)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send<LoadMessage>(new LoadMessage(loadType));
|
||||
}
|
||||
/// <summary>
|
||||
/// 发送导航消息
|
||||
/// </summary>
|
||||
/// <param name="vm">导航View的ViewModel</param>
|
||||
/// <param name="param">带的参数</param>
|
||||
public static void SendNavgatorMessage(ViewModelBase vm)
|
||||
{
|
||||
WeakReferenceMessenger.Default.Send<NavgatorMessage>(new NavgatorMessage(vm));
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
namespace DMS.Helper;
|
||||
|
||||
/// <summary>
|
||||
/// 西门子帮助类
|
||||
/// </summary>
|
||||
public static class SiemensHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 将S7数据类型字符串转换为C#数据类型字符串
|
||||
/// </summary>
|
||||
/// <param name="s7Type">S7数据类型字符串</param>
|
||||
/// <returns>对应的C#数据类型字符串</returns>
|
||||
public static string S7ToCSharpTypeString(string s7Type)
|
||||
{
|
||||
switch (s7Type.ToUpper())
|
||||
{
|
||||
case "BOOL":
|
||||
return "bool";
|
||||
case "BYTE":
|
||||
return "byte";
|
||||
case "WORD":
|
||||
return "ushort";
|
||||
case "DWORD":
|
||||
return "uint";
|
||||
case "INT":
|
||||
return "short";
|
||||
case "DINT":
|
||||
return "int";
|
||||
case "REAL":
|
||||
return "float";
|
||||
case "LREAL":
|
||||
return "double";
|
||||
case "CHAR":
|
||||
return "char";
|
||||
case "STRING":
|
||||
return "string";
|
||||
case "TIMER":
|
||||
case "TIME":
|
||||
return "TimeSpan";
|
||||
case "COUNTER":
|
||||
return "ushort";
|
||||
case "DATE":
|
||||
return "DateTime";
|
||||
case "TIME_OF_DAY":
|
||||
case "TOD":
|
||||
return "DateTime";
|
||||
case "DATE_AND_TIME":
|
||||
case "DT":
|
||||
return "DateTime";
|
||||
default:
|
||||
return "object";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将S7读取到的值转换为显示值
|
||||
/// </summary>
|
||||
/// <param name="value">S7读取到的原始值</param>
|
||||
/// <param name="dataType">变量的数据类型</param>
|
||||
/// <param name="conversion">转换规则</param>
|
||||
/// <returns>显示值</returns>
|
||||
public static string ConvertS7Value(object value, string dataType, string conversion)
|
||||
{
|
||||
if (value == null) return string.Empty;
|
||||
|
||||
// For now, a simple conversion to string. More complex logic can be added here.
|
||||
// Based on dataType and conversion, you might parse, format, or apply formulas.
|
||||
return value.ToString();
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ public interface IDataStorageService
|
||||
/// <summary>
|
||||
/// MQTT服务器列表。
|
||||
/// </summary>
|
||||
ObservableCollection<MqttServerItemViewModel> MqttServers { get; set; }
|
||||
ObservableDictionary<int, MqttServerItemViewModel> MqttServers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 菜单列表。
|
||||
|
||||
@@ -48,6 +48,7 @@ public class DataEventService : IDataEventService
|
||||
|
||||
// 监听变量值变更事件
|
||||
_eventService.OnVariableValueChanged += OnVariableValueChanged;
|
||||
_eventService.OnMqttServerChanged += OnMqttServerChanged;
|
||||
_appDataCenterService.DataLoaderService.OnLoadDataCompleted += OnLoadDataCompleted;
|
||||
// 监听日志变更事件
|
||||
// _appDataCenterService.OnLogChanged += _logDataService.OnNlogChanged;
|
||||
@@ -55,6 +56,66 @@ public class DataEventService : IDataEventService
|
||||
_logger?.LogInformation("DataEventService 初始化完成");
|
||||
}
|
||||
|
||||
private void OnMqttServerChanged(object? sender, MqttServerChangedEventArgs e)
|
||||
{
|
||||
_logger?.LogDebug("接收到Mqtt服务器状态发生了改变,服务器名称:{mqttName}属性: {mqttProperty}",
|
||||
e.MqttServer.ServerName, e.PropertyType);
|
||||
|
||||
// 在UI线程上更新变量值
|
||||
App.Current.Dispatcher.BeginInvoke(new Action(() =>
|
||||
{
|
||||
//// 查找并更新对应的变量
|
||||
if (_dataStorageService.MqttServers.TryGetValue(e.MqttServer.Id, out var mqttServerItem))
|
||||
{
|
||||
if (e.ChangeType == ActionChangeType.Updated)
|
||||
{
|
||||
switch (e.PropertyType)
|
||||
{
|
||||
case MqttServerPropertyType.ServerName:
|
||||
break;
|
||||
case MqttServerPropertyType.ServerUrl:
|
||||
break;
|
||||
case MqttServerPropertyType.Port:
|
||||
break;
|
||||
case MqttServerPropertyType.IsConnect:
|
||||
mqttServerItem.IsConnect=e.MqttServer.IsConnect;
|
||||
break;
|
||||
case MqttServerPropertyType.Username:
|
||||
break;
|
||||
case MqttServerPropertyType.Password:
|
||||
break;
|
||||
case MqttServerPropertyType.IsActive:
|
||||
break;
|
||||
case MqttServerPropertyType.SubscribeTopic:
|
||||
break;
|
||||
case MqttServerPropertyType.PublishTopic:
|
||||
break;
|
||||
case MqttServerPropertyType.ClientId:
|
||||
break;
|
||||
case MqttServerPropertyType.MessageFormat:
|
||||
break;
|
||||
case MqttServerPropertyType.MessageHeader:
|
||||
break;
|
||||
case MqttServerPropertyType.MessageContent:
|
||||
break;
|
||||
case MqttServerPropertyType.MessageFooter:
|
||||
break;
|
||||
case MqttServerPropertyType.All:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger?.LogWarning("在Mqtt服务器队列中找不到ID为 {MqttServer} 的变量,无法更新值", e.MqttServer.Id);
|
||||
}
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
private void OnLoadDataCompleted(object? sender, DataLoadCompletedEventArgs e)
|
||||
{
|
||||
_logger?.LogDebug("接收到数据加载完成事件,成功: {IsSuccess}", e.IsSuccess);
|
||||
|
||||
@@ -28,7 +28,7 @@ public class DataStorageService : IDataStorageService
|
||||
/// <summary>
|
||||
/// MQTT服务器列表。
|
||||
/// </summary>
|
||||
public ObservableCollection<MqttServerItemViewModel> MqttServers { get; set; }
|
||||
public ObservableDictionary<int, MqttServerItemViewModel> MqttServers { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 菜单列表。
|
||||
@@ -55,7 +55,7 @@ public class DataStorageService : IDataStorageService
|
||||
Devices=new ObservableDictionary<int,DeviceItemViewModel>();
|
||||
VariableTables = new ObservableDictionary<int,VariableTableItemViewModel>();
|
||||
Variables=new ObservableDictionary<int,VariableItemViewModel>();
|
||||
MqttServers=new ObservableCollection<MqttServerItemViewModel>();
|
||||
MqttServers=new ObservableDictionary<int, MqttServerItemViewModel>();
|
||||
Menus=new ObservableCollection<MenuItemViewModel>();
|
||||
MenuTrees=new ObservableCollection<MenuItemViewModel>();
|
||||
Nlogs=new ObservableCollection<NlogItemViewModel>();
|
||||
|
||||
@@ -41,7 +41,11 @@ public class MqttDataService : IMqttDataService
|
||||
try
|
||||
{
|
||||
// 加载MQTT服务器数据
|
||||
_dataStorageService.MqttServers = _mapper.Map<ObservableCollection<MqttServerItemViewModel>>(_appDataStorageService.MqttServers.Values);
|
||||
foreach (var mqttServerDto in _appDataStorageService.MqttServers.Values)
|
||||
{
|
||||
_dataStorageService.MqttServers.TryAdd(mqttServerDto.Id,_mapper.Map<MqttServerItemViewModel>(mqttServerDto));
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -61,7 +65,7 @@ public class MqttDataService : IMqttDataService
|
||||
dto.Id = id;
|
||||
|
||||
var mqttServerItem = _mapper.Map<MqttServerItemViewModel>(dto);
|
||||
_dataStorageService.MqttServers.Add(mqttServerItem);
|
||||
_dataStorageService.MqttServers.Add(mqttServerItem.Id,mqttServerItem);
|
||||
|
||||
return mqttServerItem;
|
||||
}
|
||||
@@ -82,7 +86,7 @@ public class MqttDataService : IMqttDataService
|
||||
public async Task<bool> DeleteMqttServer(MqttServerItemViewModel mqttServer)
|
||||
{
|
||||
await _mqttAppService.DeleteMqttServerAsync(mqttServer.Id);
|
||||
_dataStorageService.MqttServers.Remove(mqttServer);
|
||||
_dataStorageService.MqttServers.Remove(mqttServer.Id);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using AutoMapper;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
@@ -12,6 +11,8 @@ using DMS.WPF.Services;
|
||||
using DMS.WPF.ViewModels.Dialogs;
|
||||
using DMS.WPF.ViewModels.Items;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ObservableCollections;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace DMS.WPF.ViewModels;
|
||||
|
||||
@@ -29,10 +30,11 @@ public partial class MqttsViewModel : ViewModelBase
|
||||
private readonly INotificationService _notificationService;
|
||||
|
||||
/// <summary>
|
||||
/// MQTT服务器列表。
|
||||
/// 设备列表。
|
||||
/// </summary>
|
||||
[ObservableProperty]
|
||||
private ObservableCollection<MqttServerItemViewModel> _mqtts;
|
||||
private INotifyCollectionChangedSynchronizedViewList<MqttServerItemViewModel> _mqttServeise;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 当前选中的MQTT服务器。
|
||||
@@ -62,7 +64,7 @@ public partial class MqttsViewModel : ViewModelBase
|
||||
_navigationService = navigationService;
|
||||
_notificationService = notificationService;
|
||||
|
||||
Mqtts = _dataStorageService.MqttServers;
|
||||
_mqttServeise = _dataStorageService.MqttServers.ToNotifyCollectionChanged(x=>x.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -118,6 +118,11 @@ partial class VariableHistoryViewModel : ViewModelBase, INavigatable
|
||||
|
||||
private void OnVariableValueChanged(object? sender, VariableValueChangedEventArgs e)
|
||||
{
|
||||
if (CurrentVariable is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.Variable.Id != CurrentVariable.Id)
|
||||
{
|
||||
return;
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
<ui:ContentDialog x:Class="DMS.WPF.Views.Dialogs.MqttDialog"
|
||||
<ui:ContentDialog
|
||||
x:Class="DMS.WPF.Views.Dialogs.MqttDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ikw="http://schemas.inkore.net/lib/ui/wpf"
|
||||
xmlns:hc="https://handyorg.github.io/handycontrol"
|
||||
xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
|
||||
xmlns:vmd="clr-namespace:DMS.WPF.ViewModels.Dialogs"
|
||||
xmlns:ex="clr-namespace:DMS.Extensions"
|
||||
xmlns:enums="clr-namespace:DMS.Core.Enums;assembly=DMS.Core"
|
||||
xmlns:ex="clr-namespace:DMS.Extensions"
|
||||
xmlns:hc="https://handyorg.github.io/handycontrol"
|
||||
xmlns:ikw="http://schemas.inkore.net/lib/ui/wpf"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
|
||||
xmlns:valueConverts="clr-namespace:DMS.WPF.ValueConverts"
|
||||
xmlns:vmd="clr-namespace:DMS.WPF.ViewModels.Dialogs"
|
||||
Title="{Binding Title}"
|
||||
d:DataContext="{d:DesignInstance vmd:MqttDialogViewModel}"
|
||||
CloseButtonCommand="{Binding CancelButtonCommand}"
|
||||
CloseButtonText="取消"
|
||||
DefaultButton="Primary"
|
||||
PrimaryButtonText="{Binding PrimaryButText}"
|
||||
PrimaryButtonCommand="{Binding PrimaryButtonCommand}"
|
||||
CloseButtonCommand="{Binding CancelButtonCommand}"
|
||||
d:DataContext="{d:DesignInstance vmd:MqttDialogViewModel}"
|
||||
PrimaryButtonText="{Binding PrimaryButText}"
|
||||
mc:Ignorable="d">
|
||||
<ui:ContentDialog.Resources>
|
||||
<ex:EnumBindingSource x:Key="mqttPlatform"
|
||||
EnumType="{x:Type enums:MqttPlatform}" />
|
||||
<ex:EnumBindingSource x:Key="mqttPlatform" EnumType="{x:Type enums:MqttPlatform}" />
|
||||
<valueConverts:EnumDescriptionConverter x:Key="EnumDescriptionConverter" />
|
||||
|
||||
<Style x:Key="LabelStyle" TargetType="TextBlock">
|
||||
@@ -113,22 +113,22 @@
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="3"
|
||||
Margin="0,15,0,0"
|
||||
hc:InfoElement.Title="消息头:"
|
||||
Text="{Binding MqttServer.MessageHeader, UpdateSourceTrigger=PropertyChanged}"
|
||||
TextWrapping="Wrap"
|
||||
VerticalContentAlignment="Top"
|
||||
hc:InfoElement.Title="消息头:可以使用{timestamp}表示时间戳"
|
||||
AcceptsReturn="True"
|
||||
VerticalContentAlignment="Top" />
|
||||
Text="{Binding MqttServer.MessageHeader, UpdateSourceTrigger=PropertyChanged}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<hc:TextBox
|
||||
Grid.Row="5"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="3"
|
||||
Margin="0,15,0,0"
|
||||
hc:InfoElement.Title="消息内容:"
|
||||
Text="{Binding MqttServer.MessageContent, UpdateSourceTrigger=PropertyChanged}"
|
||||
TextWrapping="Wrap"
|
||||
VerticalContentAlignment="Top"
|
||||
hc:InfoElement.Title="消息内容:可以使用,{name}表示变量名,{value}表示变量值"
|
||||
AcceptsReturn="True"
|
||||
VerticalContentAlignment="Top" />
|
||||
Text="{Binding MqttServer.MessageContent, UpdateSourceTrigger=PropertyChanged}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<!-- Row 6 -->
|
||||
<hc:TextBox
|
||||
@@ -136,11 +136,11 @@
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="3"
|
||||
Margin="0,15,0,0"
|
||||
VerticalContentAlignment="Top"
|
||||
hc:InfoElement.Title="消息尾:"
|
||||
Text="{Binding MqttServer.MessageFooter, UpdateSourceTrigger=PropertyChanged}"
|
||||
TextWrapping="Wrap"
|
||||
AcceptsReturn="True"
|
||||
VerticalContentAlignment="Top" />
|
||||
Text="{Binding MqttServer.MessageFooter, UpdateSourceTrigger=PropertyChanged}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<!-- Row 4 -->
|
||||
<CheckBox
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
<UserControl x:Class="DMS.WPF.Views.MqttsView"
|
||||
<UserControl
|
||||
x:Class="DMS.WPF.Views.MqttsView"
|
||||
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"
|
||||
xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
|
||||
xmlns:ikw="http://schemas.inkore.net/lib/ui/wpf"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
|
||||
xmlns:vm="clr-namespace:DMS.WPF.ViewModels"
|
||||
d:DataContext="{d:DesignInstance vm:MqttsViewModel}"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300"
|
||||
d:DesignWidth="300">
|
||||
d:DesignWidth="300"
|
||||
mc:Ignorable="d">
|
||||
<UserControl.Resources>
|
||||
<DataTemplate x:Key="MqttItemTemplate">
|
||||
<Border BorderBrush="{DynamicResource SystemControlHighlightBaseMediumLowBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8"
|
||||
<Border
|
||||
Margin="5"
|
||||
Padding="15">
|
||||
Padding="15"
|
||||
BorderBrush="{DynamicResource SystemControlHighlightBaseMediumLowBrush}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="8">
|
||||
<Border.Style>
|
||||
<Style TargetType="Border">
|
||||
<Setter Property="Background" Value="{DynamicResource SystemControlBackgroundAltHighBrush}" />
|
||||
@@ -28,10 +30,11 @@
|
||||
</Style>
|
||||
</Border.Style>
|
||||
<Border.Effect>
|
||||
<DropShadowEffect ShadowDepth="1"
|
||||
Color="Black"
|
||||
<DropShadowEffect
|
||||
BlurRadius="5"
|
||||
Opacity="0.1"
|
||||
BlurRadius="5" />
|
||||
ShadowDepth="1"
|
||||
Color="Black" />
|
||||
</Border.Effect>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
@@ -41,115 +44,116 @@
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Row 0: Header with Name and ToggleSwitch -->
|
||||
<DockPanel Grid.Row="0"
|
||||
Margin="0,0,0,10">
|
||||
<ui:ToggleSwitch DockPanel.Dock="Right"
|
||||
<DockPanel Grid.Row="0" Margin="0,0,0,10">
|
||||
<ui:ToggleSwitch
|
||||
DockPanel.Dock="Right"
|
||||
IsOn="{Binding IsActive}"
|
||||
OffContent="停止"
|
||||
OnContent="启动" />
|
||||
<TextBlock Text="{Binding ServerName}"
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
FontSize="20"
|
||||
FontWeight="SemiBold"
|
||||
VerticalAlignment="Center" />
|
||||
Text="{Binding ServerName}" />
|
||||
</DockPanel>
|
||||
|
||||
<!-- Row 1: Details with Icons -->
|
||||
<StackPanel Grid.Row="1"
|
||||
Margin="0,0,0,10">
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Margin="0,2">
|
||||
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Info}"
|
||||
VerticalAlignment="Center"
|
||||
<StackPanel Grid.Row="1" Margin="0,0,0,10">
|
||||
<StackPanel Margin="0,2" Orientation="Horizontal">
|
||||
<ui:FontIcon
|
||||
Margin="0,0,8,0"
|
||||
FontSize="14" />
|
||||
<TextBlock Text="{Binding MessageFormat}"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Icon="{x:Static ui:SegoeFluentIcons.Info}" />
|
||||
<TextBlock
|
||||
Foreground="{DynamicResource SystemControlForegroundBaseMediumBrush}"
|
||||
Text="{Binding MessageFormat}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Margin="0,2">
|
||||
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Connect}"
|
||||
VerticalAlignment="Center"
|
||||
<StackPanel Margin="0,2" Orientation="Horizontal">
|
||||
<ui:FontIcon
|
||||
Margin="0,0,8,0"
|
||||
FontSize="14" />
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Icon="{x:Static ui:SegoeFluentIcons.Connect}" />
|
||||
<TextBlock>
|
||||
<Run Text="{Binding ServerUrl, FallbackValue='127.0.0.1'}" />
|
||||
<Run Text=":" />
|
||||
<Run Text="{Binding Port, FallbackValue='1883'}" />
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Margin="0,2">
|
||||
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.DeveloperTools}"
|
||||
VerticalAlignment="Center"
|
||||
<StackPanel Margin="0,2" Orientation="Horizontal">
|
||||
<ui:FontIcon
|
||||
Margin="0,0,8,0"
|
||||
FontSize="14" />
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Icon="{x:Static ui:SegoeFluentIcons.DeveloperTools}" />
|
||||
<TextBlock>
|
||||
<Run Text="未指定平台" />
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Margin="0,2">
|
||||
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Contact}"
|
||||
VerticalAlignment="Center"
|
||||
<StackPanel Margin="0,2" Orientation="Horizontal">
|
||||
<ui:FontIcon
|
||||
Margin="0,0,8,0"
|
||||
FontSize="14" />
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Icon="{x:Static ui:SegoeFluentIcons.Contact}" />
|
||||
<TextBlock Text="{Binding ClientId}" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Margin="0,2">
|
||||
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.OtherUser}"
|
||||
VerticalAlignment="Center"
|
||||
<StackPanel Margin="0,2" Orientation="Horizontal">
|
||||
<ui:FontIcon
|
||||
Margin="0,0,8,0"
|
||||
FontSize="14" />
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Icon="{x:Static ui:SegoeFluentIcons.OtherUser}" />
|
||||
<TextBlock Text="{Binding Username}" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Margin="0,2">
|
||||
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Lock}"
|
||||
VerticalAlignment="Center"
|
||||
<StackPanel Margin="0,2" Orientation="Horizontal">
|
||||
<ui:FontIcon
|
||||
Margin="0,0,8,0"
|
||||
FontSize="14" />
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Icon="{x:Static ui:SegoeFluentIcons.Lock}" />
|
||||
<TextBlock Text="{Binding Password}" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Margin="0,2">
|
||||
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Send}"
|
||||
VerticalAlignment="Center"
|
||||
<StackPanel Margin="0,2" Orientation="Horizontal">
|
||||
<ui:FontIcon
|
||||
Margin="0,0,8,0"
|
||||
FontSize="14" />
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Icon="{x:Static ui:SegoeFluentIcons.Send}" />
|
||||
<TextBlock Text="{Binding PublishTopic}" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Margin="0,2">
|
||||
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.SubscriptionAdd}"
|
||||
VerticalAlignment="Center"
|
||||
<StackPanel Margin="0,2" Orientation="Horizontal">
|
||||
<ui:FontIcon
|
||||
Margin="0,0,8,0"
|
||||
FontSize="14" />
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Icon="{x:Static ui:SegoeFluentIcons.SubscriptionAdd}" />
|
||||
<TextBlock Text="{Binding SubscribeTopic}" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Margin="0,2">
|
||||
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Calendar}"
|
||||
VerticalAlignment="Center"
|
||||
<StackPanel Margin="0,2" Orientation="Horizontal">
|
||||
<ui:FontIcon
|
||||
Margin="0,0,8,0"
|
||||
FontSize="14" />
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Icon="{x:Static ui:SegoeFluentIcons.Calendar}" />
|
||||
<TextBlock Text="{Binding ConnectedAt}" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Margin="0,2">
|
||||
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Message}"
|
||||
VerticalAlignment="Center"
|
||||
<StackPanel Margin="0,2" Orientation="Horizontal">
|
||||
<ui:FontIcon
|
||||
Margin="0,0,8,0"
|
||||
FontSize="14" />
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Icon="{x:Static ui:SegoeFluentIcons.Message}" />
|
||||
<TextBlock Text="{Binding MessageFormat}" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Margin="0,2">
|
||||
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.FavoriteStar}"
|
||||
VerticalAlignment="Center"
|
||||
<StackPanel Margin="0,2" Orientation="Horizontal">
|
||||
<ui:FontIcon
|
||||
Margin="0,0,8,0"
|
||||
FontSize="14" />
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Icon="{x:Static ui:SegoeFluentIcons.FavoriteStar}" />
|
||||
<!-- IsDefault 属性未在 ViewModel 中定义,已移除绑定 -->
|
||||
<TextBlock Text="未设置默认" />
|
||||
</StackPanel>
|
||||
@@ -161,56 +165,52 @@
|
||||
|
||||
<StackPanel>
|
||||
<!-- 操作菜单栏 -->
|
||||
<ui:CommandBar DefaultLabelPosition="Right"
|
||||
IsOpen="False">
|
||||
<ui:CommandBar DefaultLabelPosition="Right" IsOpen="False">
|
||||
<!-- 添加MQTT -->
|
||||
<ui:AppBarButton Command="{Binding AddMqttCommand}"
|
||||
Label="添加MQTT">
|
||||
<ui:AppBarButton Command="{Binding AddMqttCommand}" Label="添加MQTT">
|
||||
<ui:AppBarButton.Icon>
|
||||
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Add}" />
|
||||
</ui:AppBarButton.Icon>
|
||||
</ui:AppBarButton>
|
||||
<!-- 编辑MQTT -->
|
||||
<ui:AppBarButton Command="{Binding EditMqttCommand}"
|
||||
Label="编辑MQTT">
|
||||
<ui:AppBarButton Command="{Binding EditMqttCommand}" Label="编辑MQTT">
|
||||
<ui:AppBarButton.Icon>
|
||||
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Edit}" />
|
||||
</ui:AppBarButton.Icon>
|
||||
</ui:AppBarButton>
|
||||
<!-- 删除MQTT -->
|
||||
<ui:AppBarButton Command="{Binding DeleteMqttCommand}"
|
||||
Label="删除MQTT">
|
||||
<ui:AppBarButton Command="{Binding DeleteMqttCommand}" Label="删除MQTT">
|
||||
<ui:AppBarButton.Icon>
|
||||
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Delete}" />
|
||||
</ui:AppBarButton.Icon>
|
||||
</ui:AppBarButton>
|
||||
<!-- 查看详情 -->
|
||||
<ui:AppBarButton Command="{Binding NavigateToMqttDetailCommand}"
|
||||
Label="查看详情">
|
||||
<ui:AppBarButton Command="{Binding NavigateToMqttDetailCommand}" Label="查看详情">
|
||||
<ui:AppBarButton.Icon>
|
||||
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Document}" />
|
||||
</ui:AppBarButton.Icon>
|
||||
</ui:AppBarButton>
|
||||
<ui:AppBarButton x:Name="ShareButton"
|
||||
Label="Share">
|
||||
<ui:AppBarButton x:Name="ShareButton" Label="Share">
|
||||
<ui:AppBarButton.Icon>
|
||||
<ui:FontIcon Icon="{x:Static ui:SegoeFluentIcons.Share}" />
|
||||
</ui:AppBarButton.Icon>
|
||||
</ui:AppBarButton>
|
||||
<ui:CommandBar.SecondaryCommands>
|
||||
<ui:AppBarButton x:Name="SettingsButton"
|
||||
<ui:AppBarButton
|
||||
x:Name="SettingsButton"
|
||||
Icon="Setting"
|
||||
Label="Settings" />
|
||||
</ui:CommandBar.SecondaryCommands>
|
||||
</ui:CommandBar>
|
||||
|
||||
|
||||
<ui:GridView x:Name="BasicGridView"
|
||||
<ui:GridView
|
||||
x:Name="BasicGridView"
|
||||
Margin="20"
|
||||
IsItemClickEnabled="True"
|
||||
SelectedItem="{Binding SelectedMqtt }"
|
||||
ItemsSource="{Binding Mqtts}"
|
||||
ItemTemplate="{StaticResource MqttItemTemplate}"
|
||||
ItemsSource="{Binding MqttServeise}"
|
||||
SelectedItem="{Binding SelectedMqtt}"
|
||||
SelectionMode="Single" />
|
||||
</StackPanel>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user