给应用添加图标,完成给设备添加变量表的功能

This commit is contained in:
2025-07-02 12:01:20 +08:00
parent 663e4fda0c
commit dbf7b81d4b
20 changed files with 326 additions and 151 deletions

View File

@@ -2,6 +2,7 @@
x:Class="PMSWPF.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern">
<Application.Resources>
<ResourceDictionary>

BIN
Assets/AppIcon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -40,7 +40,7 @@ public class MenuRepository
}
public async Task<int> AddMenu(MenuBean menu)
public async Task<int> Add(MenuBean menu)
{
using (var db = DbContext.GetInstance())
{

View File

@@ -0,0 +1,21 @@
using PMSWPF.Data.Entities;
using PMSWPF.Extensions;
using PMSWPF.Models;
namespace PMSWPF.Data.Repositories;
public class VarTableRepository
{
/// <summary>
/// 添加变量表
/// </summary>
/// <param name="varTable"></param>
/// <returns>变量表的ID</returns>
public async Task<int> Add(VariableTable varTable)
{
using (var db = DbContext.GetInstance())
{
return await db.Insertable<DbVariableTable>(varTable.CopyTo<DbVariableTable>()).ExecuteReturnIdentityAsync();
}
}
}

View File

@@ -7,6 +7,24 @@ namespace PMSWPF.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,List<MenuBean> menus)
{
foreach (var mainMenu in menus)
@@ -24,6 +42,23 @@ public class DataServicesHelper
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>();

View File

@@ -5,7 +5,9 @@ namespace PMSWPF.Message;
public class LoadMessage:ValueChangedMessage<LoadTypes>
{
public LoadTypes LoadType { get; set; }
public LoadMessage(LoadTypes types) : base(types)
{
LoadType=types;
}
}

View File

@@ -1,13 +1,17 @@
using PMSWPF.Enums;
using CommunityToolkit.Mvvm.ComponentModel;
using PMSWPF.Enums;
namespace PMSWPF.Models;
public class VariableTable
public partial class VariableTable:ObservableObject
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
[ObservableProperty] private string name;
[ObservableProperty] private string description;
public ProtocolType ProtocolType { get; set; }
public List<DataVariable> DataVariables { get; set; }
public int? DeviceId { get; set; }
public Device? Device { get; set; }
}

View File

@@ -6,6 +6,7 @@
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
<ApplicationIcon>AppIcon2.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0"/>
@@ -28,5 +29,9 @@
<ItemGroup>
<Compile Remove="Data\Repositories\BaseRepositories.cs" />
</ItemGroup>
<ItemGroup>
<None Remove="Assets\AppIcon.png" />
<Resource Include="Assets\AppIcon.png" />
</ItemGroup>
</Project>

View File

@@ -21,6 +21,7 @@ public partial class DataServices : ObservableRecipient, IRecipient<LoadMessage>
private readonly DeviceRepository _deviceRepository;
private readonly MenuRepository _menuRepository;
public event Action<List<Device>> OnDeviceListChanged;
public event Action<List<MenuBean>> OnMenuTreeListChanged;
@@ -28,19 +29,11 @@ public partial class DataServices : ObservableRecipient, IRecipient<LoadMessage>
partial void OnDevicesChanged(List<Device> devices)
{
OnDeviceListChanged?.Invoke(devices);
if (menuTrees != null && Devices != null)
{
FillMenuData(MenuTrees, Devices);
}
}
partial void OnMenuTreesChanged(List<MenuBean> MenuTrees)
{
OnMenuTreeListChanged?.Invoke(MenuTrees);
if (MenuTrees != null && Devices != null)
{
FillMenuData(MenuTrees, Devices);
}
}
@@ -53,77 +46,6 @@ public partial class DataServices : ObservableRecipient, IRecipient<LoadMessage>
}
/// <summary>
/// 给Menu菜单的Data填充数据
/// </summary>
/// <param name="MenuTrees"></param>
private void FillMenuData(List<MenuBean> MenuTrees, List<Device> devices)
{
if (MenuTrees == null || MenuTrees.Count == 0)
return;
foreach (MenuBean menuBean in MenuTrees)
{
switch (menuBean.Type)
{
case MenuType.MainMenu:
menuBean.ViewModel =DataServicesHelper.GetMainViewModel(menuBean.Name);
break;
case MenuType.DeviceMenu:
menuBean.ViewModel = App.Current.Services.GetRequiredService<DeviceDetailViewModel>();
menuBean.Data = devices.FirstOrDefault(d => d.Id == menuBean.DataId);
break;
case MenuType.VariableTableMenu:
var varTableVM = App.Current.Services.GetRequiredService<VariableTableViewModel>();
varTableVM.VariableTable = FindVarTableForDevice(menuBean.DataId);
menuBean.ViewModel = varTableVM;
menuBean.Data = varTableVM.VariableTable;
break;
case MenuType.AddVariableTableMenu:
break;
}
if (menuBean.Items != null && menuBean.Items.Count > 0)
{
FillMenuData(menuBean.Items, devices);
}
}
}
/// <summary>
/// 查找设备所对应的菜单对象
/// </summary>
/// <param name="device"></param>
/// <returns></returns>
public async Task<int> UpdateMenuForDevice(Device device)
{
var menu= DataServicesHelper.FindMenusForDevice(device, MenuTrees);
if (menu != null)
return await _menuRepository.Edit(menu);
return 0;
}
/// <summary>
/// 从设备列表中找到变量表VarTable对象
/// </summary>
/// <param name="vtableId">VarTable的ID</param>
/// <returns>如果找到择返回对象否则返回null</returns>
private VariableTable FindVarTableForDevice(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;
}
/// <summary>
/// 接受加载消息,收到消息后从数据库加载对应的数据
/// </summary>
@@ -131,18 +53,16 @@ public partial class DataServices : ObservableRecipient, IRecipient<LoadMessage>
/// <exception cref="ArgumentException"></exception>
public async void Receive(LoadMessage message)
{
if (!(message.Value is LoadTypes))
throw new ArgumentException($"接受到的加载类型错误:{message.Value}");
try
{
switch ((LoadTypes)message.Value)
switch (message.LoadType)
{
case LoadTypes.All:
Devices = await _deviceRepository.GetAll();
await LoadDevices();
await LoadMenus();
break;
case LoadTypes.Devices:
Devices = await _deviceRepository.GetAll();
await LoadDevices();
break;
case LoadTypes.Menu:
await LoadMenus();
@@ -156,24 +76,18 @@ public partial class DataServices : ObservableRecipient, IRecipient<LoadMessage>
}
}
private async Task LoadDevices()
{
Devices = await _deviceRepository.GetAll();
}
private async Task LoadMenus()
{
MenuTrees = await _menuRepository.GetMenuTrees();
foreach (MenuBean menu in MenuTrees)
{
MenuHelper.MenuAddParent(menu);
DataServicesHelper.SortMenus(menu);
}
}
public async Task<int> DeleteMenuForDevice(Device device)
{
var menu= DataServicesHelper.FindMenusForDevice(device, MenuTrees);
if (menu != null)
{
return await _menuRepository.DeleteMenu(menu);
}
return 0;
}
}

View File

@@ -56,6 +56,21 @@ public class DialogService :IDialogService
return false;
}
public async Task<VariableTable> ShowAddVarTableDialog(Device device)
{
VarTableDialogViewModel vm = new();
vm.Title = "添加变量表";
vm.PrimaryButtonText = "添加变量表";
vm.VariableTable = new VariableTable();
var dialog = new VarTableDialog(vm);
var res = await dialog.ShowAsync();
if (res == ContentDialogResult.Primary)
{
return vm.VariableTable;
}
return null;
}
public void ShowMessageDialog(string title, string message)
{

View File

@@ -8,6 +8,8 @@ public interface IDialogService
Task<Device> ShowEditDeviceDialog(Device device);
Task<bool> ShowConfrimeDialog(string title, string message,string buttonText="确认");
Task<VariableTable> ShowAddVarTableDialog(Device device);
void ShowMessageDialog(string title, string message);
}

View File

@@ -102,9 +102,12 @@ public partial class DevicesViewModel : ViewModelBase
var editDievce = await _dialogService.ShowEditDeviceDialog(SelectedDevice);
if (editDievce != null)
{
{
// 更新菜单
var res = await _deviceRepository.Edit(editDievce);
await _dataServices.UpdateMenuForDevice(editDievce);
var menu = DataServicesHelper.FindMenusForDevice(editDievce, _dataServices.MenuTrees);
if (menu != null)
await _menuRepository.Edit(menu);
MessageHelper.SendLoadMessage(LoadTypes.Menu);
MessageHelper.SendLoadMessage(LoadTypes.Devices);
@@ -132,8 +135,13 @@ public partial class DevicesViewModel : ViewModelBase
var isDel = await _dialogService.ShowConfrimeDialog("删除设备", msg, "删除设备");
if (isDel)
{
var defDeviceRes = await _deviceRepository.DeleteById(SelectedDevice.Id);
var defMenuRes = await _dataServices.DeleteMenuForDevice(SelectedDevice);
// 删除设备
await _deviceRepository.DeleteById(SelectedDevice.Id);
// 删除菜单
var menu = DataServicesHelper.FindMenusForDevice(SelectedDevice, _dataServices.MenuTrees);
if (menu != null)
await _menuRepository.DeleteMenu(menu);
MessageHelper.SendLoadMessage(LoadTypes.Menu);
MessageHelper.SendLoadMessage(LoadTypes.Devices);
NotificationHelper.ShowMessage($"删除设备成功,设备名:{SelectedDevice.Name}", NotificationType.Success);
@@ -141,8 +149,8 @@ public partial class DevicesViewModel : ViewModelBase
}
catch (Exception e)
{
NotificationHelper.ShowMessage($"编辑设备的过程中发生错误:{e.Message}", NotificationType.Error);
_logger.LogError($"编辑设备的过程中发生错误:{e}");
NotificationHelper.ShowMessage($"删除设备的过程中发生错误:{e.Message}", NotificationType.Error);
_logger.LogError($"删除设备的过程中发生错误:{e}");
}
}

View File

@@ -0,0 +1,14 @@
using CommunityToolkit.Mvvm.ComponentModel;
using PMSWPF.Models;
namespace PMSWPF.ViewModels.Dialogs;
public partial class VarTableDialogViewModel:ObservableObject
{
[ObservableProperty]
private VariableTable variableTable;
[ObservableProperty]
private string title;
[ObservableProperty]
private string primaryButtonText;
}

View File

@@ -1,5 +1,9 @@
using System.Collections.ObjectModel;
using CommunityToolkit.Mvvm.ComponentModel;
using iNKORE.UI.WPF.Modern.Common.IconKeys;
using iNKORE.UI.WPF.Modern.Controls;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using PMSWPF.Data.Repositories;
using PMSWPF.Enums;
using PMSWPF.Helper;
@@ -12,35 +16,143 @@ public partial class MainViewModel : ViewModelBase
{
private readonly NavgatorServices _navgatorServices;
private readonly DataServices _dataServices;
private readonly IDialogService _dialogService;
private readonly ILogger<MainViewModel> _logger;
[ObservableProperty] private ViewModelBase currentViewModel;
[ObservableProperty]
private ObservableCollection<MenuBean> _menus;
[ObservableProperty] private ObservableCollection<MenuBean> _menus;
private readonly MenuRepository _menuRepository;
public MainViewModel(NavgatorServices navgatorServices,DataServices dataServices)
public MainViewModel(NavgatorServices navgatorServices, DataServices dataServices, IDialogService dialogService,
ILogger<MainViewModel> logger)
{
_navgatorServices = navgatorServices;
_dataServices = dataServices;
_dialogService = dialogService;
_logger = logger;
_navgatorServices.OnViewModelChanged += () => { CurrentViewModel = _navgatorServices.CurrentViewModel; };
CurrentViewModel = new HomeViewModel();
CurrentViewModel.OnLoaded();
// 发送消息加载数据
MessageHelper.SendLoadMessage(LoadTypes.All);
// 当菜单加载成功后,在前台显示菜单
dataServices.OnMenuTreeListChanged += (menus) =>
{
Menus = new ObservableCollection<MenuBean>(menus);
};
dataServices.OnMenuTreeListChanged += (menus) => { Menus = new ObservableCollection<MenuBean>(menus); };
}
public async Task MenuSelectionChanged(MenuBean menu)
{
try
{
switch (menu.Type)
{
case MenuType.MainMenu:
menu.ViewModel = DataServicesHelper.GetMainViewModel(menu.Name);
break;
case MenuType.DeviceMenu:
menu.ViewModel = App.Current.Services.GetRequiredService<DeviceDetailViewModel>();
menu.Data = _dataServices.Devices.FirstOrDefault(d => d.Id == menu.DataId);
break;
case MenuType.VariableTableMenu:
VariableTableViewModel varTableVM = App.Current.Services.GetRequiredService<VariableTableViewModel>();
varTableVM.VariableTable =
DataServicesHelper.FindVarTableForDevice(_dataServices.Devices, menu.DataId);
menu.ViewModel = varTableVM;
menu.Data = varTableVM.VariableTable;
break;
case MenuType.AddVariableTableMenu:
await AddVariableTable(menu);
break;
}
if (menu.Type==MenuType.AddVariableTableMenu)
return;
if (menu.ViewModel != null)
{
MessageHelper.SendNavgatorMessage(menu.ViewModel);
_logger.LogInformation($"导航到:{menu.Name}");
}
else
{
NotificationHelper.ShowMessage($"菜单:{menu.Name},没有对应的ViewModel.");
_logger.LogInformation($"菜单:{menu.Name},没有对应的ViewModel.");
}
}
catch (Exception e)
{
_logger.LogError($"菜单切换是出现了错误:{e}");
NotificationHelper.ShowMessage($"菜单切换是出现了错误:{e.Message}", NotificationType.Error);
}
}
private async Task AddVariableTable(MenuBean menu)
{
try
{
if (menu.Parent != null && menu.Parent.Data != null)
{
Device device = (Device)menu.Parent.Data;
var varTable = await _dialogService.ShowAddVarTableDialog(device);
if (varTable != null)
{
// 添加变量表
varTable.DeviceId = device.Id;
varTable.ProtocolType = device.ProtocolType;
var addVarTableId = await new VarTableRepository().Add(varTable);
if (addVarTableId > 0)
{
// 添加变量表菜单
MenuBean newMenu = new MenuBean();
newMenu.Icon = SegoeFluentIcons.Tablet.Glyph;
newMenu.Name = varTable.Name;
newMenu.DataId = addVarTableId;
newMenu.Type = MenuType.VariableTableMenu;
newMenu.ParentId = menu.Parent.Id;
var addMenuRes = await new MenuRepository().Add(newMenu);
if (addMenuRes > 0)
{
// 变量表菜单添加成功
MessageHelper.SendLoadMessage(LoadTypes.Menu);
MessageHelper.SendLoadMessage(LoadTypes.Devices);
NotificationHelper.ShowMessage($"变量表:{varTable.Name},添加成功",
NotificationType.Success);
_logger.LogInformation($"变量表:{varTable.Name},添加成功");
}
else
{
// 变量表菜单添加失败
NotificationHelper.ShowMessage($"变量表:{varTable.Name},添加菜单失败",
NotificationType.Error);
_logger.LogError($"变量表:{varTable.Name},添加菜单失败");
}
}
else
{
// 变量表添加失败
NotificationHelper.ShowMessage($"变量表:{varTable.Name},添加失败", NotificationType.Error);
_logger.LogError($"变量表:{varTable.Name},添加失败");
}
}
}
}
catch (Exception e)
{
_logger.LogError($"添加变量表时出现了错误:{e}");
NotificationHelper.ShowMessage($"添加变量表时出现了错误:{e.Message}", NotificationType.Error);
}
}
public override void OnLoaded()
{
}
}

View File

@@ -10,12 +10,12 @@ partial class VariableTableViewModel : ViewModelBase
private VariableTable variableTable;
[ObservableProperty]
private ObservableCollection<DataVariable> _dataVariables;
public override void OnLoaded()
{
if (VariableTable.DataVariables!=null )
{
_dataVariables = new ObservableCollection<DataVariable>(VariableTable.DataVariables);
DataVariables = new ObservableCollection<DataVariable>(VariableTable.DataVariables);
}
}
}

View File

@@ -17,12 +17,6 @@
d:DataContext="{d:DesignInstance vmd:ConfrimDialogViewModel}"
mc:Ignorable="d">
<ui:ContentDialog.Resources>
<ex:EnumBindingSource x:Key="deviceType"
EnumType="{x:Type en:DeviceType}" />
<ex:EnumBindingSource x:Key="protocolType"
EnumType="{x:Type en:ProtocolType}" />
<vc:EnumDescriptionConverter x:Key="EnumDescriptionConverter" />
</ui:ContentDialog.Resources>

View File

@@ -0,0 +1,40 @@
<ui:ContentDialog x:Class="PMSWPF.Views.Dialogs.VarTableDialog"
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:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
xmlns:vmd="clr-namespace:PMSWPF.ViewModels.Dialogs"
xmlns:vc="clr-namespace:PMSWPF.ValueConverts"
xmlns:ex="clr-namespace:PMSWPF.Extensions"
xmlns:en="clr-namespace:PMSWPF.Enums"
Title="{Binding Title}"
CloseButtonText="取消"
DefaultButton="Primary"
PrimaryButtonText="{Binding PrimaryButtonText}"
Background="#fff"
d:DataContext="{d:DesignInstance vmd:VarTableDialogViewModel}"
mc:Ignorable="d">
<ui:ContentDialog.Resources>
</ui:ContentDialog.Resources>
<ikw:SimpleStackPanel Width="300" Grid.Column="0"
Margin="10 10 20 10 "
Spacing="12">
<!-- 设备名称 -->
<TextBlock Text="变量表名称"
HorizontalAlignment="Left"
Style="{StaticResource TextBlockSubTitle}" />
<TextBox Text="{Binding VariableTable.Name, UpdateSourceTrigger=PropertyChanged}" />
<!-- 设备IP地址 -->
<TextBlock Text="变量表描述"
HorizontalAlignment="Left"
Style="{StaticResource TextBlockSubTitle}" />
<TextBox AcceptsReturn="True"
Text="{Binding VariableTable.Description, UpdateSourceTrigger=PropertyChanged}" />
</ikw:SimpleStackPanel>
</ui:ContentDialog>

View File

@@ -0,0 +1,13 @@
using iNKORE.UI.WPF.Modern.Controls;
using PMSWPF.ViewModels.Dialogs;
namespace PMSWPF.Views.Dialogs;
public partial class VarTableDialog : ContentDialog
{
public VarTableDialog(VarTableDialogViewModel viewModel)
{
InitializeComponent();
this.DataContext = viewModel;
}
}

View File

@@ -19,9 +19,17 @@
d:DataContext="{d:DesignInstance vm:MainViewModel}"
mc:Ignorable="d">
<Window.Resources>
<ContextMenu x:Key="MyMenuItemContextMenu">
<MenuItem Header="添加" />
<MenuItem Header="编辑" />
<Separator />
<MenuItem Header="删除" />
</ContextMenu>
<DataTemplate x:Key="NavigationViewMenuItem"
DataType="{x:Type mo:MenuBean}">
<ui:NavigationViewItem Content="{Binding Name}"
<ui:NavigationViewItem
Content="{Binding Name}"
MenuItemsSource="{Binding Items }">
<ui:NavigationViewItem.Icon>
<ui:FontIcon Glyph="{Binding Icon}" />

View File

@@ -1,9 +1,11 @@
using System.Windows;
using iNKORE.UI.WPF.Modern.Controls;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using PMSWPF.Enums;
using PMSWPF.Helper;
using PMSWPF.Models;
using PMSWPF.Services;
using PMSWPF.ViewModels;
namespace PMSWPF.Views;
@@ -13,15 +15,17 @@ namespace PMSWPF.Views;
/// </summary>
public partial class MainView : Window
{
private readonly DataServices _dataServices;
private readonly ILogger<MainView> _logger;
private MainViewModel _viewModel;
public MainView(MainViewModel viewModel, ILogger<MainView> logger)
public MainView(DataServices dataServices, ILogger<MainView> logger)
{
InitializeComponent();
_viewModel = viewModel;
_viewModel = App.Current.Services.GetRequiredService<MainViewModel>();
_dataServices = dataServices;
_logger = logger;
DataContext = viewModel;
DataContext = _viewModel;
_logger.LogInformation("主界面加载成功");
}
@@ -30,32 +34,16 @@ public partial class MainView : Window
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
private void NavigationView_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args)
private async void NavigationView_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args)
{
try
var menu = args.SelectedItem as MenuBean;
if (menu != null)
{
var menu = args.SelectedItem as MenuBean;
if (menu == null)
throw new ArgumentException("选择的菜单项为空!");
switch (menu.Type)
{
case MenuType.MainMenu:
case MenuType.DeviceMenu:
case MenuType.VariableTableMenu:
if (menu.ViewModel == null)
throw new ArgumentException($"菜单项:{menu.Name}没有绑定对象的ViewModel");
MessageHelper.SendNavgatorMessage(menu.ViewModel);
_logger.LogInformation($"导航到:{menu.Name}");
break;
case MenuType.AddVariableTableMenu:
break;
}
await _viewModel.MenuSelectionChanged(menu);
}
catch (Exception e)
else
{
NotificationHelper.ShowMessage(e.Message, NotificationType.Error);
_logger.LogError(e.Message);
NotificationHelper.ShowMessage("选择的菜单项为空!", NotificationType.Error);
}
}
@@ -63,5 +51,4 @@ public partial class MainView : Window
{
_viewModel.OnLoaded();
}
}