diff --git a/DMS.Infrastructure/Repositories/InitializeRepository.cs b/DMS.Infrastructure/Repositories/InitializeRepository.cs index 048def2..65422c7 100644 --- a/DMS.Infrastructure/Repositories/InitializeRepository.cs +++ b/DMS.Infrastructure/Repositories/InitializeRepository.cs @@ -1,3 +1,4 @@ +using DMS.Core.Enums; using DMS.Core.Interfaces.Repositories; using DMS.Core.Models; using DMS.Infrastructure.Configurations; @@ -91,26 +92,28 @@ public class InitializeRepository : IInitializeRepository /// /// 初始化默认菜单。 - /// 如果配置文件中没有菜单,则添加一组默认菜单项。 + /// 如果数据库中没有菜单,则添加一组默认菜单项。 /// public void InitializeMenus() { - var settings = AppSettings.Load(); - if (settings.Menus.Any()) + // 检查数据库中是否已存在菜单数据 + if (_db.Queryable().Any()) { - return ; // 如果已经有菜单,则不进行初始化 + return; // 如果数据库中已经有菜单,则不进行初始化 } - // 添加默认菜单项 - settings.Menus.Add(new MenuBean() { Id=1, Header = "主页", Icon = "Home", ParentId = 0 }); - settings.Menus.Add(new MenuBean() { Id = 2, Header = "设备", Icon = "Devices3", ParentId = 0 }); - settings.Menus.Add(new MenuBean() { Id = 3, Header = "数据转换", Icon = "ChromeSwitch", ParentId = 0 }); - settings.Menus.Add(new MenuBean() { Id = 4, Header = "Mqtt服务器", Icon = "Cloud", ParentId = 0 }); - settings.Menus.Add(new MenuBean() { Id = 5, Header = "设置", Icon = "Settings", ParentId = 0 }); - settings.Menus.Add(new MenuBean() { Id = 6, Header = "关于", Icon = "Info", ParentId = 0 }); + // 创建默认菜单项的 DbMenu 实体列表 + var defaultMenus = new List + { + new DbMenu { Id = 1, Header = "主页", Icon = "\uE80F", ParentId = 0,MenuType = MenuType.MainMenu, DisplayOrder = 1 }, + new DbMenu { Id = 2, Header = "设备", Icon = "\uE975", ParentId = 0,MenuType = MenuType.MainMenu , DisplayOrder = 2 }, + new DbMenu { Id = 3, Header = "数据转换", Icon = "\uF1CB", ParentId = 0,MenuType = MenuType.MainMenu , DisplayOrder = 3 }, + 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(); // 保存菜单到配置文件 - - return ; + // 批量插入菜单到数据库 + _db.Insertable(defaultMenus).ExecuteCommand(); } } \ No newline at end of file diff --git a/DMS.WPF/App.xaml.cs b/DMS.WPF/App.xaml.cs index a1a6100..347e1ad 100644 --- a/DMS.WPF/App.xaml.cs +++ b/DMS.WPF/App.xaml.cs @@ -1,7 +1,9 @@ using System.Windows; +using AutoMapper.Internal; using DMS.Application.Interfaces; using DMS.Application.Services; using DMS.Core.Enums; +using DMS.Core.Interfaces; using DMS.Core.Interfaces.Repositories; using DMS.Helper; using DMS.Services; @@ -118,8 +120,16 @@ public partial class App : System.Windows.Application // services.AddHostedService(); // - // 注册 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(); @@ -132,14 +142,27 @@ public partial class App : System.Windows.Application // 注册Core中的仓库 services.AddSingleton(); - services.AddSingleton(); + // services.AddSingleton(); + // 2. 配置数据库上下文 (在测试中通常使用单例) + services.AddSingleton(_ => + { + var appSettings = new AppSettings { Database = { Database = "dms_test" } }; + return new SqlSugarDbContext(appSettings); + }); + services.AddSingleton(); + services.AddSingleton(); + + // 注册App服务 services.AddSingleton(); services.AddSingleton(); - + services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); - + services.AddSingleton(); + //注册WPF中的服务 + services.AddSingleton(); // 注册视图模型 services.AddSingleton(); services.AddSingleton(); diff --git a/DMS.WPF/Services/DataServices.cs b/DMS.WPF/Services/DataServices.cs index b0a0c5e..bf78c59 100644 --- a/DMS.WPF/Services/DataServices.cs +++ b/DMS.WPF/Services/DataServices.cs @@ -1,14 +1,17 @@ using System.Collections.Concurrent; +using System.Collections.ObjectModel; using AutoMapper; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Messaging; using DMS.Application.DTOs; +using DMS.Application.Interfaces; using DMS.Core.Helper; using DMS.Core.Enums; using DMS.Core.Models; using DMS.Helper; using DMS.Message; using DMS.WPF.Helper; +using DMS.WPF.ViewModels.Items; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -22,21 +25,26 @@ namespace DMS.WPF.Services; public partial class DataServices : ObservableRecipient, IRecipient { private readonly IMapper _mapper; + + private readonly IDeviceAppService _deviceAppService; + private readonly IVariableTableAppService _variableTableAppService; + private readonly IVariableAppService _variableAppService; + // 设备列表,使用ObservableProperty特性,当值改变时会自动触发属性变更通知。 [ObservableProperty] - private List _devices; + private ObservableCollection _devices; // 变量表列表。 [ObservableProperty] - private List _variableTables; + private ObservableCollection _variableTables; // 变量数据列表。 [ObservableProperty] - private List _variables; + private ObservableCollection _variables; // 菜单树列表。 [ObservableProperty] - private List menuTrees; + private ObservableCollection _menus; // MQTT配置列表。 // [ObservableProperty] @@ -44,18 +52,8 @@ public partial class DataServices : ObservableRecipient, IRecipient public ConcurrentDictionary 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> OnDeviceListChanged; @@ -84,20 +82,27 @@ public partial class DataServices : ObservableRecipient, IRecipient // OnVariableDataChanged?.Invoke(this, value); // } - // /// - // /// DataServices类的构造函数。 - // /// 注入ILogger,并初始化各个数据仓库。 - // /// - // /// AutoMapper 实例。 - // /// - // public DataServices(IMapper mapper,DeviceRepository deviceRepository,MenuRepository menuRepository,MqttRepository mqttRepository,VarDataRepository varDataRepository) - // { - // _mapper = mapper; - // IsActive = true; // 激活消息接收器 - // - // _variables = new List(); - // AllVariables = new ConcurrentDictionary(); - // } + /// + /// DataServices类的构造函数。 + /// 注入ILogger,并初始化各个数据仓库。 + /// + /// AutoMapper 实例。 + /// + public DataServices(IMapper mapper, IDeviceAppService deviceAppService, + IVariableTableAppService variableTableAppService, IVariableAppService variableAppService,IMenuService menuService) + { + _mapper = mapper; + _deviceAppService = deviceAppService; + _variableTableAppService = variableTableAppService; + _variableAppService = variableAppService; + _menuService = menuService; + IsActive = true; // 激活消息接收器 + Devices = new ObservableCollection(); + VariableTables = new ObservableCollection(); + Variables = new ObservableCollection(); + Menus = new ObservableCollection(); + // AllVariables = new ConcurrentDictionary(); + } // /// // /// 接收加载消息,根据消息类型从数据库加载对应的数据。 @@ -134,88 +139,127 @@ public partial class DataServices : ObservableRecipient, IRecipient // } /// - /// 异步加载设备数据。 + /// 异步加载设备数据,并以高效的方式更新UI集合。 + /// 此方法会比较新旧数据,只对有变化的设备进行更新、添加或删除,避免不必要的UI刷新。 /// - /// 表示异步操作的任务。 - private async Task LoadDevices() + public async Task LoadDevices() { - // 取消订阅旧设备的属性变更事件,防止内存泄漏 - // if (Devices != null) - // { - // foreach (var device in Devices) - // { - // device.PropertyChanged -= Device_PropertyChanged; - // } - // } - // - // Devices = await _deviceRepository.GetAllAsync(); - // - // // 订阅新设备的属性变更事件 - // if (Devices != null) - // { - // foreach (var device in Devices) - // { - // device.PropertyChanged += Device_PropertyChanged; - // } - // - // var allVar = await _varDataRepository.GetAllAsync(); - // foreach (var variable in allVar) - // { - // AllVariables.AddOrUpdate(variable.Id, variable, (key, old) => variable); - // } - // - // } - // - // OnDeviceListChanged?.Invoke(Devices); - } + var deviceDtos = await _deviceAppService.GetAllDevicesAsync(); + var deviceDtoIds = new HashSet(deviceDtos.Select(d => d.Id)); - private void Device_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) - { - if (e.PropertyName == nameof(Device.IsActive)) + // 1. 更新现有项 & 查找需要删除的项 + var itemsToRemove = new List(); + foreach (var existingItem in Devices) { - if (sender is Device device) + if (deviceDtoIds.Contains(existingItem.Id)) { - NlogHelper.Info($"设备 {device.Name} 的IsActive状态改变为 {device.IsActive},触发设备IsActive状态变更事件。"); - OnDeviceIsActiveChanged?.Invoke(device, device.IsActive); + // 设备仍然存在,检查是否有更新 + var dto = deviceDtos.First(d => d.Id == existingItem.Id); + + // 逐一比较属性,只有在发生变化时才更新 + if (existingItem.Name != dto.Name) existingItem.Name = dto.Name; + if (existingItem.Protocol != dto.Protocol) existingItem.Protocol = dto.Protocol; + if (existingItem.IpAddress != dto.IpAddress) existingItem.IpAddress = dto.IpAddress; + 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; + if (existingItem.OpcUaServerUrl != dto.OpcUaServerUrl) existingItem.OpcUaServerUrl = dto.OpcUaServerUrl; + if (existingItem.IsActive != dto.IsActive) existingItem.IsActive = dto.IsActive; + if (existingItem.Status != dto.Status) existingItem.Status = dto.Status; + } + else + { + // 设备在新列表中不存在,标记为待删除 + itemsToRemove.Add(existingItem); + } + } + + // 2. 从UI集合中删除不再存在的项 + foreach (var item in itemsToRemove) + { + Devices.Remove(item); + } + + // 3. 添加新项 + var existingIds = new HashSet(Devices.Select(d => d.Id)); + foreach (var dto in deviceDtos) + { + if (!existingIds.Contains(dto.Id)) + { + // 这是一个新设备,添加到集合中 + var newItem = _mapper.Map(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); + // } + // } + // } + /// - /// 异步加载菜单数据,并进行父级关联和排序。 + /// 异步加载菜单数据,并以高效的方式更新UI集合。 + /// 此方法会比较新旧数据,只对有变化的菜单项进行更新、添加或删除,避免不必要的UI刷新。 /// - /// 表示异步操作的任务。 - private async Task LoadMenus() + public async Task LoadMenus() { - // MenuTrees = await _menuRepository.GetMenuTreesAsync(); - // foreach (MenuBean menu in MenuTrees) - // { - // MenuHelper.MenuAddParent(menu); // 为菜单添加父级引用 - // DataServicesHelper.SortMenus(menu); // 排序菜单 - // } - // - // OnMenuTreeListChanged?.Invoke(MenuTrees); + var newMenus = await _menuService.GetAllMenusAsync(); // 获取最新的菜单树 (MenuItemViewModel 列表) + var newMenuIds = new HashSet(newMenus.Select(m => m.Id)); + + // 1. 更新现有项 & 查找需要删除的项 + var itemsToRemove = new List(); + foreach (var existingItem in Menus) + { + 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); + } + } + + // 2. 从UI集合中删除不再存在的项 + foreach (var item in itemsToRemove) + { + Menus.Remove(item); + } + + // 3. 添加新项 + var existingIds = new HashSet(Menus.Select(m => m.Id)); + foreach (var newDto in newMenus) + { + if (!existingIds.Contains(newDto.Id)) + { + // 这是一个新菜单项,添加到集合中 + // 注意:这里直接添加 IMenuService 返回的 MenuItemViewModel 实例 + Menus.Add(_mapper.Map(newDto)); + } + } } - // /// - // /// 异步获取所有MQTT配置。 - // /// - // /// 包含所有MQTT配置的列表。 - // public async Task> GetMqttsAsync() - // { - // var mqtts = await _mqttRepository.GetAllAsync(); - // OnMqttListChanged?.Invoke(mqtts); - // return mqtts; - // } - - // /// - // /// 异步加载MQTT配置数据。 - // /// - // /// 表示异步操作的任务。 - // private async Task LoadMqtts() - // { - // Mqtts = await _mqttRepository.GetAllAsync(); - // } // /// @@ -249,6 +293,127 @@ public partial class DataServices : ObservableRecipient, IRecipient public void Receive(LoadMessage message) { - + } + + /// + /// 异步加载变量数据,并以高效的方式更新UI集合。 + /// 此方法会比较新旧数据,只对有变化的变量进行更新、添加或删除,避免不必要的UI刷新。 + /// + public async Task LoadVariables() + { + var variableDtos = await _variableAppService.GetAllVariablesAsync(); // 假设有此方法 + var variableDtoIds = new HashSet(variableDtos.Select(v => v.Id)); + + // 1. 更新现有项 & 查找需要删除的项 + var itemsToRemove = new List(); + 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(Variables.Select(v => v.Id)); + foreach (var dto in variableDtos) + { + if (!existingIds.Contains(dto.Id)) + { + // 这是一个新变量,添加到集合中 + var newItem = _mapper.Map(dto); + Variables.Add(newItem); + } + } + } + + /// + /// 异步加载变量表数据,并以高效的方式更新UI集合。 + /// 此方法会比较新旧数据,只对有变化的变量表进行更新、添加或删除,避免不必要的UI刷新。 + /// + public async Task LoadVariableTables() + { + var variableTableDtos = await _variableTableAppService.GetAllVariableTablesAsync(); // 假设有此方法 + var variableTableDtoIds = new HashSet(variableTableDtos.Select(vt => vt.Id)); + + // 1. 更新现有项 & 查找需要删除的项 + var itemsToRemove = new List(); + 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(VariableTables.Select(vt => vt.Id)); + foreach (var dto in variableTableDtos) + { + if (!existingIds.Contains(dto.Id)) + { + // 这是一个新变量表,添加到集合中 + var newItem = _mapper.Map(dto); + VariableTables.Add(newItem); + } + } } } \ No newline at end of file diff --git a/DMS.WPF/ViewModels/MainViewModel.cs b/DMS.WPF/ViewModels/MainViewModel.cs index ab8b477..9ae714c 100644 --- a/DMS.WPF/ViewModels/MainViewModel.cs +++ b/DMS.WPF/ViewModels/MainViewModel.cs @@ -25,7 +25,7 @@ namespace DMS.WPF.ViewModels; /// public partial class MainViewModel : ViewModelBase { - private readonly DataServices _dataServices; + public DataServices DataServices { get; } private readonly IDialogService _dialogService; private readonly ILogger _logger; @@ -48,10 +48,10 @@ public partial class MainViewModel : ViewModelBase /// 数据服务。 /// 对话框服务。 /// 日志记录器。 - public MainViewModel( + public MainViewModel(DataServices dataServices, ILogger logger) { - // _dataServices = dataServices; + DataServices = dataServices; _logger = logger; CurrentViewModel = new HomeViewModel(); diff --git a/DMS.WPF/ViewModels/SplashViewModel.cs b/DMS.WPF/ViewModels/SplashViewModel.cs index 343179a..99d2c6a 100644 --- a/DMS.WPF/ViewModels/SplashViewModel.cs +++ b/DMS.WPF/ViewModels/SplashViewModel.cs @@ -18,14 +18,16 @@ public partial class SplashViewModel : ObservableObject { private readonly IServiceProvider _serviceProvider; private readonly IInitializeService _initializeService; + private readonly DataServices _dataServices; [ObservableProperty] private string _loadingMessage = "正在加载..."; - public SplashViewModel(IServiceProvider serviceProvider, IInitializeService initializeService) + public SplashViewModel(IServiceProvider serviceProvider, IInitializeService initializeService,DataServices dataServices) { _serviceProvider = serviceProvider; _initializeService = initializeService; + _dataServices = dataServices; } /// @@ -37,8 +39,13 @@ public partial class SplashViewModel : ObservableObject { LoadingMessage = "正在初始化数据库..."; _initializeService.InitializeTables(); + _initializeService.InitializeMenus(); LoadingMessage = "正在加载系统配置..."; + await _dataServices.LoadDevices(); + await _dataServices.LoadVariableTables(); + await _dataServices.LoadVariables(); + await _dataServices.LoadMenus(); // 可以在这里添加加载配置的逻辑 await Task.Delay(500); // 模拟耗时 diff --git a/DMS.WPF/Views/MainView.xaml b/DMS.WPF/Views/MainView.xaml index bb281cd..f076c54 100644 --- a/DMS.WPF/Views/MainView.xaml +++ b/DMS.WPF/Views/MainView.xaml @@ -31,7 +31,7 @@ - @@ -60,7 +60,7 @@ IsBackButtonVisible="Collapsed" IsBackEnabled="False" SelectionFollowsFocus="Disabled" - MenuItemsSource="{Binding Menus}" + MenuItemsSource="{Binding DataServices.Menus}" MenuItemTemplate="{StaticResource NavigationViewMenuItem}" SelectionChanged="NavigationView_SelectionChanged">