diff --git a/DMS.Core/Enums/NavigationType.cs b/DMS.Core/Enums/NavigationType.cs new file mode 100644 index 0000000..dbf94ba --- /dev/null +++ b/DMS.Core/Enums/NavigationType.cs @@ -0,0 +1,12 @@ +using DMS.Core.Models; + +namespace DMS.Core.Enums; + +public enum NavigationType +{ + None, + Device, + VariableTable, + Variable, + Mqtt, +} \ No newline at end of file diff --git a/DMS.Core/Models/NavigationParameter.cs b/DMS.Core/Models/NavigationParameter.cs new file mode 100644 index 0000000..99b8e59 --- /dev/null +++ b/DMS.Core/Models/NavigationParameter.cs @@ -0,0 +1,22 @@ +using DMS.Core.Enums; + +namespace DMS.Core.Models; + +public class NavigationParameter +{ + + public string TargetViewKey { get; set; } + + public NavigationType TargetType { get; set; } + + public int TargetId { get; set; } + + public NavigationParameter(string targetViewKey, int targetId=0,NavigationType targetType=NavigationType.None ) + { + TargetViewKey = targetViewKey; + TargetType = targetType; + TargetId = targetId; + } + + +} \ No newline at end of file diff --git a/DMS.WPF/Interfaces/INavigatable.cs b/DMS.WPF/Interfaces/INavigatable.cs index 882eb20..247876e 100644 --- a/DMS.WPF/Interfaces/INavigatable.cs +++ b/DMS.WPF/Interfaces/INavigatable.cs @@ -1,5 +1,6 @@ // 文件: DMS.WPF/Services/INavigatable.cs +using DMS.Core.Models; using DMS.WPF.ViewModels.Items; namespace DMS.WPF.Interfaces; @@ -13,5 +14,13 @@ public interface INavigatable /// 当导航到此ViewModel时,由导航服务调用此方法,以传递参数。 /// /// 从导航源传递过来的参数对象。 - Task OnNavigatedToAsync(MenuItemViewModel menu); + Task OnNavigatedToAsync(NavigationParameter navigationParameter); + + /// + /// 当从当前ViewModel导航离开时,由导航服务调用此方法。 + /// + /// 即将导航到的下一个ViewModel。 + Task OnNavigatedFromAsync(NavigationParameter navigationParameter); + + } diff --git a/DMS.WPF/Interfaces/INavigationService.cs b/DMS.WPF/Interfaces/INavigationService.cs index 8de3127..4569c35 100644 --- a/DMS.WPF/Interfaces/INavigationService.cs +++ b/DMS.WPF/Interfaces/INavigationService.cs @@ -1,5 +1,6 @@ // 文件: DMS.WPF/Services/INavigationService.cs +using DMS.Core.Models; using DMS.WPF.ViewModels.Items; namespace DMS.WPF.Interfaces; @@ -9,18 +10,12 @@ namespace DMS.WPF.Interfaces; /// public interface INavigationService { - /// - /// 导航到由唯一键标识的视图,并传递一个参数。 - /// - /// 在DI容器中注册的目标视图的唯一键(通常是ViewModel的名称)。 - /// 要传递给目标ViewModel的参数。 - Task NavigateToAsync(MenuItemViewModel menu); /// /// 导航到由唯一键标识的视图,并传递一个参数。 /// /// 在DI容器中注册的目标视图的唯一键(通常是ViewModel的名称)。 /// 要传递给目标ViewModel的参数。 - Task NavigateToAsync(string viewKey, object parameter = null); + Task NavigateToAsync(object sender,NavigationParameter parameter); } diff --git a/DMS.WPF/Services/NavigationService.cs b/DMS.WPF/Services/NavigationService.cs index 206f5f6..9d07c2e 100644 --- a/DMS.WPF/Services/NavigationService.cs +++ b/DMS.WPF/Services/NavigationService.cs @@ -1,7 +1,10 @@ +using DMS.Core.Models; using DMS.WPF.Interfaces; using DMS.WPF.ViewModels; using DMS.WPF.ViewModels.Items; +using DMS.WPF.Views; using Microsoft.Extensions.DependencyInjection; +using Microsoft.IdentityModel.Tokens; namespace DMS.WPF.Services; @@ -22,49 +25,34 @@ public class NavigationService : INavigationService _notificationService = notificationService; } - /// - /// 导航到指定键的视图,并传递参数。 - /// - public async Task NavigateToAsync(MenuItemViewModel menu) - { - if (string.IsNullOrEmpty(menu.TargetViewKey)) - { - return; - } - - var mainViewModel = App.Current.Services.GetRequiredService(); - var viewModel = GetViewModelByKey(menu.TargetViewKey); - if (viewModel == null) - { - _notificationService.ShowError($"切换界面失败,没有找到界面:{menu.TargetViewKey}"); - return; - } - - - if (viewModel is INavigatable navigatableViewModel) - { - await navigatableViewModel.OnNavigatedToAsync(menu); - } - - mainViewModel.CurrentViewModel = viewModel; - } /// /// 导航到指定键的视图,并传递参数。 /// - public async Task NavigateToAsync(string viewKey, object parameter = null) + public async Task NavigateToAsync(object sender,NavigationParameter parameter) { - var mainViewModel = App.Current.Services.GetRequiredService(); - var viewModel = GetViewModelByKey(viewKey); + if (parameter == null || string.IsNullOrWhiteSpace(parameter.TargetViewKey) )return; + + + var viewModel = GetViewModelByKey(parameter.TargetViewKey); if (viewModel == null) { - _notificationService.ShowError($"切换界面失败,没有找到界面:{viewKey}"); + _notificationService.ShowError($"切换界面失败,没有找到界面:{parameter.TargetViewKey}"); return; } + + if (sender is INavigatable fromViewModel) + { + await fromViewModel.OnNavigatedFromAsync(parameter); + } - - + var mainViewModel = App.Current.Services.GetRequiredService(); mainViewModel.CurrentViewModel = viewModel; + + if (viewModel is INavigatable toViewModel) + { + await toViewModel.OnNavigatedToAsync(parameter); + } } @@ -74,29 +62,29 @@ public class NavigationService : INavigationService { switch (key) { - case "HomeView": + case nameof(HomeViewModel): return App.Current.Services.GetRequiredService(); - case "DevicesView": + case nameof(DevicesViewModel): return App.Current.Services.GetRequiredService(); - case "DeviceDetailView": + case nameof(DeviceDetailViewModel): return App.Current.Services.GetRequiredService(); - case "DataTransformView": + case nameof(DataTransformViewModel): return App.Current.Services.GetRequiredService(); - case "VariableTableView": + case nameof(VariableTableViewModel): return App.Current.Services.GetRequiredService(); - case "VariableHistoryView": + case nameof(VariableHistoryViewModel): return App.Current.Services.GetRequiredService(); - case "LogHistoryView": + case nameof(LogHistoryViewModel): return App.Current.Services.GetRequiredService(); - case "MqttsView": + case nameof(MqttsViewModel): return App.Current.Services.GetRequiredService(); - case "MqttServerDetailView": + case nameof(MqttServerDetailViewModel): return App.Current.Services.GetRequiredService(); - case "SettingView": + case nameof(SettingViewModel): return App.Current.Services.GetRequiredService(); - case "EmailManagementView": + case nameof(EmailManagementViewModel): return App.Current.Services.GetRequiredService(); - case "TriggersView": + case nameof(TriggersViewModel): return App.Current.Services.GetRequiredService(); default: return null; diff --git a/DMS.WPF/ViewModels/DeviceDetailViewModel.cs b/DMS.WPF/ViewModels/DeviceDetailViewModel.cs index e30f2e1..4d540f0 100644 --- a/DMS.WPF/ViewModels/DeviceDetailViewModel.cs +++ b/DMS.WPF/ViewModels/DeviceDetailViewModel.cs @@ -5,6 +5,7 @@ using Dm; using DMS.Application.DTOs; using DMS.Application.Interfaces; using DMS.Core.Enums; +using DMS.Core.Models; using DMS.WPF.Services; using DMS.Services; using DMS.WPF.Interfaces; @@ -14,7 +15,7 @@ using iNKORE.UI.WPF.Modern.Common.IconKeys; namespace DMS.WPF.ViewModels; -public partial class DeviceDetailViewModel : ViewModelBase, INavigatable +public partial class DeviceDetailViewModel : ViewModelBase { private readonly IMapper _mapper; private readonly IDialogService _dialogService; @@ -70,7 +71,7 @@ public partial class DeviceDetailViewModel : ViewModelBase, INavigatable { Header = variableTableItemViewModel.Name, Icon = SegoeFluentIcons.DataSense.Glyph, - TargetViewKey = "VariableTableView" + TargetViewKey = nameof(VariableTableViewModel) }; int addVarTableId = await _wpfDataService.VariableTableDataService.AddVariableTable( _mapper.Map(variableTableItemViewModel), @@ -187,9 +188,10 @@ public partial class DeviceDetailViewModel : ViewModelBase, INavigatable } - public async Task OnNavigatedToAsync(MenuItemViewModel menu) + + public override async Task OnNavigatedToAsync(NavigationParameter parameter) { - if (_dataStorageService.Devices.TryGetValue(menu.TargetId, out var device)) + if (_dataStorageService.Devices.TryGetValue(parameter.TargetId, out var device)) { CurrentDevice = device; } @@ -199,9 +201,12 @@ public partial class DeviceDetailViewModel : ViewModelBase, INavigatable public void NavigateToVariableTable() { if (SelectedVariableTable == null) return; - var menu = _dataStorageService.Menus.FirstOrDefault(m => m.MenuType == MenuType.VariableTableMenu && - m.TargetId == SelectedVariableTable.Id); - if (menu == null) return; - _navigationService.NavigateToAsync(menu); + // var menu = _dataStorageService.Menus.FirstOrDefault(m => m.MenuType == MenuType.VariableTableMenu && + // m.TargetId == SelectedVariableTable.Id); + // if (menu == null) return; + _navigationService.NavigateToAsync( + this, + new NavigationParameter(nameof(VariableTableViewModel), SelectedVariableTable.Id, + NavigationType.VariableTable)); } } diff --git a/DMS.WPF/ViewModels/DevicesViewModel.cs b/DMS.WPF/ViewModels/DevicesViewModel.cs index faac014..dd86211 100644 --- a/DMS.WPF/ViewModels/DevicesViewModel.cs +++ b/DMS.WPF/ViewModels/DevicesViewModel.cs @@ -6,6 +6,7 @@ using DMS.Application.DTOs; using DMS.Application.Interfaces; using DMS.Application.Interfaces.Database; using DMS.Core.Enums; +using DMS.Core.Models; using DMS.WPF.Interfaces; using DMS.WPF.Services; using DMS.WPF.ViewModels.Dialogs; @@ -122,7 +123,7 @@ public partial class DevicesViewModel : ViewModelBase, INavigatable { Header = dto.VariableTable.Name, Icon = SegoeFluentIcons.DataSense.Glyph, - TargetViewKey = "VariableTableView" + TargetViewKey = nameof(VariableTableViewModel) }; } @@ -241,16 +242,9 @@ public partial class DevicesViewModel : ViewModelBase, INavigatable { if (SelectedDevice == null) return; - var menu = _dataStorageService.Menus.FirstOrDefault(m => m.MenuType == MenuType.DeviceMenu && - m.TargetId == SelectedDevice.Id); - if (menu == null) return; - - _navigationService.NavigateToAsync(menu); + _navigationService.NavigateToAsync(this,new NavigationParameter(nameof(DeviceDetailViewModel),SelectedDevice.Id,NavigationType.Device)); } - public async Task OnNavigatedToAsync(MenuItemViewModel menu) - { - } [RelayCommand] private async Task AddVariableTable(DeviceItemViewModel device) @@ -276,7 +270,7 @@ public partial class DevicesViewModel : ViewModelBase, INavigatable { Header = variableTableItemViewModel.Name, Icon = SegoeFluentIcons.DataSense.Glyph, - TargetViewKey = "VariableTableView" + TargetViewKey = nameof(VariableTableViewModel) }; int addVarTableId = await _wpfDataService.VariableTableDataService.AddVariableTable( _mapper.Map(variableTableItemViewModel), diff --git a/DMS.WPF/ViewModels/MainViewModel.cs b/DMS.WPF/ViewModels/MainViewModel.cs index 978ed84..3ab6ac4 100644 --- a/DMS.WPF/ViewModels/MainViewModel.cs +++ b/DMS.WPF/ViewModels/MainViewModel.cs @@ -57,10 +57,6 @@ public partial class MainViewModel : ViewModelBase CurrentViewModel = new HomeViewModel(); CurrentViewModel.OnLoaded(); - // 发送消息加载数据 - MessageHelper.SendLoadMessage(LoadTypes.All); - // 当菜单加载成功后,在前台显示菜单 - // _dataServices.OnMenuTreeListChanged += (menus) => { Menus = new ObservableCollection(menus); }; } /// @@ -84,86 +80,6 @@ public partial class MainViewModel : ViewModelBase // Application.Current.Shutdown(); } - /// - /// 添加变量表。 - /// - /// 当前菜单项,用于获取父级设备信息。 - private async Task AddVariableTable(MenuBean menu) - { - // var db = DbContext.GetInstance(); - // try - // { - // // 1. 检查父级设备信息 - // if (menu.Parent?.Data is not Device device) - // { - // _logger.LogWarning("尝试添加变量表时,Parent 或 Parent.Data 为空,或 Parent.Data 不是 Device 类型。"); - // NotificationHelper.ShowError("操作失败:无法获取有效的设备信息。"); - // return; - // } - // - // - // // 2. 显示添加变量表对话框 - // var varTable = await _dialogService.ShowAddVarTableDialog(); - // if (varTable == null) - // { - // // 用户取消或未选择 - // return; - // } - // - // // 3. 设置变量表属性 - // varTable.IsActive = true; - // varTable.DeviceId = device.Id; - // varTable.ProtocolType = device.ProtocolType; - // - // // 4. 添加变量表到数据库 - // // 假设 _varTableRepository.AddAsync 返回一个布尔值表示成功,或者一个表示 ID 的整数 - // // 这里为了演示,我们假设它返回新添加的ID,如果失败则返回0 - // await db.BeginTranAsync(); - // var addVarTable = await _varTableRepository.AddAsync(varTable, db); - // - // // 5. 添加变量表菜单 - // MenuBean newMenu = new MenuBean - // { - // Icon = SegoeFluentIcons.Tablet.Glyph, - // Name = varTable.Name, - // DataId = addVarTable.Id, // 使用实际添加的ID - // Type = MenuType.VariableTableMenu, - // ParentId = menu.Parent.Id - // }; - // - // var addMenuRes = await _menuRepository.AddAsync(newMenu, db); - // if (addMenuRes > 0) - // { - // await db.CommitTranAsync(); - // // 变量表和菜单都添加成功 - // MessageHelper.SendLoadMessage(LoadTypes.Menu); - // MessageHelper.SendLoadMessage(LoadTypes.Devices); - // NotificationHelper.ShowSuccess($"变量表:{varTable.Name},添加成功"); - // _logger.LogInformation($"变量表:{varTable.Name},添加成功"); - // } - // else - // { - // await db.RollbackTranAsync(); - // // 变量表菜单添加失败 (此时变量表可能已添加成功,需要根据业务决定是否回滚) - // NotificationHelper.ShowError($"变量表:{varTable.Name},添加菜单失败"); - // _logger.LogError($"变量表:{varTable.Name},添加菜单失败"); - // // 考虑:如果菜单添加失败,是否需要删除之前添加的变量表? - // // 例如:await _varTableRepository.DeleteAsync(addVarTableId); - // } - // } - // catch (Exception e) - // { - // await db.RollbackTranAsync(); - // NotificationHelper.ShowError($"添加变量表时出现了错误:{e.Message}", e); - // } - } - /// - /// 处理菜单选择变化的逻辑。 - /// - /// 被选中的菜单项。 - public async Task MenuSelectionChanged(MenuItemViewModel menu) - { - _navigationService.NavigateToAsync(menu); - } + } \ No newline at end of file diff --git a/DMS.WPF/ViewModels/MqttsViewModel.cs b/DMS.WPF/ViewModels/MqttsViewModel.cs index 5dba6e0..38847f3 100644 --- a/DMS.WPF/ViewModels/MqttsViewModel.cs +++ b/DMS.WPF/ViewModels/MqttsViewModel.cs @@ -6,6 +6,7 @@ using DMS.Application.DTOs; using DMS.Application.Interfaces; using DMS.Application.Interfaces.Database; using DMS.Core.Enums; +using DMS.Core.Models; using DMS.WPF.Interfaces; using DMS.WPF.Services; using DMS.WPF.ViewModels.Dialogs; @@ -177,12 +178,13 @@ public partial class MqttsViewModel : ViewModelBase } // 导航到MQTT服务器详情页 - var menu = new MenuItemViewModel - { - TargetViewKey = "MqttServerDetailView", - TargetId = SelectedMqtt.Id - }; - - await _navigationService.NavigateToAsync(menu); + // var menu = new MenuItemViewModel + // { + // TargetViewKey = "MqttServerDetailView", + // TargetId = SelectedMqtt.Id + // }; + + await _navigationService.NavigateToAsync( + this, new NavigationParameter(nameof(MqttServerDetailViewModel), SelectedMqtt.Id, NavigationType.Mqtt)); } } \ No newline at end of file diff --git a/DMS.WPF/ViewModels/VariableHistoryViewModel.cs b/DMS.WPF/ViewModels/VariableHistoryViewModel.cs index 18fa047..d566e24 100644 --- a/DMS.WPF/ViewModels/VariableHistoryViewModel.cs +++ b/DMS.WPF/ViewModels/VariableHistoryViewModel.cs @@ -6,7 +6,9 @@ using DMS.Application.DTOs; using DMS.Application.Events; using DMS.Application.Interfaces; using DMS.Application.Interfaces.Database; +using DMS.Core.Enums; using DMS.Core.Events; +using DMS.Core.Models; using DMS.WPF.Interfaces; using DMS.WPF.ViewModels.Items; using LiveChartsCore; @@ -28,6 +30,7 @@ partial class VariableHistoryViewModel : ViewModelBase, INavigatable private readonly IDataStorageService _dataStorageService; private readonly IEventService _eventService; private readonly INotificationService _notificationService; + private readonly INavigationService _navigationService; /// /// 加载历史记录条数限制 @@ -83,8 +86,8 @@ partial class VariableHistoryViewModel : ViewModelBase, INavigatable public VariableHistoryViewModel(IMapper mapper, IDialogService dialogService, IHistoryAppService historyAppService, IWPFDataService wpfDataService, IDataStorageService dataStorageService, - IEventService eventService, - INotificationService notificationService) + IEventService eventService, INotificationService notificationService, + INavigationService navigationService) { _mapper = mapper; _dialogService = dialogService; @@ -93,6 +96,7 @@ partial class VariableHistoryViewModel : ViewModelBase, INavigatable _dataStorageService = dataStorageService; _eventService = eventService; _notificationService = notificationService; + _navigationService = navigationService; _variableHistoryList = new ObservableList(); _variableHistorySynchronizedView = _variableHistoryList.CreateView(v => v); @@ -168,9 +172,9 @@ partial class VariableHistoryViewModel : ViewModelBase, INavigatable } - public async Task OnNavigatedToAsync(MenuItemViewModel menu) + public override async Task OnNavigatedToAsync(NavigationParameter parameter) { - if (_dataStorageService.Variables.TryGetValue(menu.TargetId, out VariableItemViewModel variableItem)) + if (_dataStorageService.Variables.TryGetValue(parameter.TargetId, out VariableItemViewModel variableItem)) { CurrentVariable = variableItem; // 加载所有变量的历史记录 @@ -190,6 +194,23 @@ partial class VariableHistoryViewModel : ViewModelBase, INavigatable } } + /// + /// 返回变量表命令 + /// + [RelayCommand] + private async Task NavigateToVariableTable() + { + try + { + // 导航到变量表页面 + await _navigationService.NavigateToAsync(this,new NavigationParameter(nameof(VariableTableViewModel),CurrentVariable.VariableTableId,NavigationType.VariableTable)); + } + catch (Exception ex) + { + _notificationService.ShowError($"导航到变量表失败: {ex.Message}", ex); + } + } + /// /// 根据搜索文本过滤历史记录 diff --git a/DMS.WPF/ViewModels/VariableTableViewModel.cs b/DMS.WPF/ViewModels/VariableTableViewModel.cs index cca154d..20d99b4 100644 --- a/DMS.WPF/ViewModels/VariableTableViewModel.cs +++ b/DMS.WPF/ViewModels/VariableTableViewModel.cs @@ -739,11 +739,9 @@ partial class VariableTableViewModel : ViewModelBase, INavigatable { // 导航到历史记录视图 var navigationService = App.Current.Services.GetRequiredService(); - MenuItemViewModel viewModel = new MenuItemViewModel(); - viewModel.TargetViewKey = "VariableHistoryView"; - viewModel.MenuType = MenuType.VariableMenu; - viewModel.TargetId = SelectedVariable.Id; - navigationService.NavigateToAsync(viewModel); + navigationService.NavigateToAsync( + this, + new NavigationParameter(nameof(VariableHistoryViewModel), SelectedVariable.Id, NavigationType.Variable)); } /// @@ -875,9 +873,9 @@ partial class VariableTableViewModel : ViewModelBase, INavigatable // } } - public async Task OnNavigatedToAsync(MenuItemViewModel menu) + public override async Task OnNavigatedToAsync(NavigationParameter parameter) { - if (_dataStorageService.VariableTables.TryGetValue(menu.TargetId, out var varTable)) + if (_dataStorageService.VariableTables.TryGetValue(parameter.TargetId, out var varTable)) { CurrentVariableTable = varTable; // 根据变量表的协议类型设置对应的布尔属性 diff --git a/DMS.WPF/ViewModels/ViewModelBase.cs b/DMS.WPF/ViewModels/ViewModelBase.cs index f512c5f..fa68805 100644 --- a/DMS.WPF/ViewModels/ViewModelBase.cs +++ b/DMS.WPF/ViewModels/ViewModelBase.cs @@ -1,8 +1,11 @@ using CommunityToolkit.Mvvm.ComponentModel; +using DMS.Core.Models; +using DMS.WPF.Interfaces; +using DMS.WPF.ViewModels.Items; namespace DMS.WPF.ViewModels; -public abstract class ViewModelBase : ObservableObject +public abstract class ViewModelBase : ObservableObject,INavigatable { public virtual void OnLoaded() { @@ -20,5 +23,13 @@ public abstract class ViewModelBase : ObservableObject } + public virtual async Task OnNavigatedToAsync(NavigationParameter parameter) + { + + } + public virtual async Task OnNavigatedFromAsync(NavigationParameter parameter) + { + + } } \ No newline at end of file diff --git a/DMS.WPF/Views/MainView.xaml.cs b/DMS.WPF/Views/MainView.xaml.cs index db41ad5..f19a269 100644 --- a/DMS.WPF/Views/MainView.xaml.cs +++ b/DMS.WPF/Views/MainView.xaml.cs @@ -4,6 +4,8 @@ using DMS.WPF.ViewModels; using iNKORE.UI.WPF.Modern.Controls; using Microsoft.Extensions.DependencyInjection; using DMS.Core.Enums; +using DMS.Core.Models; +using DMS.WPF.Interfaces; using DMS.WPF.ViewModels.Items; namespace DMS.WPF.Views; @@ -60,7 +62,24 @@ public partial class MainView : Window var menu = args.SelectedItem as MenuItemViewModel; if (menu != null) { - await _viewModel.MenuSelectionChanged(menu); + + NavigationType navigationType = NavigationType.None; + switch (menu.MenuType) + { + case MenuType.DeviceMenu: + navigationType=NavigationType.Device; + break; + case MenuType.VariableTableMenu: + navigationType=NavigationType.VariableTable; + break; + case MenuType.MqttMenu: + navigationType=NavigationType.Mqtt; + break; + + } + + var navigationService= App.Current.Services.GetRequiredService(); + navigationService.NavigateToAsync(this,new NavigationParameter(menu.TargetViewKey,menu.TargetId,navigationType)); } } diff --git a/DMS.WPF/Views/VariableHistoryView.xaml b/DMS.WPF/Views/VariableHistoryView.xaml index d9a6ae9..e8f3b22 100644 --- a/DMS.WPF/Views/VariableHistoryView.xaml +++ b/DMS.WPF/Views/VariableHistoryView.xaml @@ -34,76 +34,102 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - - - - - + + + + + - - - - - - - - - -