修改了CopyTo方法,使用反射可以将列表的内容也可以复制
This commit is contained in:
21
App.xaml.cs
21
App.xaml.cs
@@ -1,4 +1,6 @@
|
|||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using iNKORE.UI.WPF.Modern.Common.IconKeys;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using NLog;
|
using NLog;
|
||||||
@@ -60,11 +62,29 @@ public partial class App : Application
|
|||||||
{
|
{
|
||||||
base.OnStartup(e);
|
base.OnStartup(e);
|
||||||
InitDB();
|
InitDB();
|
||||||
|
// InitMenu();
|
||||||
|
|
||||||
MainWindow = Services.GetRequiredService<MainView>();
|
MainWindow = Services.GetRequiredService<MainView>();
|
||||||
MainWindow.Show();
|
MainWindow.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void InitMenu()
|
||||||
|
{
|
||||||
|
using (var db = DbContext.GetInstance())
|
||||||
|
{
|
||||||
|
List<DbMenu> items = new List<DbMenu>();
|
||||||
|
items.Add(new DbMenu() { Id = 1, Name = "主页", Icon = SegoeFluentIcons.Home.Glyph, ParentId = 0});
|
||||||
|
items.Add(new DbMenu() { Id = 1, Name = "设备", Icon = SegoeFluentIcons.Devices.Glyph, ParentId = 0});
|
||||||
|
items.Add(new DbMenu() { Id = 1, Name = "数据转换", Icon = SegoeFluentIcons.Move.Glyph, ParentId = 0});
|
||||||
|
items.Add(new DbMenu() { Id = 1, Name = "设置", Icon = SegoeFluentIcons.Settings.Glyph, ParentId = 0});
|
||||||
|
items.Add(new DbMenu() { Id = 1, Name = "关于", Icon = SegoeFluentIcons.Info.Glyph, ParentId = 0});
|
||||||
|
db.Insertable<DbMenu>(items).ExecuteCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private void InitDB()
|
private void InitDB()
|
||||||
{
|
{
|
||||||
var _db = DbContext.GetInstance();
|
var _db = DbContext.GetInstance();
|
||||||
@@ -77,5 +97,6 @@ public partial class App : Application
|
|||||||
_db.CodeFirst.InitTables<DbS7DataVariable>();
|
_db.CodeFirst.InitTables<DbS7DataVariable>();
|
||||||
_db.CodeFirst.InitTables<DbUser>();
|
_db.CodeFirst.InitTables<DbUser>();
|
||||||
_db.CodeFirst.InitTables<DbMqtt>();
|
_db.CodeFirst.InitTables<DbMqtt>();
|
||||||
|
_db.CodeFirst.InitTables<DbMenu>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
16
Data/Entities/DbMenu.cs
Normal file
16
Data/Entities/DbMenu.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
using SqlSugar;
|
||||||
|
|
||||||
|
namespace PMSWPF.Data.Entities;
|
||||||
|
|
||||||
|
[SugarTable("Menu")]
|
||||||
|
public class DbMenu
|
||||||
|
{
|
||||||
|
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Icon { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
public int ParentId { get; set; }
|
||||||
|
|
||||||
|
[SugarColumn(IsIgnore = true)]
|
||||||
|
public List<DbMenu> Items { get; set; }
|
||||||
|
}
|
||||||
@@ -3,11 +3,17 @@ using PMSWPF.Excptions;
|
|||||||
using PMSWPF.Extensions;
|
using PMSWPF.Extensions;
|
||||||
using PMSWPF.Helper;
|
using PMSWPF.Helper;
|
||||||
using PMSWPF.Models;
|
using PMSWPF.Models;
|
||||||
|
using SqlSugar;
|
||||||
|
|
||||||
namespace PMSWPF.Data.Repositories;
|
namespace PMSWPF.Data.Repositories;
|
||||||
|
|
||||||
public class DevicesRepositories : BaseRepositories
|
public class DevicesRepositories
|
||||||
{
|
{
|
||||||
|
private SqlSugarClient _db;
|
||||||
|
public DevicesRepositories()
|
||||||
|
{
|
||||||
|
_db = DbContext.GetInstance();
|
||||||
|
}
|
||||||
public async Task<bool> Add(Device device)
|
public async Task<bool> Add(Device device)
|
||||||
{
|
{
|
||||||
var exist = await _db.Queryable<DbDevice>().Where(d => d.Name == device.Name).FirstAsync();
|
var exist = await _db.Queryable<DbDevice>().Where(d => d.Name == device.Name).FirstAsync();
|
||||||
@@ -30,8 +36,7 @@ public class DevicesRepositories : BaseRepositories
|
|||||||
var devices = new List<Device>();
|
var devices = new List<Device>();
|
||||||
foreach (var dbDevice in dlist)
|
foreach (var dbDevice in dlist)
|
||||||
{
|
{
|
||||||
var device = dbDevice.NewTo<Device>();
|
var device = dbDevice.CopyTo<Device>();
|
||||||
device.VariableTables = CovertHelper.ConvertList<DbVariableTable, VariableTable>(dbDevice.VariableTables);
|
|
||||||
devices.Add(device);
|
devices.Add(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
25
Data/Repositories/MenuRepositories.cs
Normal file
25
Data/Repositories/MenuRepositories.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using System.Windows.Controls;
|
||||||
|
using PMSWPF.Data.Entities;
|
||||||
|
using SqlSugar;
|
||||||
|
|
||||||
|
namespace PMSWPF.Data.Repositories;
|
||||||
|
|
||||||
|
public class MenuRepositories
|
||||||
|
{
|
||||||
|
private readonly SqlSugarClient _db;
|
||||||
|
|
||||||
|
public MenuRepositories()
|
||||||
|
{
|
||||||
|
_db=DbContext.GetInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<DbMenu>> GetMenu()
|
||||||
|
{
|
||||||
|
return await _db.Queryable<DbMenu>().ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> AddMenu(DbMenu dbMenu)
|
||||||
|
{
|
||||||
|
return await _db.Insertable<DbMenu>(dbMenu).ExecuteCommandAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,53 +1,161 @@
|
|||||||
namespace PMSWPF.Extensions;
|
using System.Collections;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace PMSWPF.Extensions;
|
||||||
|
|
||||||
public static class ObjectExtensions
|
public static class ObjectExtensions
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 对象转换,将source对象上的所有属性的值,都转换到target对象上
|
/// 复制一个新的对象并返回
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="source"></param>
|
/// <param name="source">源对象</param>
|
||||||
/// <param name="target"></param>
|
/// <typeparam name="T">新的对象类型</typeparam>
|
||||||
/// <typeparam name="T"></typeparam>
|
/// <returns>新的对象</returns>
|
||||||
public static void CopyTo<T>(this object source, T target)
|
public static T CopyTo<T>(this Object source) where T : new()
|
||||||
{
|
{
|
||||||
var sourceType = source.GetType();
|
T t = new T();
|
||||||
var targetType = target.GetType();
|
CopyTo(source, t);
|
||||||
var sourceProperties = sourceType.GetProperties();
|
return t;
|
||||||
foreach (var sourceProperty in sourceProperties)
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将可读写的公共属性值从源对象复制到目标对象。
|
||||||
|
/// 属性名称和类型必须匹配,或者它们是具有匹配元素名称的泛型List类型。
|
||||||
|
/// 对嵌套对象和列表执行深拷贝。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="tsource">源对象。</param>
|
||||||
|
/// <param name="ttarget">目标对象。</param>
|
||||||
|
public static void CopyTo(this object tsource, object ttarget)
|
||||||
|
{
|
||||||
|
// 1. 基本的空值检查,提高健壮性
|
||||||
|
if (tsource == null)
|
||||||
{
|
{
|
||||||
var targetProperty = targetType.GetProperty(sourceProperty.Name);
|
// Console.WriteLine("源对象为空。无法复制。");
|
||||||
if (targetProperty != null && targetProperty.CanWrite && sourceProperty.CanRead &&
|
throw new ArgumentNullException("源对象为空。无法复制。");
|
||||||
targetProperty.PropertyType == sourceProperty.PropertyType)
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ttarget == null)
|
||||||
|
{
|
||||||
|
// Console.WriteLine("目标对象为空。无法复制。");
|
||||||
|
throw new ArgumentNullException("目标对象为空。无法复制。");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type sourceType = tsource.GetType();
|
||||||
|
Type targetType = ttarget.GetType();
|
||||||
|
|
||||||
|
// 2. 缓存源类型的公共实例属性,避免在循环中重复获取
|
||||||
|
PropertyInfo[] sourceProperties = sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance);
|
||||||
|
|
||||||
|
foreach (PropertyInfo sourceProperty in sourceProperties)
|
||||||
|
{
|
||||||
|
// 确保源属性可读
|
||||||
|
if (!sourceProperty.CanRead)
|
||||||
{
|
{
|
||||||
var value = sourceProperty.GetValue(source, null);
|
continue;
|
||||||
targetProperty.SetValue(target, value, null);
|
}
|
||||||
|
|
||||||
|
// 在目标类型中查找对应的属性
|
||||||
|
PropertyInfo targetProperty =
|
||||||
|
targetType.GetProperty(sourceProperty.Name, BindingFlags.Public | BindingFlags.Instance);
|
||||||
|
|
||||||
|
// 确保目标属性存在且可写
|
||||||
|
if (targetProperty != null && targetProperty.CanWrite)
|
||||||
|
{
|
||||||
|
object sourceValue = sourceProperty.GetValue(tsource);
|
||||||
|
|
||||||
|
// 场景 1: 属性类型完全相同
|
||||||
|
if (targetProperty.PropertyType == sourceProperty.PropertyType)
|
||||||
|
{
|
||||||
|
targetProperty.SetValue(ttarget, sourceValue);
|
||||||
|
}
|
||||||
|
// 场景 2: 属性类型不同,但可能是泛型 List<T> 类型
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool isSourceList = sourceProperty.PropertyType.IsGenericType &&
|
||||||
|
sourceProperty.PropertyType.GetGenericTypeDefinition() == typeof(List<>);
|
||||||
|
bool isTargetList = targetProperty.PropertyType.IsGenericType &&
|
||||||
|
targetProperty.PropertyType.GetGenericTypeDefinition() == typeof(List<>);
|
||||||
|
|
||||||
|
if (isSourceList && isTargetList)
|
||||||
|
{
|
||||||
|
// 获取源列表的元素类型
|
||||||
|
Type sourceListItemType = sourceProperty.PropertyType.GetGenericArguments()[0];
|
||||||
|
// 获取目标列表的元素类型
|
||||||
|
Type targetListItemType = targetProperty.PropertyType.GetGenericArguments()[0];
|
||||||
|
|
||||||
|
// 检查列表元素类型名称是否匹配(用于潜在的深拷贝)
|
||||||
|
if (sourceProperty.Name == targetProperty.Name)
|
||||||
|
{
|
||||||
|
// 如果源列表为空,则将目标属性设置为 null
|
||||||
|
if (sourceValue == null)
|
||||||
|
{
|
||||||
|
targetProperty.SetValue(ttarget, null);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将源值强制转换为 IEnumerable 以便遍历
|
||||||
|
var sourceList = (IEnumerable)sourceValue;
|
||||||
|
|
||||||
|
// 创建一个目标泛型列表的新实例
|
||||||
|
// 假设 CreateGenericList 助手方法可用,或按注释创建
|
||||||
|
// var targetList = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(targetListItemType));
|
||||||
|
IList targetList = CreateGenericList(targetListItemType);
|
||||||
|
|
||||||
|
foreach (var item in sourceList)
|
||||||
|
{
|
||||||
|
// 确保列表项不为空,然后尝试深拷贝
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
// 如果源列表项为 null,则直接添加到目标列表
|
||||||
|
targetList.Add(null);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建目标列表元素类型的一个实例
|
||||||
|
var targetDataItem = Activator.CreateInstance(targetListItemType);
|
||||||
|
|
||||||
|
// 递归调用 CopyTo,对嵌套对象进行深拷贝
|
||||||
|
CopyTo(item, targetDataItem);
|
||||||
|
|
||||||
|
// 将复制后的项添加到目标列表
|
||||||
|
targetList.Add(targetDataItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将填充好的目标列表设置给目标对象的属性
|
||||||
|
targetProperty.SetValue(ttarget, targetList);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 列表类型匹配,但元素类型名称不匹配。此处跳过,或可实现更复杂的转换。
|
||||||
|
Console.WriteLine(
|
||||||
|
$"由于列表元素类型不匹配,跳过属性 '{sourceProperty.Name}':源 '{sourceListItemType.Name}',目标 '{targetListItemType.Name}'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 类型不同,且都不是泛型 List<T>。此处跳过,或可实现类型转换。
|
||||||
|
Console.WriteLine(
|
||||||
|
$"由于类型不匹配,跳过属性 '{sourceProperty.Name}':源 '{sourceProperty.PropertyType.Name}',目标 '{targetProperty.PropertyType.Name}'");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建一个泛型对象,将source对象上的所有属性的值,都转换到新创建对象上
|
/// 辅助方法,用于动态创建泛型 List<T>。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="source"></param>
|
/// <param name="itemType">列表应包含的元素类型。</param>
|
||||||
/// <param name="target"></param>
|
/// <returns>List<itemType> 的 IList 实例。</returns>
|
||||||
/// <typeparam name="T"></typeparam>
|
private static IList CreateGenericList(Type itemType)
|
||||||
public static T NewTo<T>(this object source) where T : new()
|
|
||||||
{
|
{
|
||||||
var target = new T();
|
Type listType = typeof(List<>).MakeGenericType(itemType);
|
||||||
var sourceType = source.GetType();
|
return (IList)Activator.CreateInstance(listType);
|
||||||
var targetType = target.GetType();
|
|
||||||
var sourceProperties = sourceType.GetProperties();
|
|
||||||
foreach (var sourceProperty in sourceProperties)
|
|
||||||
{
|
|
||||||
var targetProperty = targetType.GetProperty(sourceProperty.Name);
|
|
||||||
if (targetProperty != null && targetProperty.CanWrite && sourceProperty.CanRead &&
|
|
||||||
targetProperty.PropertyType == sourceProperty.PropertyType)
|
|
||||||
{
|
|
||||||
var value = sourceProperty.GetValue(source, null);
|
|
||||||
targetProperty.SetValue(target, value, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return target;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -25,5 +25,8 @@
|
|||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Remove="Data\Repositories\BaseRepositories.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -23,6 +23,6 @@ public partial class DeviceDialogViewModel : ObservableObject
|
|||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
public void AddDevice()
|
public void AddDevice()
|
||||||
{
|
{
|
||||||
device.CopyTo<Device>(_saveDevice);
|
device.CopyTo(_saveDevice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using PMSWPF.Data.Entities;
|
||||||
|
using PMSWPF.Data.Repositories;
|
||||||
using PMSWPF.Services;
|
using PMSWPF.Services;
|
||||||
|
|
||||||
namespace PMSWPF.ViewModels;
|
namespace PMSWPF.ViewModels;
|
||||||
@@ -8,16 +11,22 @@ public partial class MainViewModel : ViewModelBase
|
|||||||
private readonly NavgatorServices _navgatorServices;
|
private readonly NavgatorServices _navgatorServices;
|
||||||
|
|
||||||
[ObservableProperty] private ViewModelBase currentViewModel;
|
[ObservableProperty] private ViewModelBase currentViewModel;
|
||||||
|
[ObservableProperty]
|
||||||
|
private ObservableCollection<DbMenu> _menus;
|
||||||
|
|
||||||
public MainViewModel(NavgatorServices navgatorServices)
|
public MainViewModel(NavgatorServices navgatorServices)
|
||||||
{
|
{
|
||||||
_navgatorServices = navgatorServices;
|
_navgatorServices = navgatorServices;
|
||||||
_navgatorServices.OnViewModelChanged += () => { CurrentViewModel = _navgatorServices.CurrentViewModel; };
|
_navgatorServices.OnViewModelChanged += () => { CurrentViewModel = _navgatorServices.CurrentViewModel; };
|
||||||
CurrentViewModel = new HomeViewModel();
|
CurrentViewModel = new HomeViewModel();
|
||||||
|
CurrentViewModel.OnLoaded();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override void OnLoaded()
|
public override async void OnLoaded()
|
||||||
{
|
{
|
||||||
|
MenuRepositories mr = new MenuRepositories();
|
||||||
|
var menuList= await mr.GetMenu();
|
||||||
|
Menus=new ObservableCollection<DbMenu>(menuList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user