完成主菜单的加载与显示

This commit is contained in:
2025-07-26 13:35:53 +08:00
parent 86dc3b670a
commit 527fb88cdf
6 changed files with 321 additions and 123 deletions

View File

@@ -1,3 +1,4 @@
using DMS.Core.Enums;
using DMS.Core.Interfaces.Repositories; using DMS.Core.Interfaces.Repositories;
using DMS.Core.Models; using DMS.Core.Models;
using DMS.Infrastructure.Configurations; using DMS.Infrastructure.Configurations;
@@ -91,26 +92,28 @@ public class InitializeRepository : IInitializeRepository
/// <summary> /// <summary>
/// 初始化默认菜单。 /// 初始化默认菜单。
/// 如果配置文件中没有菜单,则添加一组默认菜单项。 /// 如果数据库中没有菜单,则添加一组默认菜单项。
/// </summary> /// </summary>
public void InitializeMenus() public void InitializeMenus()
{ {
var settings = AppSettings.Load(); // 检查数据库中是否已存在菜单数据
if (settings.Menus.Any()) if (_db.Queryable<DbMenu>().Any())
{ {
return ; // 如果已经有菜单,则不进行初始化 return; // 如果数据库中已经有菜单,则不进行初始化
} }
// 添加默认菜单项 // 创建默认菜单项的 DbMenu 实体列表
settings.Menus.Add(new MenuBean() { Id=1, Header = "主页", Icon = "Home", ParentId = 0 }); var defaultMenus = new List<DbMenu>
settings.Menus.Add(new MenuBean() { Id = 2, Header = "设备", Icon = "Devices3", ParentId = 0 }); {
settings.Menus.Add(new MenuBean() { Id = 3, Header = "数据转换", Icon = "ChromeSwitch", ParentId = 0 }); new DbMenu { Id = 1, Header = "主页", Icon = "\uE80F", ParentId = 0,MenuType = MenuType.MainMenu, DisplayOrder = 1 },
settings.Menus.Add(new MenuBean() { Id = 4, Header = "Mqtt服务器", Icon = "Cloud", ParentId = 0 }); new DbMenu { Id = 2, Header = "设备", Icon = "\uE975", ParentId = 0,MenuType = MenuType.MainMenu , DisplayOrder = 2 },
settings.Menus.Add(new MenuBean() { Id = 5, Header = "设置", Icon = "Settings", ParentId = 0 }); new DbMenu { Id = 3, Header = "数据转换", Icon = "\uF1CB", ParentId = 0,MenuType = MenuType.MainMenu , DisplayOrder = 3 },
settings.Menus.Add(new MenuBean() { Id = 6, Header = "关于", Icon = "Info", ParentId = 0 }); new DbMenu { Id = 4, Header = "Mqtt服务器", Icon = "\uE753", ParentId = 0,MenuType = MenuType.MainMenu , DisplayOrder = 4 },
new DbMenu { Id = 5, Header = "设置", Icon = "\uE713", ParentId = 0,MenuType = MenuType.MainMenu , DisplayOrder = 5 },
new DbMenu { Id = 6, Header = "关于", Icon = "\uE946", ParentId = 0, MenuType= MenuType.MainMenu ,DisplayOrder = 6 } // 假设有一个AboutView
};
settings.Save(); // 保存菜单到配置文件 // 批量插入菜单到数据库
_db.Insertable(defaultMenus).ExecuteCommand();
return ;
} }
} }

View File

@@ -1,7 +1,9 @@
using System.Windows; using System.Windows;
using AutoMapper.Internal;
using DMS.Application.Interfaces; using DMS.Application.Interfaces;
using DMS.Application.Services; using DMS.Application.Services;
using DMS.Core.Enums; using DMS.Core.Enums;
using DMS.Core.Interfaces;
using DMS.Core.Interfaces.Repositories; using DMS.Core.Interfaces.Repositories;
using DMS.Helper; using DMS.Helper;
using DMS.Services; using DMS.Services;
@@ -118,8 +120,16 @@ public partial class App : System.Windows.Application
// services.AddHostedService<DMS.Infrastructure.Services.MqttBackgroundService>(); // services.AddHostedService<DMS.Infrastructure.Services.MqttBackgroundService>();
// //
// 注册 AutoMapper // --- 核心配置 ---
services.AddAutoMapper(typeof(App).Assembly); services.AddAutoMapper(cfg =>
{
// 最终解决方案根据异常信息的建议设置此标记以忽略重复的Profile加载。
// 注意:此属性位于 Internal() 方法下。
cfg.Internal().AllowAdditiveTypeMapCreation = true;
cfg.AddProfile(new DMS.Application.Profiles.MappingProfile());
cfg.AddProfile(new DMS.Infrastructure.Profiles.MappingProfile());
});
// 注册数据处理服务和处理器 // 注册数据处理服务和处理器
services.AddSingleton<IDataProcessingService, DataProcessingService>(); services.AddSingleton<IDataProcessingService, DataProcessingService>();
@@ -132,14 +142,27 @@ public partial class App : System.Windows.Application
// 注册Core中的仓库 // 注册Core中的仓库
services.AddSingleton<AppSettings>(); services.AddSingleton<AppSettings>();
services.AddSingleton<SqlSugarDbContext>(); // services.AddSingleton<SqlSugarDbContext>();
// 2. 配置数据库上下文 (在测试中通常使用单例)
services.AddSingleton<SqlSugarDbContext>(_ =>
{
var appSettings = new AppSettings { Database = { Database = "dms_test" } };
return new SqlSugarDbContext(appSettings);
});
services.AddSingleton<IInitializeRepository, InitializeRepository>(); services.AddSingleton<IInitializeRepository, InitializeRepository>();
services.AddSingleton<IRepositoryManager, RepositoryManager>();
// 注册App服务 // 注册App服务
services.AddSingleton<IInitializeService,InitializeService>(); services.AddSingleton<IInitializeService,InitializeService>();
services.AddSingleton<IDeviceAppService,DeviceAppService>(); services.AddSingleton<IDeviceAppService,DeviceAppService>();
services.AddSingleton<IVariableAppService,VariableAppService>();
services.AddSingleton<IVariableTableAppService,VariableTableAppService>();
services.AddSingleton<INavigationService, NavigationService>(); services.AddSingleton<INavigationService, NavigationService>();
services.AddSingleton<IMenuService, MenuService>();
//注册WPF中的服务
services.AddSingleton<DataServices>();
// 注册视图模型 // 注册视图模型
services.AddSingleton<SplashViewModel>(); services.AddSingleton<SplashViewModel>();
services.AddSingleton<MainViewModel>(); services.AddSingleton<MainViewModel>();

View File

@@ -1,14 +1,17 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.ObjectModel;
using AutoMapper; using AutoMapper;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Messaging; using CommunityToolkit.Mvvm.Messaging;
using DMS.Application.DTOs; using DMS.Application.DTOs;
using DMS.Application.Interfaces;
using DMS.Core.Helper; using DMS.Core.Helper;
using DMS.Core.Enums; using DMS.Core.Enums;
using DMS.Core.Models; using DMS.Core.Models;
using DMS.Helper; using DMS.Helper;
using DMS.Message; using DMS.Message;
using DMS.WPF.Helper; using DMS.WPF.Helper;
using DMS.WPF.ViewModels.Items;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@@ -22,21 +25,26 @@ namespace DMS.WPF.Services;
public partial class DataServices : ObservableRecipient, IRecipient<LoadMessage> public partial class DataServices : ObservableRecipient, IRecipient<LoadMessage>
{ {
private readonly IMapper _mapper; private readonly IMapper _mapper;
private readonly IDeviceAppService _deviceAppService;
private readonly IVariableTableAppService _variableTableAppService;
private readonly IVariableAppService _variableAppService;
// 设备列表使用ObservableProperty特性当值改变时会自动触发属性变更通知。 // 设备列表使用ObservableProperty特性当值改变时会自动触发属性变更通知。
[ObservableProperty] [ObservableProperty]
private List<Device> _devices; private ObservableCollection<DeviceItemViewModel> _devices;
// 变量表列表。 // 变量表列表。
[ObservableProperty] [ObservableProperty]
private List<VariableTable> _variableTables; private ObservableCollection<VariableTableItemViewModel> _variableTables;
// 变量数据列表。 // 变量数据列表。
[ObservableProperty] [ObservableProperty]
private List<Variable> _variables; private ObservableCollection<VariableItemViewModel> _variables;
// 菜单树列表。 // 菜单树列表。
[ObservableProperty] [ObservableProperty]
private List<MenuBean> menuTrees; private ObservableCollection<MenuBeanItemViewModel> _menus;
// MQTT配置列表。 // MQTT配置列表。
// [ObservableProperty] // [ObservableProperty]
@@ -44,18 +52,8 @@ public partial class DataServices : ObservableRecipient, IRecipient<LoadMessage>
public ConcurrentDictionary<int, Variable> AllVariables; public ConcurrentDictionary<int, Variable> AllVariables;
private readonly IMenuService _menuService;
// 设备数据仓库用于设备数据的CRUD操作。
// private readonly DeviceRepository _deviceRepository;
//
// // 菜单数据仓库用于菜单数据的CRUD操作。
// private readonly MenuRepository _menuRepository;
//
// // MQTT数据仓库用于MQTT配置数据的CRUD操作。
// private readonly MqttRepository _mqttRepository;
//
// // 变量数据仓库用于变量数据的CRUD操作。
// private readonly VarDataRepository _varDataRepository;
// 设备列表变更事件,当设备列表数据更新时触发。 // 设备列表变更事件,当设备列表数据更新时触发。
public event Action<List<Device>> OnDeviceListChanged; public event Action<List<Device>> OnDeviceListChanged;
@@ -84,20 +82,27 @@ public partial class DataServices : ObservableRecipient, IRecipient<LoadMessage>
// OnVariableDataChanged?.Invoke(this, value); // OnVariableDataChanged?.Invoke(this, value);
// } // }
// /// <summary> /// <summary>
// /// DataServices类的构造函数。 /// DataServices类的构造函数。
// /// 注入ILogger<DataServices>,并初始化各个数据仓库。 /// 注入ILogger<DataServices>,并初始化各个数据仓库。
// /// </summary> /// </summary>
// /// <param name="mapper">AutoMapper 实例。</param> /// <param name="mapper">AutoMapper 实例。</param>
// /// <param name="varDataRepository"></param> /// <param name="varDataRepository"></param>
// public DataServices(IMapper mapper,DeviceRepository deviceRepository,MenuRepository menuRepository,MqttRepository mqttRepository,VarDataRepository varDataRepository) public DataServices(IMapper mapper, IDeviceAppService deviceAppService,
// { IVariableTableAppService variableTableAppService, IVariableAppService variableAppService,IMenuService menuService)
// _mapper = mapper; {
// IsActive = true; // 激活消息接收器 _mapper = mapper;
// _deviceAppService = deviceAppService;
// _variables = new List<Variable>(); _variableTableAppService = variableTableAppService;
_variableAppService = variableAppService;
_menuService = menuService;
IsActive = true; // 激活消息接收器
Devices = new ObservableCollection<DeviceItemViewModel>();
VariableTables = new ObservableCollection<VariableTableItemViewModel>();
Variables = new ObservableCollection<VariableItemViewModel>();
Menus = new ObservableCollection<MenuBeanItemViewModel>();
// AllVariables = new ConcurrentDictionary<int, Variable>(); // AllVariables = new ConcurrentDictionary<int, Variable>();
// } }
// /// <summary> // /// <summary>
// /// 接收加载消息,根据消息类型从数据库加载对应的数据。 // /// 接收加载消息,根据消息类型从数据库加载对应的数据。
@@ -134,88 +139,127 @@ public partial class DataServices : ObservableRecipient, IRecipient<LoadMessage>
// } // }
/// <summary> /// <summary>
/// 异步加载设备数据。 /// 异步加载设备数据并以高效的方式更新UI集合
/// 此方法会比较新旧数据只对有变化的设备进行更新、添加或删除避免不必要的UI刷新。
/// </summary> /// </summary>
/// <returns>表示异步操作的任务。</returns> public async Task LoadDevices()
private async Task LoadDevices()
{ {
// 取消订阅旧设备的属性变更事件,防止内存泄漏 var deviceDtos = await _deviceAppService.GetAllDevicesAsync();
// if (Devices != null) var deviceDtoIds = new HashSet<int>(deviceDtos.Select(d => d.Id));
// {
// foreach (var device in Devices) // 1. 更新现有项 & 查找需要删除的项
// { var itemsToRemove = new List<DeviceItemViewModel>();
// device.PropertyChanged -= Device_PropertyChanged; foreach (var existingItem in Devices)
// } {
// } if (deviceDtoIds.Contains(existingItem.Id))
// {
// Devices = await _deviceRepository.GetAllAsync(); // 设备仍然存在,检查是否有更新
// var dto = deviceDtos.First(d => d.Id == existingItem.Id);
// // 订阅新设备的属性变更事件
// if (Devices != null) // 逐一比较属性,只有在发生变化时才更新
// { if (existingItem.Name != dto.Name) existingItem.Name = dto.Name;
// foreach (var device in Devices) if (existingItem.Protocol != dto.Protocol) existingItem.Protocol = dto.Protocol;
// { if (existingItem.IpAddress != dto.IpAddress) existingItem.IpAddress = dto.IpAddress;
// device.PropertyChanged += Device_PropertyChanged; if (existingItem.Port != dto.Port) existingItem.Port = dto.Port;
// } if (existingItem.Rack != dto.Rack) existingItem.Rack = dto.Rack;
// if (existingItem.Slot != dto.Slot) existingItem.Slot = dto.Slot;
// var allVar = await _varDataRepository.GetAllAsync(); if (existingItem.OpcUaServerUrl != dto.OpcUaServerUrl) existingItem.OpcUaServerUrl = dto.OpcUaServerUrl;
// foreach (var variable in allVar) if (existingItem.IsActive != dto.IsActive) existingItem.IsActive = dto.IsActive;
// { if (existingItem.Status != dto.Status) existingItem.Status = dto.Status;
// AllVariables.AddOrUpdate(variable.Id, variable, (key, old) => variable); }
// } else
// {
// } // 设备在新列表中不存在,标记为待删除
// itemsToRemove.Add(existingItem);
// OnDeviceListChanged?.Invoke(Devices); }
} }
private void Device_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) // 2. 从UI集合中删除不再存在的项
foreach (var item in itemsToRemove)
{ {
if (e.PropertyName == nameof(Device.IsActive)) Devices.Remove(item);
}
// 3. 添加新项
var existingIds = new HashSet<int>(Devices.Select(d => d.Id));
foreach (var dto in deviceDtos)
{ {
if (sender is Device device) if (!existingIds.Contains(dto.Id))
{ {
NlogHelper.Info($"设备 {device.Name} 的IsActive状态改变为 {device.IsActive}触发设备IsActive状态变更事件。"); // 这是一个新设备,添加到集合中
OnDeviceIsActiveChanged?.Invoke(device, device.IsActive); var newItem = _mapper.Map<DeviceItemViewModel>(dto);
Devices.Add(newItem);
} }
} }
} }
// private void Device_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
// {
// if (e.PropertyName == nameof(Device.IsActive))
// {
// if (sender is Device device)
// {
// NlogHelper.Info($"设备 {device.Name} 的IsActive状态改变为 {device.IsActive}触发设备IsActive状态变更事件。");
// OnDeviceIsActiveChanged?.Invoke(device, device.IsActive);
// }
// }
// }
/// <summary> /// <summary>
/// 异步加载菜单数据,并进行父级关联和排序 /// 异步加载菜单数据,并以高效的方式更新UI集合
/// 此方法会比较新旧数据只对有变化的菜单项进行更新、添加或删除避免不必要的UI刷新。
/// </summary> /// </summary>
/// <returns>表示异步操作的任务。</returns> public async Task LoadMenus()
private async Task LoadMenus()
{ {
// MenuTrees = await _menuRepository.GetMenuTreesAsync(); var newMenus = await _menuService.GetAllMenusAsync(); // 获取最新的菜单树 (MenuItemViewModel 列表)
// foreach (MenuBean menu in MenuTrees) var newMenuIds = new HashSet<int>(newMenus.Select(m => m.Id));
// {
// MenuHelper.MenuAddParent(menu); // 为菜单添加父级引用 // 1. 更新现有项 & 查找需要删除的项
// DataServicesHelper.SortMenus(menu); // 排序菜单 var itemsToRemove = new List<MenuBeanItemViewModel>();
// } foreach (var existingItem in Menus)
// {
// OnMenuTreeListChanged?.Invoke(MenuTrees); if (newMenuIds.Contains(existingItem.Id))
{
// 菜单项仍然存在,检查是否有更新
var newDto = newMenus.First(m => m.Id == existingItem.Id);
// 逐一比较属性,只有在发生变化时才更新
// 注意MenuItemViewModel 的属性是 ObservableProperty直接赋值会触发通知
if (existingItem.Header != newDto.Header) existingItem.Header = newDto.Header;
if (existingItem.Icon != newDto.Icon) existingItem.Icon = newDto.Icon;
// 对于 TargetViewKey 和 NavigationParameter它们在 MenuItemViewModel 中是私有字段,
// 并且在构造时通过 INavigationService 绑定到 NavigateCommand。
// 如果这些需要动态更新MenuItemViewModel 内部需要提供公共属性或方法来处理。
// 目前我们假设如果这些变化IMenuService 会返回一个新的 MenuItemViewModel 实例。
// 如果需要更细粒度的更新,需要修改 MenuItemViewModel 的设计。
// 这里我们只更新直接暴露的 ObservableProperty。
}
else
{
// 菜单项在新列表中不存在,标记为待删除
itemsToRemove.Add(existingItem);
}
} }
// /// <summary> // 2. 从UI集合中删除不再存在的项
// /// 异步获取所有MQTT配置。 foreach (var item in itemsToRemove)
// /// </summary> {
// /// <returns>包含所有MQTT配置的列表。</returns> Menus.Remove(item);
// public async Task<List<Mqtt>> GetMqttsAsync() }
// {
// var mqtts = await _mqttRepository.GetAllAsync(); // 3. 添加新项
// OnMqttListChanged?.Invoke(mqtts); var existingIds = new HashSet<int>(Menus.Select(m => m.Id));
// return mqtts; foreach (var newDto in newMenus)
// } {
if (!existingIds.Contains(newDto.Id))
{
// 这是一个新菜单项,添加到集合中
// 注意:这里直接添加 IMenuService 返回的 MenuItemViewModel 实例
Menus.Add(_mapper.Map<MenuBeanItemViewModel>(newDto));
}
}
}
// /// <summary>
// /// 异步加载MQTT配置数据。
// /// </summary>
// /// <returns>表示异步操作的任务。</returns>
// private async Task LoadMqtts()
// {
// Mqtts = await _mqttRepository.GetAllAsync();
// }
// /// <summary> // /// <summary>
@@ -249,6 +293,127 @@ public partial class DataServices : ObservableRecipient, IRecipient<LoadMessage>
public void Receive(LoadMessage message) public void Receive(LoadMessage message)
{ {
}
/// <summary>
/// 异步加载变量数据并以高效的方式更新UI集合。
/// 此方法会比较新旧数据只对有变化的变量进行更新、添加或删除避免不必要的UI刷新。
/// </summary>
public async Task LoadVariables()
{
var variableDtos = await _variableAppService.GetAllVariablesAsync(); // 假设有此方法
var variableDtoIds = new HashSet<int>(variableDtos.Select(v => v.Id));
// 1. 更新现有项 & 查找需要删除的项
var itemsToRemove = new List<VariableItemViewModel>();
foreach (var existingItem in Variables)
{
if (variableDtoIds.Contains(existingItem.Id))
{
// 变量仍然存在,检查是否有更新
var dto = variableDtos.First(v => v.Id == existingItem.Id);
// 逐一比较属性,只有在发生变化时才更新
if (existingItem.Name != dto.Name) existingItem.Name = dto.Name;
if (existingItem.S7Address != dto.S7Address) existingItem.S7Address = dto.S7Address;
if (existingItem.DataValue != dto.DataValue) existingItem.DataValue = dto.DataValue;
if (existingItem.DisplayValue != dto.DisplayValue) existingItem.DisplayValue = dto.DisplayValue;
// 注意VariableTable 和 MqttAliases 是复杂对象,需要更深层次的比较或重新映射
// 为了简化,这里只比较基本类型属性
if (existingItem.DataType != dto.DataType) existingItem.DataType = dto.DataType;
if (existingItem.PollLevel != dto.PollLevel) existingItem.PollLevel = dto.PollLevel;
if (existingItem.IsActive != dto.IsActive) existingItem.IsActive = dto.IsActive;
if (existingItem.VariableTableId != dto.VariableTableId) existingItem.VariableTableId = dto.VariableTableId;
if (existingItem.OpcUaNodeId != dto.OpcUaNodeId) existingItem.OpcUaNodeId = dto.OpcUaNodeId;
if (existingItem.IsHistoryEnabled != dto.IsHistoryEnabled) existingItem.IsHistoryEnabled = dto.IsHistoryEnabled;
if (existingItem.HistoryDeadband != dto.HistoryDeadband) existingItem.HistoryDeadband = dto.HistoryDeadband;
if (existingItem.IsAlarmEnabled != dto.IsAlarmEnabled) existingItem.IsAlarmEnabled = dto.IsAlarmEnabled;
if (existingItem.AlarmMinValue != dto.AlarmMinValue) existingItem.AlarmMinValue = dto.AlarmMinValue;
if (existingItem.AlarmMaxValue != dto.AlarmMaxValue) existingItem.AlarmMaxValue = dto.AlarmMaxValue;
if (existingItem.AlarmDeadband != dto.AlarmDeadband) existingItem.AlarmDeadband = dto.AlarmDeadband;
if (existingItem.Protocol != dto.Protocol) existingItem.Protocol = dto.Protocol;
if (existingItem.CSharpDataType != dto.CSharpDataType) existingItem.CSharpDataType = dto.CSharpDataType;
if (existingItem.ConversionFormula != dto.ConversionFormula) existingItem.ConversionFormula = dto.ConversionFormula;
if (existingItem.CreatedAt != dto.CreatedAt) existingItem.CreatedAt = dto.CreatedAt;
if (existingItem.UpdatedAt != dto.UpdatedAt) existingItem.UpdatedAt = dto.UpdatedAt;
if (existingItem.UpdatedBy != dto.UpdatedBy) existingItem.UpdatedBy = dto.UpdatedBy;
if (existingItem.IsModified != dto.IsModified) existingItem.IsModified = dto.IsModified;
if (existingItem.Description != dto.Description) existingItem.Description = dto.Description;
}
else
{
// 变量在新列表中不存在,标记为待删除
itemsToRemove.Add(existingItem);
}
}
// 2. 从UI集合中删除不再存在的项
foreach (var item in itemsToRemove)
{
Variables.Remove(item);
}
// 3. 添加新项
var existingIds = new HashSet<int>(Variables.Select(v => v.Id));
foreach (var dto in variableDtos)
{
if (!existingIds.Contains(dto.Id))
{
// 这是一个新变量,添加到集合中
var newItem = _mapper.Map<VariableItemViewModel>(dto);
Variables.Add(newItem);
}
}
}
/// <summary>
/// 异步加载变量表数据并以高效的方式更新UI集合。
/// 此方法会比较新旧数据只对有变化的变量表进行更新、添加或删除避免不必要的UI刷新。
/// </summary>
public async Task LoadVariableTables()
{
var variableTableDtos = await _variableTableAppService.GetAllVariableTablesAsync(); // 假设有此方法
var variableTableDtoIds = new HashSet<int>(variableTableDtos.Select(vt => vt.Id));
// 1. 更新现有项 & 查找需要删除的项
var itemsToRemove = new List<VariableTableItemViewModel>();
foreach (var existingItem in VariableTables)
{
if (variableTableDtoIds.Contains(existingItem.Id))
{
// 变量表仍然存在,检查是否有更新
var dto = variableTableDtos.First(vt => vt.Id == existingItem.Id);
// 逐一比较属性,只有在发生变化时才更新
if (existingItem.Name != dto.Name) existingItem.Name = dto.Name;
if (existingItem.Description != dto.Description) existingItem.Description = dto.Description;
if (existingItem.IsActive != dto.IsActive) existingItem.IsActive = dto.IsActive;
if (existingItem.DeviceId != dto.DeviceId) existingItem.DeviceId = dto.DeviceId;
if (existingItem.Protocol != dto.Protocol) existingItem.Protocol = dto.Protocol;
}
else
{
// 变量表在新列表中不存在,标记为待删除
itemsToRemove.Add(existingItem);
}
}
// 2. 从UI集合中删除不再存在的项
foreach (var item in itemsToRemove)
{
VariableTables.Remove(item);
}
// 3. 添加新项
var existingIds = new HashSet<int>(VariableTables.Select(vt => vt.Id));
foreach (var dto in variableTableDtos)
{
if (!existingIds.Contains(dto.Id))
{
// 这是一个新变量表,添加到集合中
var newItem = _mapper.Map<VariableTableItemViewModel>(dto);
VariableTables.Add(newItem);
}
}
} }
} }

View File

@@ -25,7 +25,7 @@ namespace DMS.WPF.ViewModels;
/// </summary> /// </summary>
public partial class MainViewModel : ViewModelBase public partial class MainViewModel : ViewModelBase
{ {
private readonly DataServices _dataServices; public DataServices DataServices { get; }
private readonly IDialogService _dialogService; private readonly IDialogService _dialogService;
private readonly ILogger<MainViewModel> _logger; private readonly ILogger<MainViewModel> _logger;
@@ -48,10 +48,10 @@ public partial class MainViewModel : ViewModelBase
/// <param name="dataServices">数据服务。</param> /// <param name="dataServices">数据服务。</param>
/// <param name="dialogService">对话框服务。</param> /// <param name="dialogService">对话框服务。</param>
/// <param name="logger">日志记录器。</param> /// <param name="logger">日志记录器。</param>
public MainViewModel( public MainViewModel(DataServices dataServices,
ILogger<MainViewModel> logger) ILogger<MainViewModel> logger)
{ {
// _dataServices = dataServices; DataServices = dataServices;
_logger = logger; _logger = logger;
CurrentViewModel = new HomeViewModel(); CurrentViewModel = new HomeViewModel();

View File

@@ -18,14 +18,16 @@ public partial class SplashViewModel : ObservableObject
{ {
private readonly IServiceProvider _serviceProvider; private readonly IServiceProvider _serviceProvider;
private readonly IInitializeService _initializeService; private readonly IInitializeService _initializeService;
private readonly DataServices _dataServices;
[ObservableProperty] [ObservableProperty]
private string _loadingMessage = "正在加载..."; private string _loadingMessage = "正在加载...";
public SplashViewModel(IServiceProvider serviceProvider, IInitializeService initializeService) public SplashViewModel(IServiceProvider serviceProvider, IInitializeService initializeService,DataServices dataServices)
{ {
_serviceProvider = serviceProvider; _serviceProvider = serviceProvider;
_initializeService = initializeService; _initializeService = initializeService;
_dataServices = dataServices;
} }
/// <summary> /// <summary>
@@ -37,8 +39,13 @@ public partial class SplashViewModel : ObservableObject
{ {
LoadingMessage = "正在初始化数据库..."; LoadingMessage = "正在初始化数据库...";
_initializeService.InitializeTables(); _initializeService.InitializeTables();
_initializeService.InitializeMenus();
LoadingMessage = "正在加载系统配置..."; LoadingMessage = "正在加载系统配置...";
await _dataServices.LoadDevices();
await _dataServices.LoadVariableTables();
await _dataServices.LoadVariables();
await _dataServices.LoadMenus();
// 可以在这里添加加载配置的逻辑 // 可以在这里添加加载配置的逻辑
await Task.Delay(500); // 模拟耗时 await Task.Delay(500); // 模拟耗时

View File

@@ -31,7 +31,7 @@
</ContextMenu> </ContextMenu>
<DataTemplate x:Key="NavigationViewMenuItem" <DataTemplate x:Key="NavigationViewMenuItem"
DataType="{x:Type mo:MenuBean}"> DataType="{x:Type mo:MenuBean}">
<ui:NavigationViewItem Content="{Binding Name}" <ui:NavigationViewItem Content="{Binding Header}"
MenuItemsSource="{Binding Items }"> MenuItemsSource="{Binding Items }">
<ui:NavigationViewItem.Icon> <ui:NavigationViewItem.Icon>
<ui:FontIcon Glyph="{Binding Icon}" /> <ui:FontIcon Glyph="{Binding Icon}" />
@@ -60,7 +60,7 @@
IsBackButtonVisible="Collapsed" IsBackButtonVisible="Collapsed"
IsBackEnabled="False" IsBackEnabled="False"
SelectionFollowsFocus="Disabled" SelectionFollowsFocus="Disabled"
MenuItemsSource="{Binding Menus}" MenuItemsSource="{Binding DataServices.Menus}"
MenuItemTemplate="{StaticResource NavigationViewMenuItem}" MenuItemTemplate="{StaticResource NavigationViewMenuItem}"
SelectionChanged="NavigationView_SelectionChanged"> SelectionChanged="NavigationView_SelectionChanged">