diff --git a/Test.Console/Program.cs b/Test.Console/Program.cs new file mode 100644 index 0000000000000000000000000000000000000000..bc3aaac80fda354f0a88c4bf78df851b94144d49 --- /dev/null +++ b/Test.Console/Program.cs @@ -0,0 +1,555 @@ + + +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.Serialization; +using Vampirewal.Core.EventBus; +using Vampirewal.Core.Mapper; +using Vampirewal.Coree.ClassObjectPool; +using Yitter.IdGenerator; + +namespace Test.Console; + + +public class Program +{ + static void Main(string[] args) + { + //VampirewalCoreEventBusManager.GetInstance().RegisterAll(); + + //VampirewalCoreEventBusManager.GetInstance().Publish("testMethod"); + //VampirewalCoreEventBusManager.GetInstance().Publish("testMethod2",new TestEventObject()); + + //string fileName = Path.GetFileName("D:\\聚爱团项目\\BlindDate\\BlindDate\\BlindDate\\bin\\Debug\\net5.0-windows\\Temp\\测试1_202211161554083981.jpg"); + + //System.Console.WriteLine($"fileName:{fileName}"); + + + + System.Console.ReadKey(); + } + + private static Pool assetBundleItemPool ; + + /// + /// 获取方法执行时间 + /// + /// + /// + public static string GetMethodExcuteTime(Action action) + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + action.Invoke(); + sw.Stop(); + + return sw.ElapsedMilliseconds.ToString(); + } + + + +} + +public class testclass : IVampirewalMapper +{ + + + public Type MapperTargetType() + { + return typeof(testclassDTO); + } + + public virtual long Id { get; set; } + /// + /// 会员姓名 + /// + public virtual string MemberName { get; set; } + + /// + /// 会员生日 + /// + public virtual DateTime Birthday { get; set; } + + /// + /// 性别 + /// + public virtual int Gender { get; set; } + + /// + /// 身高 + /// + public virtual string Height { get; set; } + + /// + /// 体重 + /// + public virtual string Weight { get; set; } + + /// + /// 星座 + /// + public virtual int Constellation { get; set; } + + /// + /// 籍贯 + /// + public virtual string OldPosition { get; set; } + + /// + /// 当前工作或生活地区 + /// + public virtual string NewPosition { get; set; } + + /// + /// 学历 + /// + public virtual int Study { get; set; } + + /// + /// 职业职位 + /// + public virtual string Professional { get; set; } + + /// + /// 年收入 + /// + public virtual int YearMoney { get; set; } + + /// + /// 婚姻状态 + /// + public virtual int MarryState { get; set; } + + /// + /// 车房情况 + /// + public virtual int CarHouse { get; set; } + + /// + /// 兴趣爱好 + /// + public virtual string Interests { get; set; } + + /// + /// 补充说明 + /// + public virtual string Supplement { get; set; } + + /// + /// 婚姻计划 + /// + public virtual string MarryPlan { get; set; } + + /// + /// 手机号码 + /// + public virtual string PhoneNum { get; set; } +} + +public class testclassDTO +{ + public virtual long Id { get; set; } + /// + /// 会员姓名 + /// + public virtual string MemberName { get; set; } + + /// + /// 会员生日 + /// + public virtual DateTime Birthday { get; set; } + + /// + /// 性别 + /// + public virtual int Gender { get; set; } + + /// + /// 身高 + /// + public virtual string Height { get; set; } + + /// + /// 体重 + /// + public virtual string Weight { get; set; } + + /// + /// 星座 + /// + public virtual int Constellation { get; set; } + + /// + /// 籍贯 + /// + public virtual string OldPosition { get; set; } + + /// + /// 当前工作或生活地区 + /// + public virtual string NewPosition { get; set; } + + /// + /// 学历 + /// + public virtual int Study { get; set; } + + /// + /// 职业职位 + /// + public virtual string Professional { get; set; } + + /// + /// 年收入 + /// + public virtual int YearMoney { get; set; } + + /// + /// 婚姻状态 + /// + public virtual int MarryState { get; set; } + + /// + /// 车房情况 + /// + public virtual int CarHouse { get; set; } + + /// + /// 兴趣爱好 + /// + public virtual string Interests { get; set; } + + /// + /// 补充说明 + /// + public virtual string Supplement { get; set; } + + /// + /// 婚姻计划 + /// + public virtual string MarryPlan { get; set; } + + /// + /// 手机号码 + /// + public virtual string PhoneNum { get; set; } +} + +/// +/// 简单Id生成器 +/// +public class IdentityGenerator +{ + /// + /// 随机数缓存 + /// + private static Hashtable ht; + /// + /// 时间戳刻度缓存 + /// + private long lastTimeStampStyleTicks; + /// + /// 时间戳缓存(上一次计算ID的系统时间按时间戳刻度取值) + /// + private long lastEndDateTimeTicks; + + public IdentityGenerator() + { + if (ht == null) + ht = new Hashtable(); + } + + /// + /// IdentityGenerator的静态实例 + /// + private static IdentityGenerator ig; + public IdentityGenerator GetInstance() + { + if (ig == null) + ig = new IdentityGenerator(); + return ig; + } + + /// + /// 按照时间戳刻度计算当前时间戳 + /// + /// 起始时间 + /// 时间戳刻度值 + /// long + private long GetTimestamp(DateTime startDateTime, long timestampStyleTicks) + { + if (timestampStyleTicks == 0) + throw new Exception("时间戳刻度样式精度值不符,不能为0或负数"); + DateTime endDateTime = DateTime.Now; + long ticks = (endDateTime.Ticks - startDateTime.Ticks) / timestampStyleTicks; + return ticks; + } + + /// + /// 静态随机数生成器 + /// + private static Random random; + /// + /// 获取随机数 + /// + /// 随机数长度 + /// + private long GetRandom(int length) + { + if (length <= 0) + throw new Exception("随机数长度指派错误,长度不能为0或负数"); + if (random == null) + random = new Random(); + + int minValue = 0; + int maxValue = int.Parse(System.Math.Pow(10, length).ToString()); + long result = long.Parse(random.Next(minValue, maxValue).ToString()); + return result; + } + + /// + /// 计算一个Id + /// 以2005-1-1 00:00 000为起始时间刻度 + /// + /// long + public long GetIdentity() + { + DateTime startDateTime = new DateTime(2005, 1, 1, 0, 0, 0, 0); + TimestampStyle timestampStyle = TimestampStyle.SecondTicks; + int randomLength = 3; + return GetIdentity(startDateTime, timestampStyle, randomLength); + } + + /// + /// 计算一个Id + /// 以2005-1-1 00:00 000为起始时间刻度 + /// + /// 时间戳刻度 + /// long + public long GetIdentity(TimestampStyle timestampStyle) + { + DateTime startDateTime = new DateTime(2005, 1, 1, 0, 0, 0, 0); + int randomLength = 3; + return GetIdentity(startDateTime, timestampStyle, randomLength); + } + + /// + /// 计算一个Id + /// + /// 随机数长度 + /// long + public long GetIdentity(int randomLength) + { + DateTime startDateTime = new DateTime(2005, 1, 1, 0, 0, 0, 0); + TimestampStyle timestampStyle = TimestampStyle.SecondTicks; + return GetIdentity(startDateTime, timestampStyle, randomLength); + } + + /// + /// 计算一个Id + /// + /// 时间戳刻度 + /// 随机数长度 + /// long + public long GetIdentity(TimestampStyle timestampStyle, int randomLength) + { + DateTime startDateTime = new DateTime(2005, 1, 1, 0, 0, 0, 0); + return GetIdentity(startDateTime, timestampStyle, randomLength); + } + + /// + /// 计算一个Id + /// + /// 时间戳的起始时间 + /// 时间戳刻度 + /// 随机数长度 + /// long + public long GetIdentity(DateTime startDateTime, TimestampStyle timestampStyle, int randomLength) + { + long timestampStyleTicks = long.Parse(timestampStyle.ToString("D")); + return GetIdentity(startDateTime, timestampStyleTicks, randomLength); + } + + /// + /// 计算一个Id + /// + /// 时间戳的起始时间 + /// 时间戳刻度(毫微秒单位) + /// 随机数长度 + /// long + public long GetIdentity(DateTime startDateTime, long timestampStyleTicks, int randomLength) + { + // 新一轮时间戳刻度更新后更新缓存 + //如果该参数不变则不进行此更新 + if (timestampStyleTicks != lastTimeStampStyleTicks) + ht.Clear(); + + //取得时间戳(当前时间按刻度取值) + long timestamp = GetTimestamp(startDateTime, timestampStyleTicks); + + //新一轮时间戳更新后更新缓存 + if (timestamp != lastEndDateTimeTicks) + ht.Clear(); + //幂 + long power = long.Parse(Math.Pow(10, randomLength).ToString()); + //随机数 + long rand = GetRandom(randomLength); + //生成结果(Id) + long result = timestamp * power + rand; + + //如果发现重复 + if (ht.ContainsKey(result)) + { + //在随机数长度范围内再重复查找一次 + for (int i = 0; i < power; i++) + { + rand = GetRandom(randomLength); + result = timestamp * power + rand; + //发现非重复的Id + if (!ht.ContainsKey(result)) + { + //将新的Id加入HashTable缓存 + ht.Add(result, result); + break;//找到一个同一时间戳内的Id即退出 + } + } + // 此处运行在当前时间戳内无法再继续生成Id的代码,如: + // + //throw new Exception("已无法生成更多Id,请增加时间戳刻度TimestampStyle或增加随机数长度randomLength"); + } + else + { + //将新的Id加入HashTable缓存 + ht.Add(result, result); + } + //记录当前一轮时间戳(当前时间按刻度取值) + this.lastEndDateTimeTicks = timestamp; + //记录当前一轮时间戳刻度 + this.lastTimeStampStyleTicks = timestampStyleTicks; + return result; + } +} + +/// +/// 时间戳精度样式
+/// 采用格里高利时间刻度单位-毫微秒(1秒 =10,000,000毫微秒 ) +/// 疑问:MSDN上写的一毫微秒为一百万分之一秒 =100,000,000毫微秒,但是我始终无法算出该值, +/// 不知是我错了还是MSDN的问题实际得出的数字是1秒 =10,000,000毫微秒,认为是我错了的话请将 +/// 下面的每一项枚举值都加一个0即可 +///
+public enum TimestampStyle : long +{ + /// + /// 时间刻度精度取为1毫秒(此项无意义,因为一般PC机系统时钟只能精确到10毫秒) + /// + MillSecondTicks = 10000, + /// + /// 时间刻度精度取为10毫秒,这是一般PC机系统时钟的最小精度单位 + /// + TenMillSecondTicks = 100000, + /// + /// 时间刻度精度取为100毫秒 + /// + HundredMillSecondTicks = 1000000, + /// + /// 时间刻度精度取为1秒,即1000毫秒 + /// + SecondTicks = 10000000, + /// + /// 时间刻度精度取为5秒 + /// + FiveSecondTicks = 50000000, + /// + /// 时间刻度精度取为10秒 + /// + TenSecondTicks = 100000000, + /// + /// 时间刻度精度取为1分种(60秒) + /// + MinutesTicks = 600000000 +} + + + + + +public class TestFactory : IVampirewalCoreEventFactory +{ + public string FactoryName => "TestFactory"; + + public void EventFactoryComplate(EventFactoryContext context) + { + + } + + [SubscribeEvent("testMethod")] + public void TestMethod(EventContext context) + { + System.Console.WriteLine($"执行了方法11111TestMethod,时间:{DateTime.Now}"); + } + + [SubscribeEvent("testMethod")] + public void TestMethod2(EventContext context) + { + System.Console.WriteLine($"执行了方法11111TestMethod2,时间:{DateTime.Now}"); + } +} + +public class TestFactory2 : IVampirewalCoreEventFactory +{ + public string FactoryName => "TestFactory2"; + + public void EventFactoryComplate(EventFactoryContext context) + { + + } + + [SubscribeEvent("testMethod")] + public void TestMethod(EventContext context) + { + var model = context.PassData as TestEventObject; + + if (model == null) + { + System.Console.WriteLine($"执行了方法22222TestMethod,时间:{DateTime.Now},响应内容:model为null"); + } + else + { + System.Console.WriteLine($"执行了方法22222TestMethod,时间:{DateTime.Now},响应内容:{model.Name}"); + } + + + } + + [SubscribeEvent("testMethod2")] + public void TestMethod2(EventContext context) + { + var model = context.PassData as TestEventObject; + System.Console.WriteLine($"执行了方法22222TestMethod2,时间:{DateTime.Now},响应内容:{model.Name}"); + } +} + + +public class TestEventObject +{ + /// + /// + /// + /// + public TestEventObject(Type aa) + { + + } + public string Name { get; set; } = "haha"; +} + +public class TestEventObject2 +{ + public string Name { get; set; } = "haha222"; +} \ No newline at end of file diff --git a/Test.Console/Test.Console.csproj b/Test.Console/Test.Console.csproj new file mode 100644 index 0000000000000000000000000000000000000000..23cd747beff6796ca9ca708e093aafce9ba5fbe5 --- /dev/null +++ b/Test.Console/Test.Console.csproj @@ -0,0 +1,21 @@ + + + + Exe + net6.0 + true + + + + + + + + + + + + + + + diff --git a/Vampirewal.Core.ComputerInfo/DateTimeUtil.cs b/Vampirewal.Core.ComputerInfo/DateTimeUtil.cs new file mode 100644 index 0000000000000000000000000000000000000000..3574971f7b3fb8b09953ef722387e7cfa7126bcc --- /dev/null +++ b/Vampirewal.Core.ComputerInfo/DateTimeUtil.cs @@ -0,0 +1,200 @@ +#region [ 文件信息 ] + +/*---------------------------------------------------------------- + * CLR版本:4.0.30319.42000 + * 机器名称:VAMPIREWAL + * 公司名称:Organization + * 命名空间:Vampirewal.Core.ComputerInfo + * 唯一标识:9b5fab1a-cae8-4b24-a335-18b07639f244 + * 文件名:DateTimeUtil + * 当前用户域:VAMPIREWAL + * + * 创建者:Administrator + * 电子邮箱:1425271996@qq.com + * 创建时间:2023/3/1 18:04:29 + * 版本:V1.0.0 + * 描述: + * + * ---------------------------------------------------------------- + * 修改人: + * 时间: + * 修改说明: + * + * 版本:V1.0.1 + *----------------------------------------------------------------*/ + +#endregion [ 文件信息 ] + +namespace Vampirewal.Core.ComputerInfo +{ + /// + /// + /// + public class DateTimeUtil + { + /// + /// 获取开始时间 + /// + /// + /// + /// + public static DateTime GetBeginTime(DateTime? dateTime, int days = 0) + { + if (dateTime == DateTime.MinValue || dateTime == null) + return DateTime.Now.AddDays(days); + + return dateTime ?? DateTime.Now; + } + + /// + /// 时间戳转本地时间-时间戳精确到秒 + /// + public static DateTime ToLocalTimeDateBySeconds(long unix) + { + return DateTimeOffset.FromUnixTimeSeconds(unix).ToLocalTime().DateTime; + } + + /// + /// 时间转时间戳Unix-时间戳精确到秒 + /// + public static long ToUnixTimestampBySeconds(DateTime dt) + { + return new DateTimeOffset(dt).ToUnixTimeSeconds(); + } + + /// + /// 时间戳转本地时间-时间戳精确到毫秒 + /// + public static DateTime ToLocalTimeDateByMilliseconds(long unix) + { + return DateTimeOffset.FromUnixTimeMilliseconds(unix).ToLocalTime().DateTime; + } + + /// + /// 时间转时间戳Unix-时间戳精确到毫秒 + /// + public static long ToUnixTimestampByMilliseconds(DateTime dt) + { + return new DateTimeOffset(dt).ToUnixTimeMilliseconds(); + } + + /// + /// 毫秒转天时分秒 + /// + /// + /// + public static string FormatTime(long ms) + { + int ss = 1000; + int mi = ss * 60; + int hh = mi * 60; + int dd = hh * 24; + + long day = ms / dd; + long hour = (ms - day * dd) / hh; + long minute = (ms - day * dd - hour * hh) / mi; + long second = (ms - day * dd - hour * hh - minute * mi) / ss; + long milliSecond = ms - day * dd - hour * hh - minute * mi - second * ss; + + string sDay = day < 10 ? "0" + day : "" + day; //天 + string sHour = hour < 10 ? "0" + hour : "" + hour;//小时 + string sMinute = minute < 10 ? "0" + minute : "" + minute;//分钟 + string sSecond = second < 10 ? "0" + second : "" + second;//秒 + string sMilliSecond = milliSecond < 10 ? "0" + milliSecond : "" + milliSecond;//毫秒 + sMilliSecond = milliSecond < 100 ? "0" + sMilliSecond : "" + sMilliSecond; + + return string.Format("{0} 天 {1} 小时 {2} 分 {3} 秒", sDay, sHour, sMinute, sSecond); + } + + /// + /// 获取unix时间戳 + /// + /// + /// + public static long GetUnixTimeStamp(DateTime dt) + { + return ((DateTimeOffset)dt).ToUnixTimeMilliseconds(); + } + + /// + /// 获取日期天的最小时间 + /// + /// + /// + public static DateTime GetDayMinDate(DateTime dt) + { + return new DateTime(dt.Year, dt.Month, dt.Day, 0, 0, 0); + } + + /// + /// 获取日期天的最大时间 + /// + /// + /// + + public static DateTime GetDayMaxDate(DateTime dt) + { + return new DateTime(dt.Year, dt.Month, dt.Day, 23, 59, 59); + } + + /// + /// 获取日期天的最大时间 + /// + /// + /// + public static string FormatDateTime(DateTime? dt) + { + if (dt == null) return string.Empty; + + if (dt.Value.Year == DateTime.Now.Year) + return dt.Value.ToString("MM-dd HH:mm"); + else + return dt.Value.ToString("yyyy-MM-dd HH:mm"); + } + + /// + /// 获取今天日期范围00:00:00 - 23:59:59 + /// + /// + public static List GetTodayTimeList(DateTime time) + { + return new List + { + Convert.ToDateTime(time.ToString("D").ToString()), + Convert.ToDateTime(time.AddDays(1).ToString("D").ToString()).AddSeconds(-1) + }; + } + + /// + /// 获取星期几 + /// + /// + /// + public static string GetWeekByDate(DateTime dt) + { + var day = new[] { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" }; + return day[Convert.ToInt32(dt.DayOfWeek.ToString("d"))]; + } + + /// + /// 获取这个月的第几周 + /// + /// + /// + public static int GetWeekNumInMonth(DateTime daytime) + { + int dayInMonth = daytime.Day; + // 本月第一天 + DateTime firstDay = daytime.AddDays(1 - daytime.Day); + // 本月第一天是周几 + int weekday = (int)firstDay.DayOfWeek == 0 ? 7 : (int)firstDay.DayOfWeek; + // 本月第一周有几天 + int firstWeekEndDay = 7 - (weekday - 1); + // 当前日期和第一周之差 + int diffday = dayInMonth - firstWeekEndDay; + diffday = diffday > 0 ? diffday : 1; + // 当前是第几周,若整除7就减一天 + return ((diffday % 7) == 0 ? (diffday / 7 - 1) : (diffday / 7)) + 1 + (dayInMonth > firstWeekEndDay ? 1 : 0); + } + } +} \ No newline at end of file diff --git a/Vampirewal.Core.ComputerInfo/MemoryMetricsClient.cs b/Vampirewal.Core.ComputerInfo/MemoryMetricsClient.cs new file mode 100644 index 0000000000000000000000000000000000000000..21f4cc9fd9a84a7712782b353ba005999820e3f0 --- /dev/null +++ b/Vampirewal.Core.ComputerInfo/MemoryMetricsClient.cs @@ -0,0 +1,79 @@ +#region [ 文件信息 ] + +/*---------------------------------------------------------------- + * CLR版本:4.0.30319.42000 + * 机器名称:VAMPIREWAL + * 公司名称:Organization + * 命名空间:Vampirewal.Core.ComputerInfo + * 唯一标识:e5444041-405e-4cd5-9c9d-f151e77a67f6 + * 文件名:MemoryMetricsClient + * 当前用户域:VAMPIREWAL + * + * 创建者:Administrator + * 电子邮箱:1425271996@qq.com + * 创建时间:2023/3/1 18:39:40 + * 版本:V1.0.0 + * 描述: + * + * ---------------------------------------------------------------- + * 修改人: + * 时间: + * 修改说明: + * + * 版本:V1.0.1 + *----------------------------------------------------------------*/ + +#endregion [ 文件信息 ] + +namespace Vampirewal.Core.ComputerInfo; + +/// +/// +/// +public class MemoryMetricsClient +{ + /// + /// windows系统获取内存信息 + /// + /// + public MemoryMetrics GetWindowsMetrics() + { + string output = ShellUtil.Cmd("wmic", "OS get FreePhysicalMemory,TotalVisibleMemorySize /Value"); + var metrics = new MemoryMetrics(); + var lines = output.Trim().Split('\n', (char)StringSplitOptions.RemoveEmptyEntries); + if (lines.Length <= 0) return metrics; + + var freeMemoryParts = lines[0].Split('=', (char)StringSplitOptions.RemoveEmptyEntries); + var totalMemoryParts = lines[1].Split('=', (char)StringSplitOptions.RemoveEmptyEntries); + + metrics.Total = Math.Round(double.Parse(totalMemoryParts[1]) / 1024, 0); + metrics.Free = Math.Round(double.Parse(freeMemoryParts[1]) / 1024, 0);//m + metrics.Used = metrics.Total - metrics.Free; + + return metrics; + } + + /// + /// Unix系统获取 + /// + /// + public MemoryMetrics GetUnixMetrics() + { + string output = ShellUtil.Bash("free -m | awk '{print $2,$3,$4,$5,$6}'"); + var metrics = new MemoryMetrics(); + var lines = output.Split('\n', (char)StringSplitOptions.RemoveEmptyEntries); + if (lines.Length <= 0) return metrics; + + if (lines != null && lines.Length > 0) + { + var memory = lines[1].Split(' ', (char)StringSplitOptions.RemoveEmptyEntries); + if (memory.Length >= 3) + { + metrics.Total = double.Parse(memory[0]); + metrics.Used = double.Parse(memory[1]); + metrics.Free = double.Parse(memory[2]);//m + } + } + return metrics; + } +} \ No newline at end of file diff --git a/Vampirewal.Core.ComputerInfo/Models/DiskInfo.cs b/Vampirewal.Core.ComputerInfo/Models/DiskInfo.cs new file mode 100644 index 0000000000000000000000000000000000000000..6e5304bca82ce2faa07befea022e3edf788348ed --- /dev/null +++ b/Vampirewal.Core.ComputerInfo/Models/DiskInfo.cs @@ -0,0 +1,73 @@ +#region [ 文件信息 ] +/*---------------------------------------------------------------- + * CLR版本:4.0.30319.42000 + * 机器名称:VAMPIREWAL + * 公司名称:Organization + * 命名空间:Vampirewal.Core.ComputerInfo.Models + * 唯一标识:b6147c38-e5f7-4ef1-b474-7b8177267cdb + * 文件名:DiskInfo + * 当前用户域:VAMPIREWAL + * + * 创建者:Administrator + * 电子邮箱:1425271996@qq.com + * 创建时间:2023/3/1 18:40:18 + * 版本:V1.0.0 + * 描述: + * + * ---------------------------------------------------------------- + * 修改人: + * 时间: + * 修改说明: + * + * 版本:V1.0.1 + *----------------------------------------------------------------*/ +#endregion [ 文件信息 ] + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Vampirewal.Core.ComputerInfo; + +/// +/// 磁盘信息 +/// +public class DiskInfo +{ + /// + /// 磁盘名 + /// + public string DiskName { get; set; } + + /// + /// 类型名 + /// + public string TypeName { get; set; } + + /// + /// 总剩余 + /// + public long TotalFree { get; set; } + + /// + /// 总量 + /// + public long TotalSize { get; set; } + + /// + /// 已使用 + /// + public long Used { get; set; } + + /// + /// 可使用 + /// + public long AvailableFreeSpace { get; set; } + + /// + /// 使用百分比 + /// + public decimal AvailablePercent { get; set; } +} diff --git a/Vampirewal.Core.ComputerInfo/Models/MemoryMetrics.cs b/Vampirewal.Core.ComputerInfo/Models/MemoryMetrics.cs new file mode 100644 index 0000000000000000000000000000000000000000..978399b1e6b3544031551ed8f4abf5820374e0ec --- /dev/null +++ b/Vampirewal.Core.ComputerInfo/Models/MemoryMetrics.cs @@ -0,0 +1,73 @@ +#region [ 文件信息 ] +/*---------------------------------------------------------------- + * CLR版本:4.0.30319.42000 + * 机器名称:VAMPIREWAL + * 公司名称:Organization + * 命名空间:Vampirewal.Core.ComputerInfo.Models + * 唯一标识:fc0e4af6-9e16-4cd3-b80e-c5e95799f03d + * 文件名:MemoryMetrics + * 当前用户域:VAMPIREWAL + * + * 创建者:Administrator + * 电子邮箱:1425271996@qq.com + * 创建时间:2023/3/1 18:40:59 + * 版本:V1.0.0 + * 描述: + * + * ---------------------------------------------------------------- + * 修改人: + * 时间: + * 修改说明: + * + * 版本:V1.0.1 + *----------------------------------------------------------------*/ +#endregion [ 文件信息 ] + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +namespace Vampirewal.Core.ComputerInfo; + +/// +/// 内存信息 +/// +public class MemoryMetrics +{ + [JsonIgnore] + public double Total { get; set; } + + [JsonIgnore] + public double Used { get; set; } + + [JsonIgnore] + public double Free { get; set; } + + /// + /// 已用内存 + /// + public string UsedRam { get; set; } + + /// + /// CPU使用率% + /// + public string CpuRate { get; set; } + + /// + /// 总内存 GB + /// + public string TotalRam { get; set; } + + /// + /// 内存使用率 % + /// + public string RamRate { get; set; } + + /// + /// 空闲内存 + /// + public string FreeRam { get; set; } +} diff --git a/Vampirewal.Core.ComputerInfo/ObjectExtension.cs b/Vampirewal.Core.ComputerInfo/ObjectExtension.cs new file mode 100644 index 0000000000000000000000000000000000000000..5c848be892b416d592e1fb9ce4768854622893a8 --- /dev/null +++ b/Vampirewal.Core.ComputerInfo/ObjectExtension.cs @@ -0,0 +1,119 @@ +#region [ 文件信息 ] + +/*---------------------------------------------------------------- + * CLR版本:4.0.30319.42000 + * 机器名称:VAMPIREWAL + * 公司名称:Organization + * 命名空间:Vampirewal.Core.ComputerInfo + * 唯一标识:26837712-d30d-4867-a07b-abf67c21293d + * 文件名:ObjectExtension + * 当前用户域:VAMPIREWAL + * + * 创建者:Administrator + * 电子邮箱:1425271996@qq.com + * 创建时间:2023/3/1 18:05:57 + * 版本:V1.0.0 + * 描述: + * + * ---------------------------------------------------------------- + * 修改人: + * 时间: + * 修改说明: + * + * 版本:V1.0.1 + *----------------------------------------------------------------*/ + +#endregion [ 文件信息 ] + +namespace Vampirewal.Core.ComputerInfo; + +/// +/// +/// +public static class ObjectExtension +{ + /// + /// 将object转换为long,若失败则返回0 + /// + /// + /// + public static long ParseToLong(this object obj) + { + try + { + return long.Parse(obj.ToString()); + } + catch + { + return 0L; + } + } + + /// + /// 将object转换为double,若失败则返回0 + /// + /// + /// + public static double ParseToDouble(this object obj) + { + try + { + return double.Parse(obj.ToString()); + } + catch + { + return 0; + } + } + + /// + /// 将string转换为DateTime,若失败则返回日期最小值 + /// + /// + /// + public static DateTime ParseToDateTime(this string str) + { + try + { + if (string.IsNullOrWhiteSpace(str)) + { + return DateTime.MinValue; + } + if (str.Contains('-') || str.Contains('/')) + { + return DateTime.Parse(str); + } + else + { + int length = str.Length; + switch (length) + { + case 4: + return DateTime.ParseExact(str, "yyyy", System.Globalization.CultureInfo.CurrentCulture); + + case 6: + return DateTime.ParseExact(str, "yyyyMM", System.Globalization.CultureInfo.CurrentCulture); + + case 8: + return DateTime.ParseExact(str, "yyyyMMdd", System.Globalization.CultureInfo.CurrentCulture); + + case 10: + return DateTime.ParseExact(str, "yyyyMMddHH", System.Globalization.CultureInfo.CurrentCulture); + + case 12: + return DateTime.ParseExact(str, "yyyyMMddHHmm", System.Globalization.CultureInfo.CurrentCulture); + + case 14: + return DateTime.ParseExact(str, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture); + + default: + return DateTime.ParseExact(str, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture); + } + } + } + catch + { + return DateTime.MinValue; + } + } +} \ No newline at end of file diff --git a/Vampirewal.Core.ComputerInfo/ShellUtil.cs b/Vampirewal.Core.ComputerInfo/ShellUtil.cs new file mode 100644 index 0000000000000000000000000000000000000000..92dcd751f8d5aac63fb2e4f8d6f241af9d691194 --- /dev/null +++ b/Vampirewal.Core.ComputerInfo/ShellUtil.cs @@ -0,0 +1,85 @@ +#region [ 文件信息 ] + +/*---------------------------------------------------------------- + * CLR版本:4.0.30319.42000 + * 机器名称:VAMPIREWAL + * 公司名称:Organization + * 命名空间:Vampirewal.Core.ComputerInfo + * 唯一标识:1c2160b0-aae8-4b52-8b73-6fda4959f70a + * 文件名:ShellUtil + * 当前用户域:VAMPIREWAL + * + * 创建者:Administrator + * 电子邮箱:1425271996@qq.com + * 创建时间:2023/3/1 18:39:04 + * 版本:V1.0.0 + * 描述: + * + * ---------------------------------------------------------------- + * 修改人: + * 时间: + * 修改说明: + * + * 版本:V1.0.1 + *----------------------------------------------------------------*/ + +#endregion [ 文件信息 ] + +using System.Diagnostics; + +namespace Vampirewal.Core.ComputerInfo; + +/// +/// +/// +internal class ShellUtil +{ + /// + /// linux 系统命令 + /// + /// + /// + internal static string Bash(string command) + { + var escapedArgs = command.Replace("\"", "\\\""); + var process = new Process() + { + StartInfo = new ProcessStartInfo + { + FileName = "/bin/bash", + Arguments = $"-c \"{escapedArgs}\"", + RedirectStandardOutput = true, + UseShellExecute = false, + CreateNoWindow = true, + } + }; + process.Start(); + string result = process.StandardOutput.ReadToEnd(); + process.WaitForExit(); + process.Dispose(); + return result; + } + + /// + /// windows系统命令 + /// + /// + /// + /// + internal static string Cmd(string fileName, string args) + { + string output = string.Empty; + + var info = new ProcessStartInfo(); + info.FileName = fileName; + info.Arguments = args; + info.RedirectStandardOutput = true; + info.CreateNoWindow = true; + + using (var process = Process.Start(info)) + { + output = process.StandardOutput.ReadToEnd(); + } + return output; + } +} \ No newline at end of file diff --git a/Vampirewal.Core.ComputerInfo/Vampirewal.Core.ComputerInfo.csproj b/Vampirewal.Core.ComputerInfo/Vampirewal.Core.ComputerInfo.csproj new file mode 100644 index 0000000000000000000000000000000000000000..132c02c59c23649c0b1ecd3906af6a82a3852d7a --- /dev/null +++ b/Vampirewal.Core.ComputerInfo/Vampirewal.Core.ComputerInfo.csproj @@ -0,0 +1,9 @@ + + + + net6.0 + enable + enable + + + diff --git a/Vampirewal.Core.ComputerInfo/VampirewalCoreComputerService.cs b/Vampirewal.Core.ComputerInfo/VampirewalCoreComputerService.cs new file mode 100644 index 0000000000000000000000000000000000000000..afb91b1ca15f2918f49a1a3848a3422289a5e7f0 --- /dev/null +++ b/Vampirewal.Core.ComputerInfo/VampirewalCoreComputerService.cs @@ -0,0 +1,188 @@ +#region [ 文件信息 ] +/*---------------------------------------------------------------- + * CLR版本:4.0.30319.42000 + * 机器名称:VAMPIREWAL + * 公司名称:Organization + * 命名空间:Vampirewal.Core.ComputerInfo + * 唯一标识:f099cf97-3fb4-448b-bd9e-856af6af30a4 + * 文件名:ComputerService + * 当前用户域:VAMPIREWAL + * + * 创建者:Administrator + * 电子邮箱:1425271996@qq.com + * 创建时间:2023/3/1 18:16:20 + * 版本:V1.0.0 + * 描述:代码来自互联网,我这边组合整合了一下 + * + * ---------------------------------------------------------------- + * 修改人: + * 时间: + * 修改说明: + * + * 版本:V1.0.1 + *----------------------------------------------------------------*/ +#endregion [ 文件信息 ] + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace Vampirewal.Core.ComputerInfo; + +/// +/// 电脑信息服务 +/// +public interface IVampirewalCoreComputerService +{ + /// + /// 内存信息 + /// + /// + MemoryMetrics GetComputerInfo(); + /// + /// 磁盘信息 + /// + /// + List GetDiskInfos(); + + /// + /// 获取系统运行时间 + /// + /// + string GetRunTime(); +} + +/// +/// 电脑信息服务 +/// +public sealed class VampirewalCoreComputerService : IVampirewalCoreComputerService +{ + public VampirewalCoreComputerService() + { + //构造函数 + } + + /// + /// 内存信息 + /// + /// + public MemoryMetrics GetComputerInfo() + { + MemoryMetricsClient client = new(); + MemoryMetrics memoryMetrics = IsUnix() ? client.GetUnixMetrics() : client.GetWindowsMetrics(); + + memoryMetrics.FreeRam = Math.Round(memoryMetrics.Free / 1024, 2) + "GB"; + memoryMetrics.UsedRam = Math.Round(memoryMetrics.Used / 1024, 2) + "GB"; + memoryMetrics.TotalRam = Math.Round(memoryMetrics.Total / 1024, 2) + "GB"; + memoryMetrics.RamRate = Math.Ceiling(100 * memoryMetrics.Used / memoryMetrics.Total).ToString() + "%"; + memoryMetrics.CpuRate = Math.Ceiling(GetCPURate().ParseToDouble()) + "%"; + return memoryMetrics; + } + + /// + /// 磁盘信息 + /// + /// + public List GetDiskInfos() + { + List diskInfos = new(); + + if (IsUnix()) + { + string output = ShellUtil.Bash("df -m / | awk '{print $2,$3,$4,$5,$6}'"); + var arr = output.Split('\n', StringSplitOptions.RemoveEmptyEntries); + if (arr.Length == 0) return diskInfos; + + var rootDisk = arr[1].Split(' ', (char)StringSplitOptions.RemoveEmptyEntries); + if (rootDisk == null || rootDisk.Length == 0) + return diskInfos; + + DiskInfo diskInfo = new() + { + DiskName = "/", + TotalSize = long.Parse(rootDisk[0]) / 1024, + Used = long.Parse(rootDisk[1]) / 1024, + AvailableFreeSpace = long.Parse(rootDisk[2]) / 1024, + AvailablePercent = decimal.Parse(rootDisk[3].Replace("%", "")) + }; + diskInfos.Add(diskInfo); + } + else + { + var driv = DriveInfo.GetDrives().Where(u => u.IsReady); + foreach (var item in driv) + { + var obj = new DiskInfo() + { + DiskName = item.Name, + TypeName = item.DriveType.ToString(), + TotalSize = item.TotalSize / 1024 / 1024 / 1024, + AvailableFreeSpace = item.AvailableFreeSpace / 1024 / 1024 / 1024, + }; + obj.Used = obj.TotalSize - obj.AvailableFreeSpace; + obj.AvailablePercent = decimal.Ceiling(obj.Used / (decimal)obj.TotalSize * 100); + diskInfos.Add(obj); + } + } + return diskInfos; + } + + #region 公共方法 + + /// + /// 获取系统运行时间 + /// + /// + public string GetRunTime() + { + string runTime = string.Empty; + if (IsUnix()) + { + string output = ShellUtil.Bash("uptime -s").Trim(); + runTime = DateTimeUtil.FormatTime((DateTime.Now - output.ParseToDateTime()).TotalMilliseconds.ToString().Split('.')[0].ParseToLong()); + } + else + { + string output = ShellUtil.Cmd("wmic", "OS get LastBootUpTime/Value"); + string[] outputArr = output.Split('=', (char)StringSplitOptions.RemoveEmptyEntries); + if (outputArr.Length == 2) + runTime = DateTimeUtil.FormatTime((DateTime.Now - outputArr[1].Split('.')[0].ParseToDateTime()).TotalMilliseconds.ToString().Split('.')[0].ParseToLong()); + } + return runTime; + } + + #endregion + + #region 私有方法 + /// + /// 是否Unix系统 + /// + /// + private bool IsUnix() + { + return RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux); + } + + + private string GetCPURate() + { + string cpuRate; + if (IsUnix()) + { + string output = ShellUtil.Bash("top -b -n1 | grep \"Cpu(s)\" | awk '{print $2 + $4}'"); + cpuRate = output.Trim(); + } + else + { + string output = ShellUtil.Cmd("wmic", "cpu get LoadPercentage"); + cpuRate = output.Replace("LoadPercentage", string.Empty).Trim(); + } + return cpuRate; + } + + + #endregion +} diff --git a/Vampirewal.Core.EventBus/Attributes/SubscribeEventAttribute.cs b/Vampirewal.Core.EventBus/Attributes/SubscribeEventAttribute.cs new file mode 100644 index 0000000000000000000000000000000000000000..ba677390767e17c71f16eb6ae817d6109feb271d --- /dev/null +++ b/Vampirewal.Core.EventBus/Attributes/SubscribeEventAttribute.cs @@ -0,0 +1,102 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: SubscribeEventAttribute +// 创建者: 杨程 +// 创建日期: 2022/12/31 16:12:50 + +//----------------------------------------------------------------*/ +#endregion + +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + + + +namespace Vampirewal.Core.EventBus; + +/// +/// 订阅事件特性 +/// +[AttributeUsage(AttributeTargets.Method)] +public sealed class SubscribeEventAttribute : Attribute +{ + /// + /// 订阅事件特性 + /// + public SubscribeEventAttribute(object token) + { + if (token is string) + { + Token = token as string; + } + else if (token is Enum) + { + Token = (token as Enum).GetDisplay(); + } + else + { + throw new ArgumentException("不支持除字符串和枚举以外的token"); + } + } + + public string Token { get; set; } + +} + +/// +/// 标记在事件总线中的方法才会执行 +/// +[AttributeUsage(AttributeTargets.Method)] +public sealed class EventBusExcuteAttribute : Attribute +{ + +} + + +/// +/// 事件工厂AOP特性,需继承 +/// +[AttributeUsage(AttributeTargets.Method)] +public abstract class EventBusAOPAttribute : Attribute +{ + /// + /// 方法执行前 + /// + /// 上下文 + public abstract void ExcuteBefore(EventContext context); + /// + /// 方法执行后 + /// + /// 上下文 + public abstract void ExcuteAfter(EventContext context); +} + +internal static class EnumHelper +{ + /// + /// 获取枚举的Display文本 + /// + /// + /// + public static String GetDisplay(this Enum value) + { + var type = value.GetType();//先获取这个枚举的类型 + var field = type.GetField(value.ToString());//通过这个类型获取到值 + var obj = (DisplayAttribute)field.GetCustomAttribute(typeof(DisplayAttribute));//得到特性 + return obj.Name ?? ""; + } +} + + diff --git a/Vampirewal.Core.EventBus/IVampirewalCoreEventFactory.cs b/Vampirewal.Core.EventBus/IVampirewalCoreEventFactory.cs new file mode 100644 index 0000000000000000000000000000000000000000..1e6fb9730abff7153f6dbce503692d7eb754099f --- /dev/null +++ b/Vampirewal.Core.EventBus/IVampirewalCoreEventFactory.cs @@ -0,0 +1,56 @@ +#region 文件信息 + +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: IVampirewalCoreEventFactory +// 创建者: 杨程 +// 创建日期: 2022/12/31 16:32:05 + +//----------------------------------------------------------------*/ + +#endregion + +namespace Vampirewal.Core.EventBus; + +/// +/// 事件工厂 +/// +public interface IVampirewalCoreEventFactory +{ + /// + /// 工厂名称(方便查找定位) + /// + string FactoryName { get; } + + /// + /// 事件工厂完成 + /// + /// + void EventFactoryComplate(EventFactoryContext context); +} + +/// +/// 事件工厂上下文 +/// +public class EventFactoryContext +{ + public EventFactoryContext() + { + EventContexts = new List(); + IsEventFactoryComplateSuccess=true; + } + + /// + /// 内部方法上下文 + /// + public List EventContexts { get;internal set; } + + /// + /// 事件工厂是否全部完成成功 + /// + public bool IsEventFactoryComplateSuccess { get;internal set; } +} \ No newline at end of file diff --git a/Vampirewal.Core.EventBus/LICENSE b/Vampirewal.Core.EventBus/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..ddbd00b437e877e43b09521e47a65ad43f04aa8a --- /dev/null +++ b/Vampirewal.Core.EventBus/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 vampirewal + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Vampirewal.Core.EventBus/Vampirewal-Logo.png b/Vampirewal.Core.EventBus/Vampirewal-Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..3d150ba56db89235caebb1676f05415ddc65740d Binary files /dev/null and b/Vampirewal.Core.EventBus/Vampirewal-Logo.png differ diff --git a/Vampirewal.Core.EventBus/Vampirewal.Core.EventBus.csproj b/Vampirewal.Core.EventBus/Vampirewal.Core.EventBus.csproj new file mode 100644 index 0000000000000000000000000000000000000000..8cd114e107fbba06ac579557772a39bddddc8a27 --- /dev/null +++ b/Vampirewal.Core.EventBus/Vampirewal.Core.EventBus.csproj @@ -0,0 +1,46 @@ + + + + net6.0 + enable + enable + True + True + vampirewal + 1.0.0.7 + Vampirewal.Core中简单的事件总线 + Vampirewal-Logo.png + LICENSE + True + Vampirewal + Copyright © 2022 Vampirewal + EventBus + + + + + + + + + + + + + + + + + + \ + True + + + + + bin\Debug\net6.0\Vampirewal.Core.EventBus.xml + + true + + + diff --git a/Vampirewal.Core.EventBus/VampirewalCoreEventBus.cs b/Vampirewal.Core.EventBus/VampirewalCoreEventBus.cs new file mode 100644 index 0000000000000000000000000000000000000000..188b521f7775d9ac96bef96cd4517d53fb7ec518 --- /dev/null +++ b/Vampirewal.Core.EventBus/VampirewalCoreEventBus.cs @@ -0,0 +1,228 @@ +#region 文件信息 + +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: VampirewalCoreEventBus +// 创建者: 杨程 +// 创建日期: 2022/12/31 15:36:23 + +//----------------------------------------------------------------*/ + +#endregion + +using System.Reflection; + +namespace Vampirewal.Core.EventBus; + +/// +/// VampirewalCore简单事件总线管理器 +/// +public sealed class VampirewalCoreEventBusManager +{ + private static VampirewalCoreEventBusManager _instance; + private static object _objLock = new object(); + + /// + /// 获取单例实例 + /// + /// + public static VampirewalCoreEventBusManager GetInstance() + { + if (_instance == null) + { + lock (_objLock) + { + if (_instance == null) + { + _instance = new VampirewalCoreEventBusManager(); + } + } + } + return _instance; + } + + /// + /// + /// + public VampirewalCoreEventBusManager() + { + //构造函数 + Subscribers = new List(); + } + + private List Subscribers { get; set; } + + #region [ 注册 ] + + /// + /// 全部注册 + /// + public void RegisterAll() + { + Type[]? types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).Where(t => t.GetInterfaces().Contains(typeof(IVampirewalCoreEventFactory))).ToArray(); + + foreach (Type type in types) + { + if (type != null) + { + object? obj = Activator.CreateInstance(type); + + if (obj != null) + { + IEnumerable? methods = type.GetMethods(); + + foreach (MethodInfo method in methods) + { + SubscribeEventAttribute? attr = method.GetCustomAttribute(); + + if (attr != null) + { + if (string.IsNullOrEmpty(attr.Token)) + { + throw new VampirewalCoreEventBusException("Token不能为null!"); + } + + Subscriber sub = new Subscriber() + { + Register = obj, + Token = $"{attr.Token}", + Method = method, + }; + + Subscribers.Add(sub); + } + } + } + } + } + } + + #endregion + + #region [ 推送 ] + + /// + /// 推送事件消息 + /// + /// 订阅的Token + /// + public void Publish(string SubscribeToken, object? Params = null) + { + List? subs = Subscribers.FindAll(f => f.Token == $"{SubscribeToken}"); + + Parallel.ForEach(subs, (sub) => + { + EventContext context = new EventContext() + { + PassData = Params, + ExcutingTime = DateTime.Now, + MethodName = sub.Method.Name, + }; + + var attrs = sub.Method.GetCustomAttributes().Where(w => w is EventBusAOPAttribute).ToList(); + + try + { + foreach (EventBusAOPAttribute item in attrs) + { + item.ExcuteBefore(context); + } + + sub.Method.Invoke(sub.Register, new object[] { context }); + } + catch (Exception ex) + { + context.ExceptionInfo = ex.InnerException; + } + finally + { + context.ExcutedTime = DateTime.Now; + + foreach (EventBusAOPAttribute item in attrs) + { + item.ExcuteAfter(context); + } + } + }); + } + + /// + /// 内部方法-订阅 + /// + internal void Subscribe(Subscriber sub) + { + Subscribers.Add(sub); + } + + #endregion +} + +/// +/// 订阅者 +/// +internal class Subscriber +{ + /// + /// 注册体 + /// + public object? Register { get; set; } + + /// + /// 口令 + /// + public string? Token { get; set; } + + /// + /// 方法 + /// + public MethodInfo? Method { get; set; } +} + +/// +/// 事件上下文 +/// +public class EventContext +{ + /// + /// 传递过来的参数 + /// + public object? PassData { get; set; } + + /// + /// 执行的方法名 + /// + public string MethodName { get; internal set; } = ""; + + /// + /// 开始执行时间 + /// + public DateTime? ExcutingTime { get; internal set; } + + /// + /// 执行结束时间 + /// + public DateTime? ExcutedTime { get; internal set; } + + /// + /// 异常信息 + /// + public Exception? ExceptionInfo { get; internal set; } +} + +/// +/// VampirewalCore事件总线异常类 +/// +internal class VampirewalCoreEventBusException : Exception +{ + /// + /// VampirewalCore事件总线异常类 + /// + /// 异常信息 + public VampirewalCoreEventBusException(string ErrorMsg) : base(ErrorMsg) + { + } +} \ No newline at end of file diff --git a/Vampirewal.Core.EventBus/VampirewalCoreEventBusExtension.cs b/Vampirewal.Core.EventBus/VampirewalCoreEventBusExtension.cs new file mode 100644 index 0000000000000000000000000000000000000000..db9539ecb1b3af895b81cd0c8fadf15b49f9b972 --- /dev/null +++ b/Vampirewal.Core.EventBus/VampirewalCoreEventBusExtension.cs @@ -0,0 +1,232 @@ +#region 文件信息 + +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: VampirewalCoreEventBusExtension +// 创建者: 杨程 +// 创建日期: 2023/2/22 22:27:53 + +//----------------------------------------------------------------*/ + +#endregion + +using Microsoft.Extensions.DependencyInjection; +using System.Reflection; + +namespace Vampirewal.Core.EventBus; + +/// +/// +/// +public static class VampirewalCoreEventBusExtension +{ + /// + /// 将事件总线工厂注册到IoC中 + /// + /// + public static void AddVampirewalCoreEventBusFactory(this IServiceCollection services) + { + Type[]? types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).Where(t => t.GetInterfaces().Contains(typeof(IVampirewalCoreEventFactory))).ToArray(); + + AddVampirewalCoreEventBusFactory(services, factory => + { + foreach (var type in types) + { + factory.Add(type); + } + }); + } + + /// + /// 如果事件工厂放在其他项目内,可能自动全部加载的方式无法获取到,可通过这个方法加载 + /// + /// + /// + public static void AddVampirewalCoreEventBusFactory(this IServiceCollection services, Action> eventFactorys) + { + List types = new List(); + + eventFactorys?.Invoke(types); + + foreach (Type type in types) + { + if (type != null) + { + //var methods = type.GetMethods(BindingFlags.Public); + var ErrorMethods = type.GetMethods() + .Where(w => w.GetCustomAttribute() != null&&( w.GetParameters().Length != 1 || w.GetParameters()[0].ParameterType != typeof(EventContext))) + .Select(s => $"{type.Name}事件工厂内的{s.Name}方法参数数量不等于1或参数类型不是EventContext!请修改!") + .ToList(); + + if (ErrorMethods != null && ErrorMethods.Count > 0) + { + throw new VampirewalCoreEventBusException(string.Join("\r\n", ErrorMethods)); + } + + //var methods = type.GetMethods().Where(w=>w.GetCustomAttribute()!=null); + + //foreach (var method in methods) + //{ + // if (method.GetParameters().Length != 1) + // { + // throw new VampirewalCoreEventBusException("事件工厂内的方法仅能有1个参数,EventContext!"); + // } + + // if (method.GetParameters()[0].ParameterType != typeof(EventContext)) + // { + // throw new VampirewalCoreEventBusException($"{type.Name}事件工厂内的{method.Name}方法参数不是EventContext!"); + // } + //} + + //注册事件工厂 + services.AddSingleton(type); + } + } + + //注册事件总线工厂 + services.AddSingleton(); + } +} + +/// +/// VampirewalCore事件总线工厂接口 +/// +public interface IVampirewalCoreEventBusFactory +{ + /// + /// 推送 + /// + /// 事件工厂Type名称 + /// + void Publish(string EventFactoryName, object? Params = null); + + /// + /// 推送 + /// + /// + /// + void Publish(object? Params = null) where TEventFactory : IVampirewalCoreEventFactory; +} + +/// +/// VampirewalCore事件总线工厂 +/// +internal class VampirewalCoreEventBusFactory : IVampirewalCoreEventBusFactory +{ + private readonly IServiceProvider Service; + + private Dictionary EventBusFactoryTypes { get; set; } + + public VampirewalCoreEventBusFactory(IServiceProvider provider) + { + Service = provider; + + EventBusFactoryTypes = new Dictionary(); + RegisterAll(); + } + + /// + /// 注册全部 + /// + private void RegisterAll() + { + Type[]? types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).Where(t => t.GetInterfaces().Contains(typeof(IVampirewalCoreEventFactory))).ToArray(); + + foreach (Type type in types) + { + if (type != null) + { + EventBusFactoryTypes.Add(type.Name, type); + } + } + } + + public void Publish(string EventFactoryName, object? Params = null) + { + if (EventBusFactoryTypes.TryGetValue(EventFactoryName, out Type type)) + { + var im = Service.GetService(type) as IVampirewalCoreEventFactory; + + if (im == null) + throw new VampirewalCoreEventBusException($"未找到类型为{type}的事件工厂!"); + + //获取当前事件工厂内的所有标记了EventBusExcuteAttribute的方法 + var methods = type.GetMethods().Where(w => w.GetCustomAttribute() != null).ToList(); + + if (methods != null && methods.Count() == 0) + { + throw new VampirewalCoreEventBusException($"该事件工厂中没有找到标记EventBusExcuteAttribute特性的方法!"); + } + else if (methods != null) + { + //new一个事件工厂上下文 + EventFactoryContext FactoryContexts = new EventFactoryContext(); + + //这个foreach方法会并行执行,且会等待所有的方法执行完之后,再往下执行方法 + var result= Parallel.ForEach(methods, sub => + { + //new一个事件上下文,方便传递数据 + EventContext context = new EventContext() + { + PassData = Params, + MethodName = sub.Name, + ExcutingTime = DateTime.Now + }; + //将事件上下文添加到事件工厂的上下文集合中 + FactoryContexts.EventContexts.Add(context); + //获取到当前方法上的AOP特性 + var attrs = sub.GetCustomAttributes().Where(w => w is EventBusAOPAttribute).ToList(); + + try + { + //循环执行AOP特性的执行前方法 + foreach (EventBusAOPAttribute item in attrs) + { + item.ExcuteBefore(context); + } + + sub.Invoke(im, new object[] { context }); + } + catch (Exception ex) + { + //捕获方法执行中的异常信息 + context.ExceptionInfo = ex.InnerException; + //将事件工厂的是否全部完成成功标记为false + FactoryContexts.IsEventFactoryComplateSuccess = false; + } + finally + { + context.ExcutedTime = DateTime.Now; + //循环执行AOP特性的执行后方法 + foreach (EventBusAOPAttribute item in attrs) + { + item.ExcuteAfter(context); + } + } + }); + + if (result.IsCompleted) + { + //在事件工厂内的方法全部都执行完成之后,执行事件工厂的完成方法 + im.EventFactoryComplate(FactoryContexts); + } + + } + } + else + { + throw new VampirewalCoreEventBusException($"未找到{EventFactoryName}对应的事件工厂!"); + } + } + + public void Publish(object? Params = null) where TEventFactory : IVampirewalCoreEventFactory + { + Type type = typeof(TEventFactory); + + Publish(type.Name, Params); + } +} \ No newline at end of file diff --git a/Vampirewal.Core.FlowEngine/Model/FlowInfo.cs b/Vampirewal.Core.FlowEngine/Model/FlowInfo.cs new file mode 100644 index 0000000000000000000000000000000000000000..1a0408d585b2e5fb2ed7d651daf3894e6a10852b --- /dev/null +++ b/Vampirewal.Core.FlowEngine/Model/FlowInfo.cs @@ -0,0 +1,68 @@ +#region << 文 件 说 明 >> +/****************************************************************************************************** +*机器名称: DESKTOP-6RM95GA +*命名空间: Vampirewal.Core.FlowEngine.Model +*文 件 名: FlowInfo +*创 建 人: 杨程 +*电子邮箱: 235160615@qq.com +*创建时间: 2022/5/7 15:44:53 + +*描述: +* +*******************************************************************************************************/ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Vampirewal.Core.FlowEngine.Model +{ + /// + /// 流程实体 + /// + public class FlowInfo + { + /// + /// 流程id + /// + public string FlowId { get; set; } + /// + /// 流程编号 + /// + public string FlowCode { get; set; } + /// + /// 版本号 + /// + public int Ver { get; set; } + /// + /// 描述 + /// + public string Desc { get; set; } + /// + /// 状态(0停用1启用) + /// + public FlowInfoState State { get; set; } + /// + /// 模块名 + /// + public string TypeKey { get; set; } + /// + /// 系统类别(0,1,2,3,4....) + /// + public int BillClass { get; set; } + } + public enum FlowInfoState + { + /// + /// 停用 + /// + Disable = 0, + /// + /// 启用 + /// + Enable = 1 + } +} diff --git a/Vampirewal.Core/Interface/ITreeData.cs b/Vampirewal.Core.FlowEngine/Model/FlowUser.cs similarity index 32% rename from Vampirewal.Core/Interface/ITreeData.cs rename to Vampirewal.Core.FlowEngine/Model/FlowUser.cs index efaad16e2ee6d15135eda4b25ad07ebcdb06222f..e5f886056406f0ba9daf659cf30bd9386c218a0a 100644 --- a/Vampirewal.Core/Interface/ITreeData.cs +++ b/Vampirewal.Core.FlowEngine/Model/FlowUser.cs @@ -1,8 +1,8 @@ #region << 文 件 说 明 >> /*---------------------------------------------------------------- -// 文件名称:ITreeData -// 创 建 者:杨程 -// 创建时间:2021/9/15 14:24:14 +// 文件名称:FlowUser +// 创 建 人:YangCheng +// 创建时间:2022/7/6 10:22:13 // 文件版本:V1.0.0 // =============================================================== // 功能描述: @@ -16,37 +16,41 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using Vampirewal.Core.Models; -namespace Vampirewal.Core.Interface +namespace Vampirewal.Core.FlowEngine.Model { /// - /// 树形结构model接口 + /// /// - public interface ITreeData + public class FlowUser { - /// - /// 父节点Id - /// - Guid? ParentId { get; set; } - Guid ID { get; set; } - } - - /// - /// 泛型树形结构model接口 - /// - /// 父节点类型,父节点应该和实现本接口的类是同一个类,否则没有意义 - public interface ITreeData : ITreeData where T : TopBaseModel - { - /// - /// 通过实现这个函数获得所有的子节点数据 - /// - /// 所有子节点数据 - List Children { get; } + public FlowUser(string user) + { + UserName = user; + } - /// - /// 获取父节点 - /// - T? Parent { get; } + public FlowUser(string user, string OrgId, string RoleName) + { + UserName = user; + this.OrgId = OrgId; + this.RoleName = RoleName; + } + public string UserName { get; set; } + public string OrgId { get; set; } + public string RoleName { get; set; } + public override string ToString() + { + return this.UserName; + } + public override bool Equals(object obj) + { + if (obj is FlowUser && ((FlowUser)obj).UserName == this.UserName) + return true; + return false; + } + public override int GetHashCode() + { + return base.GetHashCode(); + } } } diff --git a/Vampirewal.Core.FlowEngine/Model/Task.cs b/Vampirewal.Core.FlowEngine/Model/Task.cs new file mode 100644 index 0000000000000000000000000000000000000000..b6cdc0a4bdbe9576f200614c139dbe52fc17efb4 --- /dev/null +++ b/Vampirewal.Core.FlowEngine/Model/Task.cs @@ -0,0 +1,159 @@ +#region << 文 件 说 明 >> +/****************************************************************************************************** +*机器名称: DESKTOP-6RM95GA +*命名空间: Vampirewal.Core.FlowEngine.Model +*文 件 名: Task +*创 建 人: 杨程 +*电子邮箱: 235160615@qq.com +*创建时间: 2022/5/7 15:47:26 + +*描述: +* +*******************************************************************************************************/ +#endregion + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Vampirewal.Core.FlowEngine.Model +{ + public class Task + { + /// + /// 任务Id + /// + public string TaskId { get; set; } + /// + /// 流程实例Id + /// + public string WorkId { get; set; } + /// + /// 提交流程的实体Id + /// + public string EntityId { get; set; } + /// + /// 提交流程的机构名 + /// + public string OrgName { get; set; } + /// + /// 任务描述 + /// + public string TaskDescription { get; set; } + /// + /// 提交流程的实体所属子系统或模块分类(例如:材料,结算等) + /// 0 招标 + /// 1 合同 + /// 2 结算 + /// 3 工程 + /// 4 物料 + /// 5 设备 + /// 6 外包方 + /// 7 周材 + /// 8 物资结算 + /// 9 设备结算 + /// 10 周材结算 + /// 11 工程结算 + /// 12 安全 + /// 13 报表 + /// + public int Class { get; set; } + /// + /// 单据名称 + /// + public string BillName { get; set; } + /// + /// 单据编号 + /// + public string BillNo { get; set; } + /// + /// 显示任务界面的统一资源定位符 + /// + public string URI { get; set; } + + /// + /// 显示任务界面的统一资源定位符(WPF) + /// + public string WpfURI { get; set; } + /// + /// 分配给的用户 + /// + public string AssignUser { get; set; } + /// + /// 通知时间 + /// + public DateTime? NotifyTime { get; set; } + /// + /// 任务状态 + /// + public TaskState State { get; set; } + /// + /// 完成任务的用户 + /// + public string CompleteUser { get; set; } + /// + /// 完成任务的时间 + /// + public DateTime? CompleteTime { get; set; } + /// + /// 任务是否未通过 + /// + public bool IsReject { get; set; } + /// + /// 审批意见 + /// + public string Opinion { get; set; } + /// + /// 是否自由流程节点 + /// + public bool IsFreeUnit { get; set; } + /// + /// 审核级次 + /// + public string UnitName { get; set; } + /// + /// 审核人岗位 + /// + public string UserTitle { get; set; } + /// + /// 在此节点单据是否可修改 + /// + public bool CanModify { get; set; } + /// + /// 用户分配ID + /// + public string DispId { get; set; } + /// + /// 是否合并待办 + /// + public bool MergeTodo { get; set; } + /// + /// 节点Id + /// + public string UnitId { get; set; } + /// + /// 节点索引号 + /// + public int UnitIndex { get; set; } + /// + /// 是否可以撤销 + /// + public bool CanUndo { get; set; } + /// + /// 单据类别 + /// + public string TypeKey { get; set; } + + } + + public enum TaskState + { + [Description("待办")] + Todo, + [Description("已完成")] + Complete + } +} diff --git a/Vampirewal.Core.FlowEngine/Model/UnitInfo.cs b/Vampirewal.Core.FlowEngine/Model/UnitInfo.cs new file mode 100644 index 0000000000000000000000000000000000000000..c8fdf52ee6a7ceeb8083331bbce787168cb8dfd2 --- /dev/null +++ b/Vampirewal.Core.FlowEngine/Model/UnitInfo.cs @@ -0,0 +1,65 @@ +#region << 文 件 说 明 >> +/****************************************************************************************************** +*机器名称: DESKTOP-6RM95GA +*命名空间: Vampirewal.Core.FlowEngine.Model +*文 件 名: UnitInfo +*创 建 人: 杨程 +*电子邮箱: 235160615@qq.com +*创建时间: 2022/5/7 15:52:31 + +*描述: +* +*******************************************************************************************************/ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Vampirewal.Core.FlowEngine.Model +{ + /// + /// 当前节点信息 + /// + public class UnitInfo + { + /// + /// 当前节点是否允许修改 + /// + public bool CanModify { get; set; } + /// + /// 当前节点是否允许审核 + /// + public bool CanAudit { get; set; } + /// + /// 当前节点是否允许单步退回 + /// + public bool CanUndoAudit { get; set; } + /// + /// 当前节点是否自由流程节点 + /// + public bool IsFree { get; set; } + /// + /// 自由流程节点的下一步节点 + /// + public List FreeNextUnits { get; set; } + + } + + /// + /// 节点信息 + /// + public class UnitData + { + /// + /// 节点索引号 + /// + public int UnitIndex { get; set; } + /// + /// 节点名称 + /// + public string UnitName { get; set; } + } +} diff --git a/Vampirewal.Core.FlowEngine/Model/Work.cs b/Vampirewal.Core.FlowEngine/Model/Work.cs new file mode 100644 index 0000000000000000000000000000000000000000..a54f9f1be4882a353f095597af93c9513362c3ad --- /dev/null +++ b/Vampirewal.Core.FlowEngine/Model/Work.cs @@ -0,0 +1,74 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:Work +// 创 建 人:YangCheng +// 创建时间:2022/7/6 10:14:47 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Vampirewal.Core.FlowEngine.Model +{ + /// + /// + /// + public class Work + { + //public Work() + //{ + // Tasks = new StateList(); + //} + //public Work(Flow flow) + //{ + // this.m_Flow = flow; + // //this.Desc = flow.FirstUnit.TaskDescriptionTemplate; + // this.BillClass = flow.BillClass; + // Tasks = new StateList(); + // Params = new ParamList(this, true); + //} + + //public string TransTaskId { get; set; } + //public object BLWork { get; set; } + //private Flow m_Flow = null; + //public Flow Flow + //{ + // get + // { + // return m_Flow; + // } + //} + //public string Id { get; set; } + //public FlowUser Startor { get; set; } + //public DateTime? StartTime { get; set; } + //public DateTime? FinishTime { get; set; } + //public WorkState State { get; set; } + //public string Desc { get; set; } + //public StateList Tasks { get; set; } + //public ParamList Params { get; set; } + //public string EntityId { get; set; } + //public string OrgId { get; set; } + //public string OrgName { get; set; } + //public int BillClass { get; set; } + } + + public enum WorkState + { + [Description("运行中")] + wsRuning, + [Description("已完成")] + wsComplete, + [Description("取消")] + wsCancel + } +} diff --git a/Vampirewal.Core.FlowEngine/Vampirewal.Core.FlowEngine.csproj b/Vampirewal.Core.FlowEngine/Vampirewal.Core.FlowEngine.csproj new file mode 100644 index 0000000000000000000000000000000000000000..cf424d0095141b73844b42ad362ee39be5d0357a --- /dev/null +++ b/Vampirewal.Core.FlowEngine/Vampirewal.Core.FlowEngine.csproj @@ -0,0 +1,11 @@ + + + + net6.0-windows + + + + + + + diff --git a/Vampirewal.Core.FolwEngine.Test/Program.cs b/Vampirewal.Core.FolwEngine.Test/Program.cs new file mode 100644 index 0000000000000000000000000000000000000000..463fedfa8c8cf620303daa7525b7741c0c9f3ddd --- /dev/null +++ b/Vampirewal.Core.FolwEngine.Test/Program.cs @@ -0,0 +1,63 @@ +// See https://aka.ms/new-console-template for more information + +using Microsoft.Extensions.DependencyInjection; +using WorkflowCore.Interface; +using WorkflowCore.Models; + +class Program +{ + static void Main(string[] args) + { + IServiceProvider serviceProvider = ConfigureServices(); + var host = serviceProvider.GetService(); + host.RegisterWorkflow(); + host.Start(); + + host.StartWorkflow("HelloWorld", 1, null); + Console.ReadLine(); + host.Stop(); + } + + private static IServiceProvider ConfigureServices() + { + //setup dependency injection + IServiceCollection services = new ServiceCollection(); + services.AddLogging(); + services.AddWorkflow(); + + var serviceProvider = services.BuildServiceProvider(); + + return serviceProvider; + } +} + +public class HelloWorldWorkflow : IWorkflow +{ + public string Id => "HelloWorld"; + public int Version => 1; + + public void Build(IWorkflowBuilder builder) + { + //builder + // .StartWith(). + // .Then(); + } +} + +public class HelloWorld : StepBody +{ + public override ExecutionResult Run(IStepExecutionContext context) + { + Console.WriteLine("你好"); + return ExecutionResult.Next(); + } +} + +public class GoodbyeWorld : StepBody +{ + public override ExecutionResult Run(IStepExecutionContext context) + { + Console.WriteLine("再见"); + return ExecutionResult.Next(); + } +} diff --git a/Vampirewal.Core.FolwEngine.Test/Vampirewal.Core.FolwEngine.Test.csproj b/Vampirewal.Core.FolwEngine.Test/Vampirewal.Core.FolwEngine.Test.csproj new file mode 100644 index 0000000000000000000000000000000000000000..fafa65ffaa890512baf83e3a132b04aa63b77843 --- /dev/null +++ b/Vampirewal.Core.FolwEngine.Test/Vampirewal.Core.FolwEngine.Test.csproj @@ -0,0 +1,16 @@ + + + + Exe + net6.0 + enable + enable + + + + + + + + + diff --git a/Vampirewal.Core.HttpClientService/IHttpClientService.cs b/Vampirewal.Core.HttpClientService/IHttpClientService.cs new file mode 100644 index 0000000000000000000000000000000000000000..08fb43c2b48d8573d041abe44941e3f8c8eebe0f --- /dev/null +++ b/Vampirewal.Core.HttpClientService/IHttpClientService.cs @@ -0,0 +1,147 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:IHttpClientService +// 创 建 人:YangCheng +// 创建时间:2022/7/8 9:06:16 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + +using System.Collections.Generic; +using System.Text.Json; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; + +namespace Vampirewal.Core.HttpClientService +{ + /// + /// + /// + public interface IHttpClientService + { + ServiceProvider ServiceProvider { get; } + + ServiceCollection serviceCollection { get; } + + /// + /// Json序列化设置 + /// + JsonSerializerOptions options { get; } + /// + /// 设置Json序列化配置 + /// + /// + void SetJsonSerializerOptions(JsonSerializerOptions options); + + /// + /// 请求头字典 + /// + Dictionary RequestHeaderDic { get; } + + /// + /// 设置请求头 + /// + /// + void SetHeader(Dictionary _requestHeaderDic); + + /// + /// GET请求 + /// + /// + /// + string HttpGet(string url); + + /// + /// GET请求(返回对象) + /// + /// + /// + /// + T HttpGet(string url); + + /// + /// 自定义参数的GET请求(无需将参数自行写进url中) + /// + /// 请求地址 + /// 参数 + /// + string RequestGetOfCustomParameter(string url, params RequestParam[] requestParams); + + /// + /// 自定义参数的GET请求(无需将参数自行写进url中) + /// + /// 返回值类型 + /// 请求地址 + /// 参数 + /// + T RequestGetOfCustomParameter(string url, params RequestParam[] requestParams); + + /// + /// 通过GET调用下载附件 + /// + /// + /// + /// + Task HttpGetDownLoad(string url, string SavePath); + + /// + /// POST请求 + /// + /// API地址 + /// 传递的参数 + /// application/xml、application/json、application/text、application/x-www-form-urlencoded + /// + /// Json文本 + string HttpPost(string url, object obj, ContentType contentType, string charset = "UTF-8"); + + /// + /// POST请求(返回对象) + /// + /// API地址 + /// 传递的参数 + /// application/xml、application/json、application/text、application/x-www-form-urlencoded + /// + /// 对象 + T HttpPost(string url, object obj, ContentType contentType, string charset = "UTF-8"); + + /// + /// 自定义参数的POST请求(无需将参数自行写进url中) + /// + /// + /// + /// + string RequestPostOfCustomParameter(string url, params RequestParam[] requestParams); + + /// + /// 自定义参数的POST请求(无需将参数自行写进url中) + /// + /// + /// + /// + /// + T RequestPostOfCustomParameter(string url, params RequestParam[] requestParams); + + /// + /// 通过POST模拟表单调用上传图片 + /// + /// 请求地址 + /// 图片路径 + /// 表单参数 + /// + /// + Task PostUploadImage(string uploadUrl, string imgPath,Dictionary Param = null, string fileparameter = "file"); + + /// + /// 模拟web表单提交 + /// + /// + /// + /// + Task FormRequestPost(string url, RequestParam[] requestParams); + } + +} diff --git a/Vampirewal.Core.HttpClientService/LICENSE b/Vampirewal.Core.HttpClientService/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..ddbd00b437e877e43b09521e47a65ad43f04aa8a --- /dev/null +++ b/Vampirewal.Core.HttpClientService/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 vampirewal + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Vampirewal.Core.HttpClientService/RequestParam.cs b/Vampirewal.Core.HttpClientService/RequestParam.cs new file mode 100644 index 0000000000000000000000000000000000000000..015274bd8f49175b0e0420170bc818c2e903764f --- /dev/null +++ b/Vampirewal.Core.HttpClientService/RequestParam.cs @@ -0,0 +1,57 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: RequestParam +// 创建者: 杨程 +// 创建日期: 2022/11/14 12:08:59 + +//----------------------------------------------------------------*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + + + +namespace Vampirewal.Core.HttpClientService +{ + /// + /// 请求参数 + /// + public class RequestParam + { + public RequestParam(string requestParameterName, object requestValue) + { + RequestParameterName = requestParameterName; + RequestValue = requestValue; + } + + /// + /// 请求的参数名 + /// + public string RequestParameterName { get; } + /// + /// 请求参数值 + /// + public object RequestValue { get; } + + /// + /// 拼接好的参数Key=value + /// + public string RequestString + { + get + { + return $"{RequestParameterName}={RequestValue}"; + } + } + } +} diff --git a/Vampirewal.Core.HttpClientService/Vampirewal-Logo.png b/Vampirewal.Core.HttpClientService/Vampirewal-Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..3d150ba56db89235caebb1676f05415ddc65740d Binary files /dev/null and b/Vampirewal.Core.HttpClientService/Vampirewal-Logo.png differ diff --git a/Vampirewal.Core.HttpClientService/Vampirewal.Core.HttpClientService.csproj b/Vampirewal.Core.HttpClientService/Vampirewal.Core.HttpClientService.csproj new file mode 100644 index 0000000000000000000000000000000000000000..3ab2e65e4b87c3b6534be3110730337fcf102c1c --- /dev/null +++ b/Vampirewal.Core.HttpClientService/Vampirewal.Core.HttpClientService.csproj @@ -0,0 +1,35 @@ + + + + net5.0 + True + vampirewal + 1.0.0.13 + Vampirewal.Core中请求WebApi的组件 + Vampirewal-Logo.png + LICENSE + True + + + + + + + + + + + + + + + + + + + \ + True + + + + diff --git a/Vampirewal.Core.HttpClientService/VampirewalHttpClientService.cs b/Vampirewal.Core.HttpClientService/VampirewalHttpClientService.cs new file mode 100644 index 0000000000000000000000000000000000000000..8afff126be1ab781cda3646c3cf6359eda35f6a2 --- /dev/null +++ b/Vampirewal.Core.HttpClientService/VampirewalHttpClientService.cs @@ -0,0 +1,573 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: VampirewalHttpClientService +// 创建者: 杨程 +// 创建日期: 2022/11/14 15:20:57 + +//----------------------------------------------------------------*/ +#endregion + +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http.Headers; +using System.Net.Http; +using System.Net; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; +using System.Text.Json.Serialization; +using System.ComponentModel.DataAnnotations; +using System.Reflection; + +namespace Vampirewal.Core.HttpClientService +{ + /// + /// + /// + public class VampirewalHttpClientService : IHttpClientService + { + + #region 配置 + public ServiceProvider ServiceProvider { get; private set; } + public ServiceCollection serviceCollection { get; private set; } + + public JsonSerializerOptions options { get; private set; } + + public VampirewalHttpClientService() + { + serviceCollection = new ServiceCollection(); + ServiceProvider = serviceCollection.AddHttpClient().BuildServiceProvider(); + ConfigureServices(serviceCollection); + + _httpClientFactory = ServiceProvider.GetService(); + + + } + + private void ConfigureServices(ServiceCollection services) + { + //services.AddHttpClient(); + //ServiceProvider = services.BuildServiceProvider(); + } + + public Dictionary RequestHeaderDic { get; private set; } = new Dictionary(); + + /// + /// 设置请求头 + /// + /// + public void SetHeader(Dictionary _requestHeaderDic) + { + RequestHeaderDic = _requestHeaderDic; + } + + + [Obsolete("暂时不可用", true)] + public void AddHttpClient(string ClientName, Dictionary RequestHeaderDic) + { + serviceCollection.AddHttpClient("aaa", c => + { + + }); + } + + /// + /// 设置自定义反序列化设置 + /// + /// + public void SetJsonSerializerOptions(JsonSerializerOptions options) + { + this.options = options; + } + #endregion + + + protected IHttpClientFactory _httpClientFactory { get; set; } + + + private HttpClient CreateClient(string url) + { + if (url.StartsWith("https")) + { + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls; + } + + var _httpClient = _httpClientFactory.CreateClient(); + + if (RequestHeaderDic.Count > 0) + { + foreach (var item in RequestHeaderDic) + { + _httpClient.DefaultRequestHeaders.Add(item.Key, item.Value); + } + } + + return _httpClient; + } + + #region GET请求 + /// + /// GET请求 + /// + /// + /// + public string HttpGet(string url) + { + string result = ""; + + var _httpClient = CreateClient(url); + + var response = _httpClient.GetAsync(url).Result; + + if (response.IsSuccessStatusCode) + { + Task t = response.Content.ReadAsStringAsync(); + if (t != null) + { + result = t.Result; + } + } + return result; + } + + /// + /// GET请求(返回对象) + /// + /// + /// + public T HttpGet(string url) + { + var _httpClient = CreateClient(url); + + var response = _httpClient.GetAsync(url).Result; + + if (response.IsSuccessStatusCode) + { + Task t = response.Content.ReadAsStringAsync(); + if (t != null) + { + //options.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All); //解决中文序列化被编码的问题 + //options.Converters.Add(new DateTimeConverter()); //解决时间格式序列化的问题 + + return JsonSerializer.Deserialize(t.Result, options); + } + } + return default(T); + } + + public async Task HttpGetDownLoad(string url, string SavePath) + { + var _httpClient = CreateClient(url); + + HttpResponseMessage response = _httpClient.GetAsync(url).Result; + response.EnsureSuccessStatusCode(); + if (response.IsSuccessStatusCode) + { + using (FileStream fs = File.Open(SavePath, FileMode.Create)) + { + using Stream ms = response.Content.ReadAsStream(); + await ms.CopyToAsync(fs); + } + + return true; + } + + return false; + } + + public string RequestGetOfCustomParameter(string url, params RequestParam[] requestParams) + { + string result = ""; + var _httpClient = CreateClient(url); + + string UrlAndParamStr = ""; + + if (requestParams!=null&& requestParams.Count()>0) + { + List ParamList = new List(); + foreach (var item in requestParams) + { + ParamList.Add(item.RequestString); + } + UrlAndParamStr = $"{url}?{string.Join("&", ParamList)}"; + } + else + { + UrlAndParamStr = $"{url}"; + } + + + var response = _httpClient.GetAsync(UrlAndParamStr).Result; + + if (response.IsSuccessStatusCode) + { + Task t = response.Content.ReadAsStringAsync(); + if (t != null) + { + result = t.Result; + } + } + return result; + } + + public T RequestGetOfCustomParameter(string url, params RequestParam[] requestParams) + { + var _httpClient = CreateClient(url); + + string UrlAndParamStr = ""; + + if (requestParams != null && requestParams.Count() > 0) + { + List ParamList = new List(); + foreach (var item in requestParams) + { + ParamList.Add(item.RequestString); + } + UrlAndParamStr = $"{url}?{string.Join("&", ParamList)}"; + } + else + { + UrlAndParamStr = $"{url}"; + } + + var response = _httpClient.GetAsync(UrlAndParamStr).Result; + + if (response.IsSuccessStatusCode) + { + Task t = response.Content.ReadAsStringAsync(); + if (t != null) + { + return JsonSerializer.Deserialize(t.Result, options); + } + } + return default(T); + } + #endregion + + #region POST请求--异步方法 + + /// + /// POST请求 + /// + /// API地址 + /// 传递的参数 + /// application/xml、application/json、application/text、application/x-www-form-urlencoded + /// + /// Json文本 + public string HttpPost(string url, object obj, ContentType contentType, string charset = "UTF-8") + { + string result = ""; + var _httpClient = CreateClient(url); + + _httpClient.DefaultRequestHeaders.Accept.Clear(); + _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(contentType.GetDisplay())); + + string content = JsonSerializer.Serialize(obj); + + var httpContent = new StringContent(content, Encoding.UTF8, contentType.GetDisplay()); + + var response = _httpClient.PostAsync(url, httpContent).Result; + if (response.IsSuccessStatusCode) + { + Task t = response.Content.ReadAsStringAsync(); + if (t != null) + { + result = t.Result; + } + } + return result; + } + + public string RequestPostOfCustomParameter(string url, params RequestParam[] requestParams) + { + string result = ""; + var _httpClient = CreateClient(url); + + string UrlAndParamStr = ""; + + if (requestParams != null && requestParams.Count() > 0) + { + List ParamList = new List(); + foreach (var item in requestParams) + { + ParamList.Add(item.RequestString); + } + UrlAndParamStr = $"{url}?{string.Join("&", ParamList)}"; + } + else + { + UrlAndParamStr = $"{url}"; + } + + HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, UrlAndParamStr); + + var response = _httpClient.SendAsync(request).Result; + + if (response.IsSuccessStatusCode) + { + Task t = response.Content.ReadAsStringAsync(); + if (t != null) + { + result = t.Result; + } + } + return result; + } + + public T RequestPostOfCustomParameter(string url, params RequestParam[] requestParams) + { + var _httpClient = CreateClient(url); + + string UrlAndParamStr = ""; + + if (requestParams != null && requestParams.Count() > 0) + { + List ParamList = new List(); + foreach (var item in requestParams) + { + ParamList.Add(item.RequestString); + } + UrlAndParamStr = $"{url}?{string.Join("&", ParamList)}"; + } + else + { + UrlAndParamStr = $"{url}"; + } + + HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, UrlAndParamStr); + + var response = _httpClient.SendAsync(request).Result; + + if (response.IsSuccessStatusCode) + { + Task t = response.Content.ReadAsStringAsync(); + if (t != null) + { + return JsonSerializer.Deserialize(t.Result, options); + } + else + { + return default(T); + } + } + else + { + return default(T); + } + } + + /// + /// POST请求(返回对象) + /// + /// API地址 + /// 传递的参数 + /// application/xml、application/json、application/text、application/x-www-form-urlencoded + /// + /// 对象 + public T HttpPost(string url, object obj, ContentType contentType, string charset = "UTF-8") + { + var _httpClient = CreateClient(url); + + _httpClient.DefaultRequestHeaders.Accept.Clear(); + _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(contentType.GetDisplay())); + + string content = JsonSerializer.Serialize(obj); + + var httpContent = new StringContent(content, Encoding.UTF8, contentType.GetDisplay()); + + var response = _httpClient.PostAsync(url, httpContent).Result; + if (response.IsSuccessStatusCode) + { + Task t = response.Content.ReadAsStringAsync(); + if (t != null) + { + return JsonSerializer.Deserialize(t.Result, options); + } + else + { + return default(T); + } + } + else + { + return default(T); + } + + } + + /// + /// 通过POST模拟表单调用上传图片 + /// + /// 请求地址 + /// 图片路径 + /// 表单参数 + /// + /// + public async Task PostUploadImage(string uploadUrl, string imgPath, Dictionary Param = null, string fileparameter = "file") + { + var httpClient = CreateClient(uploadUrl); + + httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/JOSN"));//设定要响应的数据格式 + + using (MultipartFormDataContent httpContent = new MultipartFormDataContent()) + { + using (var fileContent = new ByteArrayContent(System.IO.File.ReadAllBytes(imgPath))) + { + //int pos = imgPath.LastIndexOf("/"); + //string fileName = imgPath.Substring(pos + 1); + string fileName = Path.GetFileName(imgPath); + httpContent.Add(fileContent, fileparameter, fileName); + + if (Param != null && Param.Count > 0) + { + foreach (var (key, value) in Param) + { + var valueBytes = Encoding.UTF8.GetBytes(value); + var byteArray = new ByteArrayContent(valueBytes); + byteArray.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") + { + Name = key + }; + httpContent.Add(byteArray); + } + } + + + var response = await httpClient.PostAsync(uploadUrl, httpContent); + + if (response.IsSuccessStatusCode) + { + string result = await response.Content.ReadAsStringAsync(); + return result; + } + return null; + } + + } + } + + public async Task FormRequestPost(string url, RequestParam[] requestParams) + { + if (requestParams == null) + { + throw new Exception("请求参数不能为null!"); + } + + var httpClient = CreateClient(url); + + using (MultipartFormDataContent httpContent = new MultipartFormDataContent()) + { + foreach (var item in requestParams) + { + var valueBytes = Encoding.UTF8.GetBytes(item.RequestValue.ToString()); + var byteArray = new ByteArrayContent(valueBytes); + byteArray.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") + { + Name = item.RequestParameterName + }; + httpContent.Add(byteArray); + } + + var response = await httpClient.PostAsync(url, httpContent); + + if (response.IsSuccessStatusCode) + { + string result = await response.Content.ReadAsStringAsync(); + return result; + } + return null; + } + + } + + #endregion + } + + + + + + + /// + /// + /// + public class Token + { + public string access_token { get; set; } + + public int expires_in { get; set; } + + public string token_type { get; set; } + + public string refresh_token { get; set; } + } + + /// + /// 传输类型枚举 + /// + public enum ContentType + { + [Display(Name = "application/xml")] + application_xml = 0, + [Display(Name = "application/json")] + application_json = 1, + [Display(Name = "application/text")] + application_text = 2, + [Display(Name = "application/x-www-form-urlencoded")] + application_x_www_form_urlencoded = 3 + } + + public class DateTimeConverter : JsonConverter + { + public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return DateTime.Parse(reader.GetString()); + } + + public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) + { + writer.WriteStringValue(value.ToString("yyyy-MM-dd HH:mm:ss")); + } + } + + public class DateTimeNullableConverter : JsonConverter + { + public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return string.IsNullOrEmpty(reader.GetString()) ? default(DateTime?) : DateTime.Parse(reader.GetString()); + } + + public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options) + { + writer.WriteStringValue(value?.ToString("yyyy-MM-dd HH:mm:ss")); + } + } + + /// + /// 枚举扩展类 + /// + internal static class EnumHelper + { + /// + /// 获取枚举的Display文本 + /// + /// + /// + public static String GetDisplay(this Enum value) + { + var type = value.GetType();//先获取这个枚举的类型 + var field = type.GetField(value.ToString());//通过这个类型获取到值 + var obj = (DisplayAttribute)field.GetCustomAttribute(typeof(DisplayAttribute));//得到特性 + return obj.Name ?? ""; + } + } +} diff --git a/Vampirewal.Core.Mapper/IVampirewalMapper.cs b/Vampirewal.Core.Mapper/IVampirewalMapper.cs new file mode 100644 index 0000000000000000000000000000000000000000..bb60aa35d37c55184c6832c25f81d2d0279607f3 --- /dev/null +++ b/Vampirewal.Core.Mapper/IVampirewalMapper.cs @@ -0,0 +1,34 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: IVampirewalMapper +// 创建者: 杨程 +// 创建日期: 2022/10/24 17:22:31 + +//----------------------------------------------------------------*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + + + +namespace Vampirewal.Core.Mapper; + +/// +/// +/// +public interface IVampirewalMapper +{ + + + Type MapperTargetType(); +} diff --git a/Vampirewal.Core.Mapper/MapperManager.cs b/Vampirewal.Core.Mapper/MapperManager.cs new file mode 100644 index 0000000000000000000000000000000000000000..3a645e5f8e1d7742128c29635fe63fd6b373e416 --- /dev/null +++ b/Vampirewal.Core.Mapper/MapperManager.cs @@ -0,0 +1,429 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: MapperManager +// 创建者: 杨程 +// 创建日期: 2022/10/24 16:59:55 + +//----------------------------------------------------------------*/ +#endregion + +using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using static System.Linq.Expressions.Expression; + + + +namespace Vampirewal.Core.Mapper; + +/// +/// 映射管理器 +/// +public static class MapperManager +{ + + + static Dictionary MapperDic = new Dictionary(); + + #region 注册(Register) + public static void RegisterAll() + { + /* + * 注意事项: + * 1、如果是WPF使用的话,建议把ViewModelLocator放在VM类库中 + * 2、然后再调用这个,才能在初始化的时候,找到VM这个类库,然后加载里面的ViewModel,不然的话,找不到VM这个程序集,会无法加载ViewModel + */ + + + + var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).Where(w => w.GetInterface("IVampirewalMapper") != null).ToList(); + + + + foreach (var v in types) + { + var aaa = Activator.CreateInstance(v) as IVampirewalMapper; + + var target = aaa.MapperTargetType(); + + MapperDic.Add(v, target); + } + } + #endregion + + #region 属性 + + #endregion + + #region 公共方法 + + public static TTarget Map(Tsource source) where Tsource : class, new() where TTarget : class, new() + { + //MapperDic.TryGetValue(typeof(Tsource), out Type target); + + var result = Activator.CreateInstance(typeof(TTarget)); + + var SourceProps = typeof(Tsource).GetProperties(); + var TargetProps = typeof(TTarget).GetProperties(); + + foreach (var prop1 in SourceProps) + { + foreach (var prop2 in TargetProps) + { + if (prop2.PropertyType.IsValueType || prop2.PropertyType.Name.StartsWith("String")) + { + if (prop1.Name == prop2.Name) + { + try + { + object value = prop1.GetValue(source, null); + var prop = typeof(TTarget).GetProperty(prop1.Name); + if (prop != null && prop.CanWrite && !(value is DBNull)) + { + prop.SetValue(result, value, null); + } + } + catch (Exception) + { + + throw; + } + } + } + } + } + + return (TTarget)result; + } + + public static object Map(TSource source) + { + + if (MapperDic.TryGetValue(typeof(TSource), out Type target)) + { + var result = Activator.CreateInstance(target); + + var SourceProps = typeof(TSource).GetProperties(); + var TargetProps = target.GetProperties(); + + foreach (var prop1 in SourceProps) + { + foreach (var prop2 in TargetProps) + { + if (prop2.PropertyType.IsValueType || prop2.PropertyType.Name.StartsWith("String")) + { + if (prop1.Name == prop2.Name) + { + try + { + object value = prop1.GetValue(source, null); + var prop = target.GetProperty(prop1.Name); + if (prop != null && prop.CanWrite && !(value is DBNull)) + { + prop.SetValue(result, value, null); + } + } + catch (Exception) + { + + throw; + } + } + } + } + } + + return result; + } + else + { + throw new Exception("未注册目标类型"); + } + + + } + + /// + /// 简单映射 + /// + /// 目标类型 + /// + /// + public static TTarget SimpleMap(this object source) + { + var result = Activator.CreateInstance(typeof(TTarget)); + + var SourceProps = source.GetType().GetProperties(); + var TargetProps = typeof(TTarget).GetProperties(); + + foreach (var prop1 in SourceProps) + { + foreach (var prop2 in TargetProps) + { + if (prop2.PropertyType.IsValueType || prop2.PropertyType.Name.StartsWith("String")) + { + if (prop1.Name == prop2.Name) + { + try + { + object value = prop1.GetValue(source, null); + var prop = typeof(TTarget).GetProperty(prop1.Name); + if (prop != null && prop.CanWrite && !(value is DBNull)) + { + prop.SetValue(result, value, null); + } + } + catch (Exception ex) + { + + throw ex; + } + } + } + } + } + + return (TTarget)result; + } + + #endregion + + #region 私有方法 + + #endregion + + #region Command命令 + + #endregion +} + + +public static class Mapper where TSource : class where TTarget : class +{ + public readonly static Func MapFunc = GetMapFunc(); + + public readonly static Action MapAction = GetMapAction(); + + /// + /// 将对象TSource转换为TTarget + /// + /// + /// + public static TTarget Map(TSource source) => MapFunc(source); + + public static List MapList(IEnumerable sources) => sources.Select(MapFunc).ToList(); + + + + /// + /// 将对象TSource的值赋给给TTarget + /// + /// + /// + public static void Map(TSource source, TTarget target) => MapAction(source, target); + + private static Func GetMapFunc() + { + var sourceType = typeof(TSource); + var targetType = typeof(TTarget); + //Func委托传入变量 + var parameter = Parameter(sourceType, "p"); + + var memberBindings = new List(); + var targetTypes = targetType.GetProperties().Where(x => x.PropertyType.IsPublic && x.CanWrite); + foreach (var targetItem in targetTypes) + { + var sourceItem = sourceType.GetProperty(targetItem.Name); + + //判断实体的读写权限 + if (sourceItem == null || !sourceItem.CanRead || sourceItem.PropertyType.IsNotPublic) + continue; + + //标注NotMapped特性的属性忽略转换 + if (sourceItem.GetCustomAttribute() != null) + continue; + + var sourceProperty = Property(parameter, sourceItem); + + //当非值类型且类型不相同时 + if (!sourceItem.PropertyType.IsValueType && sourceItem.PropertyType != targetItem.PropertyType) + { + //判断都是(非泛型)class + if (sourceItem.PropertyType.IsClass && targetItem.PropertyType.IsClass && + !sourceItem.PropertyType.IsGenericType && !targetItem.PropertyType.IsGenericType) + { + var expression = GetClassExpression(sourceProperty, sourceItem.PropertyType, targetItem.PropertyType); + memberBindings.Add(Bind(targetItem, expression)); + } + + //集合数组类型的转换 + if (typeof(IEnumerable).IsAssignableFrom(sourceItem.PropertyType) && typeof(IEnumerable).IsAssignableFrom(targetItem.PropertyType)) + { + var expression = GetListExpression(sourceProperty, sourceItem.PropertyType, targetItem.PropertyType); + memberBindings.Add(Bind(targetItem, expression)); + } + + continue; + } + + if (targetItem.PropertyType != sourceItem.PropertyType) + continue; + + memberBindings.Add(Bind(targetItem, sourceProperty)); + } + + //创建一个if条件表达式 + var test = NotEqual(parameter, Constant(null, sourceType));// p==null; + var ifTrue = MemberInit(New(targetType), memberBindings); + var condition = Condition(test, ifTrue, Constant(null, targetType)); + + var lambda = Lambda>(condition, parameter); + return lambda.Compile(); + } + + /// + /// 类型是clas时赋值 + /// + /// + /// + /// + /// + /// + private static Expression GetClassExpression(Expression sourceProperty, Type sourceType, Type targetType) + { + //条件p.Item!=null + var testItem = NotEqual(sourceProperty, Constant(null, sourceType)); + + //构造回调 Mapper.Map() + var mapperType = typeof(Mapper<,>).MakeGenericType(sourceType, targetType); + var iftrue = Call(mapperType.GetMethod(nameof(Map), new[] { sourceType }), sourceProperty); + + var conditionItem = Condition(testItem, iftrue, Constant(null, targetType)); + + return conditionItem; + } + + /// + /// 类型为集合时赋值 + /// + /// + /// + /// + /// + /// + private static Expression GetListExpression(Expression sourceProperty, Type sourceType, Type targetType) + { + //条件p.Item!=null + var testItem = NotEqual(sourceProperty, Constant(null, sourceType)); + + //构造回调 Mapper.MapList() + var sourceArg = sourceType.IsArray ? sourceType.GetElementType() : sourceType.GetGenericArguments()[0]; + var targetArg = targetType.IsArray ? targetType.GetElementType() : targetType.GetGenericArguments()[0]; + var mapperType = typeof(Mapper<,>).MakeGenericType(sourceArg, targetArg); + + var mapperExecMap = Call(mapperType.GetMethod(nameof(MapList), new[] { sourceType }), sourceProperty); + + Expression iftrue; + if (targetType == mapperExecMap.Type) + { + iftrue = mapperExecMap; + } + else if (targetType.IsArray)//数组类型调用ToArray()方法 + { + iftrue = Call(mapperExecMap, mapperExecMap.Type.GetMethod("ToArray")); + } + else if (typeof(IDictionary).IsAssignableFrom(targetType)) + { + iftrue = Constant(null, targetType);//字典类型不转换 + } + else + { + iftrue = Convert(mapperExecMap, targetType); + } + + var conditionItem = Condition(testItem, iftrue, Constant(null, targetType)); + + return conditionItem; + } + + private static Action GetMapAction() + { + var sourceType = typeof(TSource); + var targetType = typeof(TTarget); + //Func委托传入变量 + var sourceParameter = Parameter(sourceType, "p"); + + var targetParameter = Parameter(targetType, "t"); + + //创建一个表达式集合 + var expressions = new List(); + + var targetTypes = targetType.GetProperties().Where(x => x.PropertyType.IsPublic && x.CanWrite); + foreach (var targetItem in targetTypes) + { + var sourceItem = sourceType.GetProperty(targetItem.Name); + + //判断实体的读写权限 + if (sourceItem == null || !sourceItem.CanRead || sourceItem.PropertyType.IsNotPublic) + continue; + + //标注NotMapped特性的属性忽略转换 + if (sourceItem.GetCustomAttribute() != null) + continue; + + var sourceProperty = Property(sourceParameter, sourceItem); + var targetProperty = Property(targetParameter, targetItem); + + //当非值类型且类型不相同时 + if (!sourceItem.PropertyType.IsValueType && sourceItem.PropertyType != targetItem.PropertyType) + { + //判断都是(非泛型)class + if (sourceItem.PropertyType.IsClass && targetItem.PropertyType.IsClass && + !sourceItem.PropertyType.IsGenericType && !targetItem.PropertyType.IsGenericType) + { + var expression = GetClassExpression(sourceProperty, sourceItem.PropertyType, targetItem.PropertyType); + expressions.Add(Assign(targetProperty, expression)); + } + + //集合数组类型的转换 + if (typeof(IEnumerable).IsAssignableFrom(sourceItem.PropertyType) && typeof(IEnumerable).IsAssignableFrom(targetItem.PropertyType)) + { + var expression = GetListExpression(sourceProperty, sourceItem.PropertyType, targetItem.PropertyType); + expressions.Add(Assign(targetProperty, expression)); + } + + continue; + } + + if (targetItem.PropertyType != sourceItem.PropertyType) + continue; + + + expressions.Add(Assign(targetProperty, sourceProperty)); + } + + //当Target!=null判断source是否为空 + var testSource = NotEqual(sourceParameter, Constant(null, sourceType)); + var ifTrueSource = Block(expressions); + var conditionSource = IfThen(testSource, ifTrueSource); + + //判断target是否为空 + var testTarget = NotEqual(targetParameter, Constant(null, targetType)); + var conditionTarget = IfThen(testTarget, conditionSource); + + var lambda = Lambda>(conditionTarget, sourceParameter, targetParameter); + return lambda.Compile(); + } +} diff --git a/Vampirewal.Core.Mapper/Vampirewal.Core.Mapper.csproj b/Vampirewal.Core.Mapper/Vampirewal.Core.Mapper.csproj new file mode 100644 index 0000000000000000000000000000000000000000..132c02c59c23649c0b1ecd3906af6a82a3852d7a --- /dev/null +++ b/Vampirewal.Core.Mapper/Vampirewal.Core.Mapper.csproj @@ -0,0 +1,9 @@ + + + + net6.0 + enable + enable + + + diff --git a/Vampirewal.Core/SystemDataContext.cs b/Vampirewal.Core.Mapper/VampirewalMapperAttribute.cs similarity index 40% rename from Vampirewal.Core/SystemDataContext.cs rename to Vampirewal.Core.Mapper/VampirewalMapperAttribute.cs index d697253fd461fad87f9b1730342d11da65f84a45..ba88394211c9323768cd2c9762de48931f2ba791 100644 --- a/Vampirewal.Core/SystemDataContext.cs +++ b/Vampirewal.Core.Mapper/VampirewalMapperAttribute.cs @@ -1,13 +1,15 @@ -#region << 文 件 说 明 >> + +#region 文件信息 /*---------------------------------------------------------------- -// 文件名称:SystemDataContext -// 创 建 者:杨程 -// 创建时间:2021/9/24 10:26:15 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// +// +// 文件名称: +// 文件功能描述: +// 设计要求: // +// 文 件 名: VampirewalMapperAttribute +// 创建者: 杨程 +// 创建日期: 2022/10/24 17:15:39 + //----------------------------------------------------------------*/ #endregion @@ -16,19 +18,33 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using Vampirewal.Core.Models; -namespace Vampirewal.Core + + +namespace Vampirewal.Core.Mapper { - public class SystemDataContext:BaseSingleton + /// + /// 类型映射特性 + /// + [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] + public class VampirewalMapperAttribute: Attribute { /// - /// 当前登陆用户 + /// /// - public LoginUserInfo loginUserInfo { get; set; } + public VampirewalMapperAttribute(Type target) + { + //构造函数 + Target=target; + } - #region 属性 + + #region 属性 + /// + /// 目标类型 + /// + public Type Target { get; set; } #endregion #region 公共方法 @@ -39,8 +55,11 @@ namespace Vampirewal.Core #endregion - #region 命令 + #region Command命令 #endregion } + + + } diff --git a/Vampirewal.Core/Models/TreeBaseModel.cs b/Vampirewal.Core.OperationExcelService/ExportExcelPropertyAttribute.cs similarity index 39% rename from Vampirewal.Core/Models/TreeBaseModel.cs rename to Vampirewal.Core.OperationExcelService/ExportExcelPropertyAttribute.cs index e3bcc145962d8af140e89ca2c74619935962a7fd..36ad382ae1bdede0f1142df2dc30ecc88070dc1b 100644 --- a/Vampirewal.Core/Models/TreeBaseModel.cs +++ b/Vampirewal.Core.OperationExcelService/ExportExcelPropertyAttribute.cs @@ -1,8 +1,8 @@ #region << 文 件 说 明 >> /*---------------------------------------------------------------- -// 文件名称:TreeBaseModel +// 文件名称:ExportExcelPropertyAttribute // 创 建 者:杨程 -// 创建时间:2021/8/12 15:44:47 +// 创建时间:2022/2/11 19:16:22 // 文件版本:V1.0.0 // =============================================================== // 功能描述: @@ -13,58 +13,44 @@ using System; using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; using System.Linq; using System.Text; -using System.Text.Json.Serialization; using System.Threading.Tasks; -namespace Vampirewal.Core.Models +namespace Vampirewal.Core.OperationExcelService { /// - /// 树形model基类 + /// 是否能导出Excel /// - /// 需要使用到树形的model - public class TreeBaseModel : TopBaseModel + [AttributeUsage(AttributeTargets.Property)] + public sealed class ExportExcelAttribute : Attribute { /// - /// 构造函数 + /// 是否能 /// - public TreeBaseModel() - { - Childs = new ObservableCollection(); - } + public bool IsCanExport { get; set; } - private string _ParentId; /// - /// 父ID + /// 属性导出中文名 /// - public string ParentId { get => _ParentId; set { _ParentId = value; DoNotify(); } } - /// - /// 父类 - /// - //[JsonIgnore] - //public T Parent { get; set; } + public string PropertyChineseName { get; set; } /// - /// 子集 + /// 中文名对应的属性名称 /// - [InverseProperty("Parent")] - [NotMapped] - public ObservableCollection Childs { get; set; } + public string PropertyName { get; set; } /// - /// 是否存在子项 + /// 构造函数 /// - [NotMapped] - public bool HasChildren + /// 属性导出中文名 + /// 中文名对应的属性名称 + /// 是否能导出 + public ExportExcelAttribute(string propertyChineseName, string propertyName, bool isCanExport = true) { - get - { - return Childs?.Any() == true; - } + IsCanExport = isCanExport; + PropertyChineseName = propertyChineseName; + PropertyName = propertyName; } } } diff --git a/Vampirewal.Core.OperationExcelService/IVampirewalOperationExcelService.cs b/Vampirewal.Core.OperationExcelService/IVampirewalOperationExcelService.cs new file mode 100644 index 0000000000000000000000000000000000000000..73469886f967f7e5a94342141bbf15e7187b94a1 --- /dev/null +++ b/Vampirewal.Core.OperationExcelService/IVampirewalOperationExcelService.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Data; + +namespace Vampirewal.Core.OperationExcelService +{ + /// + /// 操作Excel服务接口 + /// + /// + public interface IVampirewalOperationExcelService + { + + ///// + ///// 保存Excel文件名 + ///// + //string SaveFileName { get; } + + ///// + ///// Excel文件保存地址 + ///// + //string SaveFilePath { get; } + + ///// + ///// Excel类型 + ///// + //ExcelType excelType { get; } + + ///// + ///// 设置 + ///// + ///// 设置保存文件的文件名 + ///// 设置保存文件的路径 + ///// 设置excel类型 + //void Setting(string saveFileName, string saveFilePath, ExcelType type); + + /// + /// 执行导出 + /// + /// 实体类型 + /// 导出数据源 + /// + public void ExportDataToExcel(List EntityList, string SaveFilePath, ExcelType excelType) where T : class, new(); + + /// + /// 将excel中的数据导入到DataTable中 + /// + /// /// 表名 + /// 第一行是否是DataTable的列名 + /// 文件完整路径 + /// 返回的DataTable + DataTable ExcelToDataTable(string sheetName, bool isFirstRowColumn, string FileFullPath); + + /// + /// 导入EXCEL文件转成List + /// + /// + /// 第一行是否是DataTable的列名 + /// 文件完整路径 + /// + List ExcelToList(bool isFirstRowColumn, string FileFullPath); + } +} diff --git a/Vampirewal.Core.OperationExcelService/LICENSE b/Vampirewal.Core.OperationExcelService/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..ddbd00b437e877e43b09521e47a65ad43f04aa8a --- /dev/null +++ b/Vampirewal.Core.OperationExcelService/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 vampirewal + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Vampirewal.Core.OperationExcelService/Vampirewal-Logo.png b/Vampirewal.Core.OperationExcelService/Vampirewal-Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..3d150ba56db89235caebb1676f05415ddc65740d Binary files /dev/null and b/Vampirewal.Core.OperationExcelService/Vampirewal-Logo.png differ diff --git a/Vampirewal.Core.OperationExcelService/Vampirewal.Core.OperationExcelService.csproj b/Vampirewal.Core.OperationExcelService/Vampirewal.Core.OperationExcelService.csproj new file mode 100644 index 0000000000000000000000000000000000000000..e74e2cac1b142e53f8123fe8139e1fb7a79b1992 --- /dev/null +++ b/Vampirewal.Core.OperationExcelService/Vampirewal.Core.OperationExcelService.csproj @@ -0,0 +1,34 @@ + + + + net5.0 + True + vampirewal + 1.0.0.1 + Vampirewal.Core中操作excel的组件 + Vampirewal-Logo.png + LICENSE + True + + + + + + + + + + + + + + + + + + \ + True + + + + diff --git a/Vampirewal.Core.OperationExcelService/VampirewalExportExcelService.cs b/Vampirewal.Core.OperationExcelService/VampirewalExportExcelService.cs new file mode 100644 index 0000000000000000000000000000000000000000..bd7cb4eb1137e7df4ea969ec79c2d476870edb7b --- /dev/null +++ b/Vampirewal.Core.OperationExcelService/VampirewalExportExcelService.cs @@ -0,0 +1,383 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:VampirewalExportExcelService +// 创 建 者:杨程 +// 创建时间:2022/2/11 9:56:59 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + +using NPOI.HSSF.UserModel; +using NPOI.SS.UserModel; +using NPOI.XSSF.UserModel; +using System; +using System.Collections.Generic; +using System.Data; +using System.IO; +using System.Linq; +using System.Reflection; + +namespace Vampirewal.Core.OperationExcelService +{ + /// + /// Excel类型 + /// + public enum ExcelType + { + + xlsx = 0, + xls = 1 + } + /// + /// Vampirewal操作Excel服务 + /// + public sealed class VampirewalOperationExcelService : IVampirewalOperationExcelService + { + /// + /// 执行导出 + /// + /// 实体类型 + /// 导出数据源 + /// + public void ExportDataToExcel(List EntityList, string SaveFilePath, ExcelType excelType) where T : class, new() + { + try + { + if (EntityList == null) + { + throw new Exception("导出Excel文件的数据源不能为空!"); + } + + Type type = typeof(T); + + if (string.IsNullOrEmpty(SaveFilePath)) + { + SaveFilePath = AppDomain.CurrentDomain.BaseDirectory; + } + //if (string.IsNullOrEmpty(SaveFileName)) + //{ + // throw new Exception("导出Excel文件的文件名称不能为空!"); + //} + + var dt = ToDataTable(EntityList); + + switch (excelType) + { + case ExcelType.xlsx: + var sfn = type.Name + ".xlsx"; + + SaveFilePath += sfn; + break; + case ExcelType.xls: + var sfn2 = type.Name + ".xlsx"; + + SaveFilePath += sfn2; + break; + } + + //NPOI + IWorkbook workbook; + string FileExt = Path.GetExtension(SaveFilePath).ToLower(); + if (FileExt == ".xlsx") + { + workbook = new XSSFWorkbook(); + } + else if (FileExt == ".xls") + { + workbook = new HSSFWorkbook(); + } + else + { + workbook = null; + } + if (workbook == null) + { + return; + } + //ISheet sheet = string.IsNullOrEmpty(SaveFileName) ? workbook.CreateSheet("Sheet1") : workbook.CreateSheet(SaveFileName); + ISheet sheet = workbook.CreateSheet(type.Name); + + + //读取标题 + IRow rowHeader = sheet.CreateRow(0); + for (int i = 0; i < dt.Columns.Count; i++) + { + ICell cell = rowHeader.CreateCell(i); + cell.SetCellValue(dt.Columns[i].ColumnName); + } + + //读取数据 + for (int i = 0; i < dt.Rows.Count; i++) + { + IRow rowData = sheet.CreateRow(i + 1); + for (int j = 0; j < dt.Columns.Count; j++) + { + ICell cell = rowData.CreateCell(j); + cell.SetCellValue(dt.Rows[i][j].ToString()); + } + } + + //转为字节数组 + MemoryStream stream = new MemoryStream(); + workbook.Write(stream); + var buf = stream.ToArray(); + + //保存为Excel文件 + using (FileStream fs = new FileStream(SaveFilePath, FileMode.Create, FileAccess.Write)) + { + fs.Write(buf, 0, buf.Length); + fs.Flush(); + fs.Close(); + } + + + } + catch (Exception ex) + { + throw; + } + finally + { + + } + + + } + + + /// + /// 将excel中的数据导入到DataTable中 + /// + /// 表名 + /// 第一行是否是DataTable的列名 + /// 文件完整路径 + /// 返回的DataTable + public DataTable ExcelToDataTable(string sheetName, bool isFirstRowColumn, string FileFullPath) + { + //if (string.IsNullOrEmpty(sheetName)) + //{ + // throw new ArgumentNullException(sheetName); + //} + if (string.IsNullOrEmpty(FileFullPath)) + { + throw new ArgumentNullException(FileFullPath); + } + var data = new DataTable(); + IWorkbook workbook = null; + FileStream fs = null; + try + { + fs = new FileStream(FileFullPath, FileMode.Open, FileAccess.Read); + if (FileFullPath.IndexOf(".xlsx", StringComparison.Ordinal) > 0) + { + workbook = new XSSFWorkbook(fs); + } + else if (FileFullPath.IndexOf(".xls", StringComparison.Ordinal) > 0) + { + workbook = new HSSFWorkbook(fs); + } + + ISheet sheet = null; + if (workbook != null) + { + //如果没有找到指定的sheetName对应的sheet,则尝试获取第一个sheet + sheet = workbook.GetSheet(sheetName) ?? workbook.GetSheetAt(0); + } + if (sheet == null) return data; + var firstRow = sheet.GetRow(0); + //一行最后一个cell的编号 即总的列数 + int cellCount = firstRow.LastCellNum; + int startRow; + if (isFirstRowColumn) + { + for (int i = firstRow.FirstCellNum; i < cellCount; ++i) + { + var cell = firstRow.GetCell(i); + var cellValue = cell.StringCellValue; + if (cellValue == null) continue; + var column = new DataColumn(cellValue); + data.Columns.Add(column); + } + startRow = sheet.FirstRowNum + 1; + } + else + { + startRow = sheet.FirstRowNum; + } + //最后一列的标号 + var rowCount = sheet.LastRowNum; + for (var i = startRow; i <= rowCount; ++i) + { + var row = sheet.GetRow(i); + //没有数据的行默认是null + if (row == null) continue; + var dataRow = data.NewRow(); + for (int j = row.FirstCellNum; j < cellCount; ++j) + { + //同理,没有数据的单元格都默认是null + if (row.GetCell(j) != null) + dataRow[j] = row.GetCell(j).ToString(); + } + data.Rows.Add(dataRow); + } + + return data; + } + catch (IOException ioex) + { + throw new IOException(ioex.Message); + } + catch (Exception ex) + { + throw new Exception(ex.Message); + } + finally + { + if (fs != null) + { + fs.Close(); + } + } + } + + + /// + /// 导入EXCEL文件转成List + /// + /// + /// 第一行是否是DataTable的列名 + /// 文件完整路径 + /// + public List ExcelToList(bool isFirstRowColumn, string FileFullPath) + { + Type type = typeof(T); + + return DataTableToList(ExcelToDataTable(type.Name, isFirstRowColumn, FileFullPath)); + } + + /// + /// List转DataTable + /// 仅适用于导出excel的数据,且对应实体类的属性上有特性 + /// + private DataTable ToDataTable(List items) + { + var tb = new DataTable(typeof(T).Name); + + PropertyInfo[] props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance); + + var clone = props.Clone(); + var cur = new List(); + + foreach (var item in clone as PropertyInfo[]) + { + var export = item.GetCustomAttribute(); + + if (export != null && export.IsCanExport) + { + tb.Columns.Add(export.PropertyChineseName, item.PropertyType); + cur.Add(item); + } + } + + foreach (T item in items) + { + var values = new object[cur.Count]; + + for (int i = 0; i < cur.Count; i++) + { + values[i] = cur[i].GetValue(item, null); + } + + tb.Rows.Add(values); + } + + return tb; + } + + /// + /// DataTable转List + /// 仅适用于excel导入的数据,且对应实体类的属性上有特性 + /// + /// + /// + /// + /// + private List DataTableToList(DataTable dt) + { + var list = new List(); + var plist = new List(typeof(T).GetProperties()); + foreach (DataRow item in dt.Rows) + { + if (item.ItemArray[0] is DBNull) + continue; + + T s = Activator.CreateInstance(); + for (int i = 0; i < dt.Columns.Count; i++) + { + //PropertyInfo info = plist.Find(p => p.Name == dt.Columns[i].ColumnName); + + PropertyInfo info = null; + + foreach (var Prop in plist) + { + var customAttributes = Prop.GetCustomAttributes(typeof(ExportExcelAttribute), false).ToList(); + + foreach (var attribute in customAttributes) + { + if (attribute is ExportExcelAttribute export) + { + if (export.PropertyChineseName == dt.Columns[i].ColumnName) + { + info = Prop; + continue; + } + } + } + + if (info != null) + { + continue; + } + } + + if (info != null) + { + try + { + if (!Convert.IsDBNull(item[i])) + { + object v = null; + if (info.PropertyType.ToString().Contains("System.Nullable")) + { + v = Convert.ChangeType(item[i], Nullable.GetUnderlyingType(info.PropertyType)); + } + else if (info.PropertyType.IsEnum) + { + //int enumInt = Convert.ToInt32(item[i]); + + v = Enum.Parse(info.PropertyType, item[i].ToString()); + } + else + { + v = Convert.ChangeType(item[i], info.PropertyType); + } + + info.SetValue(s, v, null); + } + } + catch (Exception ex) + { + throw new Exception("字段[" + info.Name + "]转换出错," + ex.Message); + } + } + } + list.Add(s); + } + return list; + } + } +} diff --git a/Vampirewal.Core.SourceGeneratorMvvm/Generators/AopProxyGenerator.cs b/Vampirewal.Core.SourceGeneratorMvvm/Generators/AopProxyGenerator.cs new file mode 100644 index 0000000000000000000000000000000000000000..a7e4eb58406f2c63fbfcca6983b3a231a920e225 --- /dev/null +++ b/Vampirewal.Core.SourceGeneratorMvvm/Generators/AopProxyGenerator.cs @@ -0,0 +1,235 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: AopProxyGenerator +// 创建者: 杨程 +// 创建日期: 2023/2/14 12:48:40 + +//----------------------------------------------------------------*/ +#endregion + +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis; +using System; +using System.Collections.Generic; +using System.Text; +using System.Diagnostics; +using System.Linq; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Text; + +namespace Vampirewal.Core.SourceGeneratorMvvm.Generators; + +public class AopProxySyntaxReceiver : ISyntaxReceiver +{ + public List CandidateClasses { get; } = new List(); + public void OnVisitSyntaxNode(SyntaxNode syntaxNode) + { + if (syntaxNode is AttributeSyntax cds && cds.Name is IdentifierNameSyntax identifierName && identifierName.Identifier.ValueText == "GeneratorAopProxy") + { + CandidateClasses.Add(cds); + } + + //if (syntaxNode is ClassDeclarationSyntax cds1 && cds1.BaseList != null && cds1.BaseList.Types.Where(w => ((IdentifierNameSyntax)w.Type).Identifier.ValueText == "AopBase").Count() > 0) + //{ + + // var aaa = cds1.BaseList; + + // var bbb = (aaa.Parent as ClassDeclarationSyntax); + + // var ccc = aaa.Types; + + + // //ccc.FirstOrDefault(f => f.Typ) + + // foreach (var item in ccc) + // { + // var aaaa = item.Type; + + // var asd = (aaaa as IdentifierNameSyntax).Identifier.ValueText; + + // var str = aaaa.GetText(); + // } + //} + + + } +} + +/// +/// +/// +[Generator] +public partial class AopProxyGenerator : ISourceGenerator +{ + public void Execute(GeneratorExecutionContext context) + { + var syntaxReceiver = (AopProxySyntaxReceiver)context.SyntaxReceiver; + var attributeSyntaxList = syntaxReceiver.CandidateClasses; + + if (attributeSyntaxList.Count == 0) + { + return; + } + + List ClassName = new List(); + + foreach (AttributeSyntax attributeSyntax in attributeSyntaxList) + { + // 找到class,并且判断一下是否有parital字段 + var classDeclarationSyntax = attributeSyntax.FirstAncestorOrSelf(); + if (classDeclarationSyntax == null || !classDeclarationSyntax.Modifiers.Any(m => m.IsKind(SyntaxKind.PartialKeyword))) + { + continue; + } + + //判断是否已经处理过这个class了 + if (ClassName.Contains(classDeclarationSyntax.Identifier.ValueText)) + { + continue; + } + + // 找到namespace + var namespaceDeclarationSyntax = classDeclarationSyntax.FirstAncestorOrSelf(); + + + // 找到methods + var methodDeclarationList = classDeclarationSyntax.Members.OfType().ToList(); + if (methodDeclarationList.Count == 0) + { + continue; + } + + StringBuilder sb = new StringBuilder(); + + sb.AppendLine("using Vampirewal.Core.SimpleMVVM;"); + sb.AppendLine("using Vampirewal.Core.Attributes;"); + sb.AppendLine("using System.Reflection;"); + sb.AppendLine(); + + sb.AppendLine($"namespace {namespaceDeclarationSyntax.Name}"); + sb.AppendLine("{"); + + sb.AppendLine($" public partial class {classDeclarationSyntax.Identifier.Text}"); + sb.AppendLine(" {"); + + foreach (MethodDeclarationSyntax methodDeclaration in methodDeclarationList) + { + //判断一下是否包含AOP结尾的特性 + if (!SyntaxUtils.HasAopAttribute(methodDeclaration, out AttributeSyntax AopAttribute)) + { + continue; + } + + var AopAttributeName = (AopAttribute.Name as IdentifierNameSyntax).Identifier.ValueText; + + //获取方法的返回值字符串 + var ReturnTypeStr = (methodDeclaration.ReturnType as PredefinedTypeSyntax).Keyword.ValueText; + + //获取方法内的参数 + var ParameterList = methodDeclaration.ParameterList.Parameters; + + //var asd= ParameterList.Select(s => $"{s.ToFullString().Split(' ')[1]}").ToList(); + + sb.AppendLine("/// "); + sb.AppendLine($"/// {methodDeclaration.Identifier.Text}的AOP代理方法"); + sb.AppendLine($"/// 多个AOP特性均会执行"); + sb.AppendLine("/// "); + sb.AppendLine($"public {ReturnTypeStr} {methodDeclaration.Identifier.Text}_Proxy ({string.Join(",", ParameterList.Select(s => $"{s.ToFullString()}"))})"); + sb.AppendLine("{"); + + + if (ReturnTypeStr != "void") + { + sb.AppendLine($"return ({ReturnTypeStr})ExcuteProxy(\"{ methodDeclaration.Identifier.Text}\",{string.Join(",", ParameterList.Select(s => $"{s.ToFullString().Split(' ')[1]}"))});"); + } + else + { + sb.AppendLine($"ExcuteProxy(\"{methodDeclaration.Identifier.Text}\",{string.Join(",", ParameterList.Select(s => $"{s.ToFullString().Split(' ')[1]}"))});"); + } + + + sb.AppendLine("}"); + } + + sb.AppendLine("/// "); + sb.AppendLine("/// 执行代理方法"); + sb.AppendLine("/// "); + sb.AppendLine($@" + + +private object ExcuteProxy(string MethodName,params object[] args) + {{ + object result = null; + + var method = this.GetType().GetMethod(MethodName); + object[]? attrs = method.GetCustomAttributes(true); + + foreach (var item in attrs) + {{ + if (item is AopBaseAttribute aop) + {{ + AopMethod aopMethod = new AopMethod(this, method, args); + Exception ex = null; + try + {{ + if (aop.Location == InvokeLocation.Before) + {{ + aop.ExcuteBefore(); + }} + + if (aop.Location == InvokeLocation.Both) + {{ + aop.ExcuteMiddle(aopMethod); + }} + }} + catch (Exception exx) + {{ + ex=exx; + }} + + if (aopMethod.ReturnValue is Task) + {{ + (aopMethod.ReturnValue as Task).ContinueWith((Task t) => + {{ + aop.ExcuteAfter(aopMethod, t.Exception); + }}); + }} + else + {{ + aop.ExcuteAfter(aopMethod, ex); + }} + + result = aopMethod.ReturnValue; + }} + }} + + return result; + }} +"); + + sb.AppendLine(" }"); + sb.AppendLine("}"); + + string extensionTextFormatted = CSharpSyntaxTree.ParseText(sb.ToString(), new CSharpParseOptions(LanguageVersion.CSharp8)).GetRoot().NormalizeWhitespace().SyntaxTree.GetText().ToString(); + // 添加到源代码,这样IDE才能感知 + context.AddSource($"{classDeclarationSyntax.Identifier}.g.cs", SourceText.From(extensionTextFormatted, Encoding.UTF8)); + // 保存一下类名,避免重复生成 + ClassName.Add(classDeclarationSyntax.Identifier.ValueText); + } + } + + public void Initialize(GeneratorInitializationContext context) + { +#if DEBUG + //Debugger.Launch(); +#endif + + context.RegisterForSyntaxNotifications(() => new AopProxySyntaxReceiver()); + } +} diff --git a/Vampirewal.Core.SourceGeneratorMvvm/Generators/AttributeGenerator.cs b/Vampirewal.Core.SourceGeneratorMvvm/Generators/AttributeGenerator.cs new file mode 100644 index 0000000000000000000000000000000000000000..9c62485e0c88af656c796eb5c6b4751f058d02eb --- /dev/null +++ b/Vampirewal.Core.SourceGeneratorMvvm/Generators/AttributeGenerator.cs @@ -0,0 +1,55 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: AttributeGenerator +// 创建者: 杨程 +// 创建日期: 2023/2/6 14:03:01 + +//----------------------------------------------------------------*/ +#endregion + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Text; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; + +namespace Vampirewal.Core.SourceGeneratorMvvm.Generators; + +/// +/// +/// +[Generator] +public partial class AttributeGenerator : ISourceGenerator +{ + + public void Execute(GeneratorExecutionContext context) + { + Dictionary attributes = new Dictionary(); + attributes.Add("DoNotifyPropertyAttrubite", Utils.GetTemplateByFileName("AttributeTemplate.DoNotifyPropertyAttributeStr.txt")); + attributes.Add("GeneratorDTOAttribute", Utils.GetTemplateByFileName("AttributeTemplate.GeneratorDTOStr.txt")); + attributes.Add("RelayCommandAttribute", Utils.GetTemplateByFileName("AttributeTemplate.RelayCommandStr.txt")); + attributes.Add("DtoIgnoreAttribute", Utils.GetTemplateByFileName("AttributeTemplate.DtoIgnoreAttributeStr.txt")); + attributes.Add("AopBaseAttribute", Utils.GetTemplateByFileName("AttributeTemplate.AopBaseAttribute.txt")); + attributes.Add("GeneratorAopProxy", Utils.GetTemplateByFileName("AttributeTemplate.GeneratorAopProxy.txt")); + + + foreach (var item in attributes) + { + context.AddSource(item.Key, SourceText.From(item.Value, Encoding.UTF8)); + } + } + + public void Initialize(GeneratorInitializationContext context) + { +#if DEBUG + //Debugger.Launch(); +#endif + } +} diff --git a/Vampirewal.Core.SourceGeneratorMvvm/Generators/BaseCodeGenerator.cs b/Vampirewal.Core.SourceGeneratorMvvm/Generators/BaseCodeGenerator.cs new file mode 100644 index 0000000000000000000000000000000000000000..74f2cb2b330453115c4b7c63cab85cc037540e6f --- /dev/null +++ b/Vampirewal.Core.SourceGeneratorMvvm/Generators/BaseCodeGenerator.cs @@ -0,0 +1,49 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: BaseCodeGenerator +// 创建者: 杨程 +// 创建日期: 2023/2/6 16:59:38 + +//----------------------------------------------------------------*/ +#endregion + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Text; +using System; +using System.Collections.Generic; +using System.Text; + + + +namespace Vampirewal.Core.SourceGeneratorMvvm.Generators; + +/// +/// 基础代码生成器 +/// +[Generator] +public partial class BaseCodeGenerator : ISourceGenerator +{ + public void Execute(GeneratorExecutionContext context) + { + Dictionary attributes = new Dictionary(); + attributes.Add("RelayCommand", Utils.GetTemplateByFileName("RelayCommandTemplate.RelayCommand.txt")); + attributes.Add("NotifyBase", Utils.GetTemplateByFileName("NotifyChangedTemplate.NotifyBase.txt")); + attributes.Add("AopMethod", Utils.GetTemplateByFileName("AopTemplate.AopMethod.txt")); + + foreach (var item in attributes) + { + context.AddSource(item.Key, SourceText.From(item.Value, Encoding.UTF8)); + } + } + + public void Initialize(GeneratorInitializationContext context) + { + + } +} diff --git a/Vampirewal.Core.SourceGeneratorMvvm/Generators/DTOGenerator.cs b/Vampirewal.Core.SourceGeneratorMvvm/Generators/DTOGenerator.cs new file mode 100644 index 0000000000000000000000000000000000000000..519474c95274087a3e2b6e5b40bee76528335b17 --- /dev/null +++ b/Vampirewal.Core.SourceGeneratorMvvm/Generators/DTOGenerator.cs @@ -0,0 +1,267 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: DTOGenerator +// 创建者: 杨程 +// 创建日期: 2023/2/6 15:31:48 + +//----------------------------------------------------------------*/ +#endregion + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Text; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Diagnostics; + +namespace Vampirewal.Core.SourceGeneratorMvvm.Generators; + +public class DtoSyntaxReceiver : ISyntaxReceiver +{ + public List CandidateClasses { get; }=new List(); + + public void OnVisitSyntaxNode(SyntaxNode syntaxNode) + { + //if ((syntaxNode is ClassDeclarationSyntax cds)&&cds.AttributeLists.Count>0&& cds.Identifier.Value is IdentifierNameSyntax identifierName) + //{ + + // CandidateClasses.Add(cds); + //} + + if (syntaxNode is AttributeSyntax cds && cds.Name is IdentifierNameSyntax identifierName && identifierName.Identifier.ValueText == "GeneratorDTO") + { + CandidateClasses.Add(cds); + } + } +} + +/// +/// 生成DTO文件 +/// +[Generator] +public partial class DTOGenerator : ISourceGenerator +{ + public void Execute(GeneratorExecutionContext context) + { + var syntaxReceiver = (DtoSyntaxReceiver)context.SyntaxReceiver; + var attributeSyntaxList = syntaxReceiver.CandidateClasses; + + if (attributeSyntaxList.Count == 0) + { + return; + } + + List ClassName = new List(); + + foreach (AttributeSyntax attributeSyntax in attributeSyntaxList) + { + // 找到class,并且判断一下是否有parital字段 + var classDeclarationSyntax = attributeSyntax.FirstAncestorOrSelf(); + if (classDeclarationSyntax == null ||!classDeclarationSyntax.Modifiers.Any(m => m.IsKind(SyntaxKind.PartialKeyword))) + { + throw new Exception("该类不是Partial"); + //continue; + } + + // 找到namespace + var namespaceDeclarationSyntax = classDeclarationSyntax.FirstAncestorOrSelf(); + if (ClassName.Contains(classDeclarationSyntax.Identifier.ValueText)) + { + continue; + } + + // 找到property + var propertyDeclarationList = classDeclarationSyntax.Members.OfType().ToList(); + if (propertyDeclarationList.Count == 0) + { + continue; + } + + + StringBuilder sb = new StringBuilder(); + + sb.AppendLine("// "); + sb.AppendLine("#pragma warning disable"); + sb.AppendLine("#nullable enable"); + sb.AppendLine(); + sb.AppendLine("using System;"); + //sb.AppendLine("using Newtonsoft.Json;"); + sb.AppendLine(); + sb.AppendLine($"namespace {namespaceDeclarationSyntax.Name.ToString()}"); + sb.AppendLine("{"); + sb.AppendLine($" /// "); + sb.AppendLine($" /// {classDeclarationSyntax.Identifier.Text}的DTO类"); + sb.AppendLine($" /// "); + sb.AppendLine($" public partial class {classDeclarationSyntax.Identifier.Text}DTO"); + sb.AppendLine(" {"); + + #region 生成DTO属性 + foreach (PropertyDeclarationSyntax prop in propertyDeclarationList) + { + //再判断一下属性上是否标记了DtoIgnore特性,没有的话继续,有的话,就不继续了 + if (SyntaxUtils.HasAttribute(prop, "DtoIgnore")) + { + continue; + } + + var type = prop.Type.ToString(); + + var name = prop.Identifier.Text; + + sb.AppendLine(); + sb.AppendLine(" [global::Newtonsoft.Json.JsonProperty(\"" + Utils.ConvertToCamel(name, "_") + "\")]"); + sb.AppendLine($" public {type} {name} " + "{get; set;}"); + sb.AppendLine(); + } + #endregion + + #region 生成转换方法 + sb.AppendLine($" /// "); + sb.AppendLine($" /// 将DTO转成Source类"); + sb.AppendLine($" /// "); + sb.AppendLine($" /// Source类"); + sb.AppendLine($" public {classDeclarationSyntax.Identifier.Text} FromDTO()"); + sb.AppendLine(" {"); + sb.AppendLine($" {classDeclarationSyntax.Identifier.Text} vo=new {classDeclarationSyntax.Identifier.Text}(); "); + + foreach (PropertyDeclarationSyntax prop in propertyDeclarationList) + { + //再判断一下属性上是否标记了DtoIgnore特性,没有的话继续,有的话,就不继续了 + if (SyntaxUtils.HasAttribute(prop, "DtoIgnore")) + { + continue; + } + + sb.AppendLine($" vo.{prop.Identifier.Text}=this.{prop.Identifier.Text};"); + } + sb.AppendLine(" return vo;"); + + sb.AppendLine(" }"); + #endregion + + + sb.AppendLine(" }"); + + sb.AppendLine("}"); + + context.AddSource($"{classDeclarationSyntax.Identifier.Text}DTO.cs", SourceText.From(sb.ToString(), Encoding.UTF8)); + } + + + //var options = (context.Compilation as CSharpCompilation).SyntaxTrees[0].Options as CSharpParseOptions; + //var compilation = context.Compilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(Utils.GetTemplateByFileName("AttributeTemplate.GeneratorDTOStr.txt"), options)); + + //var allNodes = compilation.SyntaxTrees.SelectMany(s => s.GetRoot().DescendantNodes()); + //var allAttributes = allNodes.Where((d) => d.IsKind(SyntaxKind.Attribute)).OfType(); + //var attributes = allAttributes.Where(d => d.Name.ToString() == "GeneratorDTO").ToList(); + + //var allClasses = compilation.SyntaxTrees.SelectMany(x => x.GetRoot().DescendantNodes().OfType()); + + //List ClassName = new List(); + //foreach (AttributeSyntax attr in attributes) + //{ + // var TypeArgSyntax = attr.ArgumentList.Arguments.First(); + // var TypeArgSyntaxExpr = TypeArgSyntax.Expression.NormalizeWhitespace().ToFullString(); + + // //找到CLASS + // var toClassName = Utils.GetContentInParentheses(TypeArgSyntaxExpr); + // if (ClassName.Any(a => a.Equals(toClassName))) + // { + // continue; + // } + // ClassName.Add(toClassName); + + // var toClassSyntax = allClasses.First(x => x.Identifier.ToString() == toClassName); + + // // 找到namespace + // var namespaceDeclarationSyntax = toClassSyntax.FirstAncestorOrSelf(); + + + + // var toClassModel = compilation.GetSemanticModel(toClassSyntax.SyntaxTree); + // var toClassNamedTypeSymbol = ModelExtensions.GetDeclaredSymbol(toClassModel, toClassSyntax); + // var toClassFullName = toClassNamedTypeSymbol.OriginalDefinition.ToString(); + + // // 找到field + // var propertyDeclarationList = toClassSyntax.Members.OfType().ToList(); + + // StringBuilder sb = new StringBuilder(); + + // sb.AppendLine("using System;"); + // //sb.AppendLine("using Newtonsoft.Json;"); + // sb.AppendLine(); + // sb.AppendLine($"namespace {namespaceDeclarationSyntax.Name.ToString()}"); + // sb.AppendLine("{"); + // sb.AppendLine($" /// "); + // sb.AppendLine($" /// {toClassSyntax.Identifier.Text}的DTO类"); + // sb.AppendLine($" /// "); + // sb.AppendLine($" public partial class {toClassSyntax.Identifier.Text}DTO"); + // sb.AppendLine(" {"); + + + + // if(propertyDeclarationList.Count == 0) + // { + // sb.AppendLine($" // 原始类中不包含属性!"); + // } + + // //[JsonProperty("")] + // foreach (PropertyDeclarationSyntax prop in propertyDeclarationList) + // { + // var type = prop.Type.ToString(); + + // var name = prop.Identifier.Text; + + + // sb.AppendLine(); + // sb.AppendLine(" [global::Newtonsoft.Json.JsonProperty(\"" + Utils.ConvertToCamel(name, "_") + "\")]"); + // sb.AppendLine($" public {type} {name} " + "{get; set;}"); + // sb.AppendLine(); + + // } + // sb.AppendLine(" }"); + + + + // sb.AppendLine("}"); + + // context.AddSource($"{toClassSyntax.Identifier.Text}.g.cs", SourceText.From(sb.ToString(), Encoding.UTF8)); + //} + } + + public void Initialize(GeneratorInitializationContext context) + { +#if DEBUG + //Debugger.Launch(); +#endif + + context.RegisterForSyntaxNotifications(() => new DtoSyntaxReceiver()); + } +} + +internal class ClassModel +{ + public string Namespace { get; set; } + + public string Class { get; set; } + + public List Fields { get; set; } + public List Usings { get; set; } +} + +internal class Field +{ + public string Type { get; set; } + + public string Name { get; set; } + public bool IsOptions { get; set; } +} diff --git a/Vampirewal.Core.SourceGeneratorMvvm/Generators/DoNotifyGenerator.cs b/Vampirewal.Core.SourceGeneratorMvvm/Generators/DoNotifyGenerator.cs new file mode 100644 index 0000000000000000000000000000000000000000..b1e186b7e6c53a862cc047bf6adb186438e853d2 --- /dev/null +++ b/Vampirewal.Core.SourceGeneratorMvvm/Generators/DoNotifyGenerator.cs @@ -0,0 +1,143 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: DoNotifyGenerator +// 创建者: 杨程 +// 创建日期: 2023/2/7 14:12:14 + +//----------------------------------------------------------------*/ +#endregion + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Text; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + + + +namespace Vampirewal.Core.SourceGeneratorMvvm.Generators; + +public class DoNotifySyntaxReceiver : ISyntaxReceiver +{ + public List CandidateClasses { get; } = new List(); + public void OnVisitSyntaxNode(SyntaxNode syntaxNode) + { + if (syntaxNode is AttributeSyntax cds && cds.Name is IdentifierNameSyntax identifierName && identifierName.Identifier.ValueText == "DoNotifyProperty") + { + CandidateClasses.Add(cds); + } + } +} + +/// +/// +/// +[Generator] +public partial class DoNotifyGenerator : ISourceGenerator +{ + public void Execute(GeneratorExecutionContext context) + { + var syntaxReceiver = (DoNotifySyntaxReceiver)context.SyntaxReceiver; + var attributeSyntaxList = syntaxReceiver.CandidateClasses; + + if (attributeSyntaxList.Count == 0) + { + return; + } + + List ClassName = new List(); + + foreach (var attributeSyntax in attributeSyntaxList) + { + + + // 找到class,并且判断一下是否有parital字段 + var classDeclarationSyntax = attributeSyntax.FirstAncestorOrSelf(); + if (classDeclarationSyntax == null || !classDeclarationSyntax.Modifiers.Any(m => m.IsKind(SyntaxKind.PartialKeyword))) + { + continue; + } + + //classDeclarationSyntax.BaseList + + // 找到namespace + var namespaceDeclarationSyntax = classDeclarationSyntax.FirstAncestorOrSelf(); + if (ClassName.Contains(classDeclarationSyntax.Identifier.ValueText)) + { + continue; + } + + // 找到field + var fieldDeclarationList = classDeclarationSyntax.Members.OfType().ToList(); + if (fieldDeclarationList.Count == 0) + { + continue; + } + + ClassName.Add(classDeclarationSyntax.Identifier.ValueText); + + StringBuilder sb = new StringBuilder(); + + sb.AppendLine("// "); + sb.AppendLine("#pragma warning disable"); + sb.AppendLine("#nullable enable"); + sb.AppendLine(); + sb.AppendLine($"namespace {namespaceDeclarationSyntax.Name.ToString()}"); + sb.AppendLine("{"); + sb.AppendLine($" public partial class {classDeclarationSyntax.Identifier.Text}"); + sb.AppendLine(" {"); + + foreach (var field in fieldDeclarationList) + { + var type = field.Declaration.Type.ToString(); + + + + foreach (var declarationVariable in field.Declaration.Variables) + { + var name = SyntaxUtils.GetName(declarationVariable); + + var propertyName = Utils.ConvertToPascal(name, ""); + + sb.AppendLine(); + sb.AppendLine($" public {type} {propertyName} "); + sb.AppendLine(" {"); + sb.AppendLine(" get"); + sb.AppendLine(" {"); + sb.AppendLine($" return {name};"); + sb.AppendLine(" }"); + sb.AppendLine(" set"); + sb.AppendLine(" {"); + sb.AppendLine($" {name}=value;"); + sb.AppendLine($" DoNotify();"); + sb.AppendLine(" }"); + sb.AppendLine(" }"); + sb.AppendLine(); + } + } + + sb.AppendLine(" }"); + sb.AppendLine("}"); + + context.AddSource($"{classDeclarationSyntax.Identifier.Text}.g.cs", SourceText.From(sb.ToString(), Encoding.UTF8)); + } + } + + public void Initialize(GeneratorInitializationContext context) + { +#if DEBUG + //Debugger.Launch(); +#endif + + context.RegisterForSyntaxNotifications(() => new DoNotifySyntaxReceiver()); + } +} diff --git a/Vampirewal.Core.SourceGeneratorMvvm/Generators/RelayCommandGenerator.cs b/Vampirewal.Core.SourceGeneratorMvvm/Generators/RelayCommandGenerator.cs new file mode 100644 index 0000000000000000000000000000000000000000..a70f92f75dd4b8756d6231ca06627c285876445a --- /dev/null +++ b/Vampirewal.Core.SourceGeneratorMvvm/Generators/RelayCommandGenerator.cs @@ -0,0 +1,245 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: RelayCommandGenerator +// 创建者: 杨程 +// 创建日期: 2023/2/6 16:54:01 + +//----------------------------------------------------------------*/ +#endregion + +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Diagnostics; +using Microsoft.CodeAnalysis.Text; + +namespace Vampirewal.Core.SourceGeneratorMvvm.Generators; + +/// +/// +/// +[Generator] +public partial class RelayCommandGenerator : ISourceGenerator +{ + public void Execute(GeneratorExecutionContext context) + { + var syntaxReceiver = (RelayCommandSyntaxReceiver)context.SyntaxReceiver; + var attributeSyntaxList = syntaxReceiver.CandidateClasses; + + if (attributeSyntaxList.Count == 0) + { + return; + } + + List ClassName = new List(); + foreach (AttributeSyntax attributeSyntax in attributeSyntaxList) + { + // 找到class,并且判断一下是否有parital字段 + var classDeclarationSyntax = attributeSyntax.FirstAncestorOrSelf(); + if (classDeclarationSyntax == null || !classDeclarationSyntax.Modifiers.Any(m => m.IsKind(SyntaxKind.PartialKeyword))) + { + continue; + } + + //判断是否已经处理过这个class了 + if (ClassName.Any(a => a.Equals(classDeclarationSyntax.Identifier.ValueText))) + { + continue; + } + + // 找到namespace + var namespaceDeclarationSyntax = classDeclarationSyntax.FirstAncestorOrSelf(); + if (ClassName.Contains(classDeclarationSyntax.Identifier.ValueText)) + { + continue; + } + + // 找到methods + var methodDeclarationList = classDeclarationSyntax.Members.OfType().ToList(); + if (methodDeclarationList.Count == 0) + { + continue; + } + + StringBuilder sb = new StringBuilder(); + + sb.AppendLine("using Vampirewal.Core.SimpleMVVM;"); + sb.AppendLine(); + + sb.AppendLine($"namespace {namespaceDeclarationSyntax.Name}"); + sb.AppendLine("{"); + + sb.AppendLine($" public partial class {classDeclarationSyntax.Identifier.Text}"); + sb.AppendLine(" {"); + + foreach (MethodDeclarationSyntax methodDeclaration in methodDeclarationList) + { + //再判断一下方法上是否标记了RelayCommand特性,没有的话继续,有的话,就正常执行下去 + if (!SyntaxUtils.HasAttribute(methodDeclaration, "RelayCommand")) + { + continue; + } + + if (methodDeclaration.ParameterList.Parameters.Count > 0) + { + var type = methodDeclaration.ParameterList.Parameters.First(); + + var firstType = type.ToFullString().Split(' ')[0]; + + sb.AppendLine($"private RelayCommand<{firstType}>? _{methodDeclaration.Identifier.Text}Command;"); + + sb.AppendLine($"public RelayCommand<{firstType}> {methodDeclaration.Identifier.Text}Command=>_{methodDeclaration.Identifier.Text}Command??new RelayCommand<{firstType}>({methodDeclaration.Identifier.Text});"); + + } + else + { + sb.AppendLine($" private RelayCommand? _{methodDeclaration.Identifier.Text}Command;"); + + sb.AppendLine($" public RelayCommand {methodDeclaration.Identifier.Text}Command=>_{methodDeclaration.Identifier.Text}Command??new RelayCommand({methodDeclaration.Identifier.Text});"); + + } + } + + sb.AppendLine(" }"); + sb.AppendLine("}"); + + string extensionTextFormatted = CSharpSyntaxTree.ParseText(sb.ToString(), new CSharpParseOptions(LanguageVersion.CSharp8)).GetRoot().NormalizeWhitespace().SyntaxTree.GetText().ToString(); + // 添加到源代码,这样IDE才能感知 + context.AddSource($"{classDeclarationSyntax.Identifier}.g.cs", SourceText.From(extensionTextFormatted,Encoding.UTF8)); + // 保存一下类名,避免重复生成 + ClassName.Add(classDeclarationSyntax.Identifier.ValueText); + } + + + + //var options = (context.Compilation as CSharpCompilation).SyntaxTrees[0].Options as CSharpParseOptions; + //var compilation = context.Compilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(Utils.GetTemplateByFileName("AttributeTemplate.RelayCommandStr.txt"), options)); + + //var allNodes = compilation.SyntaxTrees.SelectMany(s => s.GetRoot().DescendantNodes()); + //var allAttributes = allNodes.Where((d) => d.IsKind(SyntaxKind.Attribute)).OfType(); + //var attributes = allAttributes.Where(d => d.Name.ToString() == "RelayCommand").ToList(); + + //var allClasses = compilation.SyntaxTrees.SelectMany(x => x.GetRoot().DescendantNodes().OfType()); + + ////foreach (var classDeclarationSyntax in allClasses) + ////{ + //// context.AddSource($"{classDeclarationSyntax.Identifier}.g.cs", ""); + ////} + + + //List classList = new List(); + //foreach (AttributeSyntax attributeSyntax in attributes) + //{ + // // 找到class,并且判断一下是否有parital字段 + // var classDeclarationSyntax = attributeSyntax.FirstAncestorOrSelf(); + // if (classDeclarationSyntax == null || + // !classDeclarationSyntax.Modifiers.Any(m => m.IsKind(SyntaxKind.PartialKeyword))) + // { + // continue; + // } + + // // 找到namespace + // var namespaceDeclarationSyntax = + // classDeclarationSyntax.FirstAncestorOrSelf(); + + // if (classList.Contains(classDeclarationSyntax.Identifier.ValueText)) + // { + // continue; + // } + + + + // //var compilationUnitSyntax = classDeclarationSyntax.SyntaxTree.GetRoot() as CompilationUnitSyntax; + // //var usings = compilationUnitSyntax.Usings.Select(m => m.ToString()).ToList(); + + // // 找到method + // var methodDeclarationList = classDeclarationSyntax.Members.OfType().ToList(); + // //if (methodDeclarationList.Count == 0) + // //{ + // // continue; + // //} + + // StringBuilder sb = new StringBuilder(); + + // sb.AppendLine("using Vampirewal.Core.SimpleMVVM;"); + // sb.AppendLine(); + + // sb.AppendLine($"namespace {namespaceDeclarationSyntax.Name}"); + // sb.AppendLine("{"); + + // sb.AppendLine($" public partial class {classDeclarationSyntax.Identifier.Text}"); + // sb.AppendLine(" {"); + // foreach (var methodDeclaration in methodDeclarationList) + // { + + + // //sb.AppendLine($"//该command的参数是{firstType} 12"); + + // if (methodDeclaration.ParameterList.Parameters.Count > 0) + // { + // var type = methodDeclaration.ParameterList.Parameters.First(); + // //sb.AppendLine($"//该command的参数是{type.ToFullString()}"); + + // var firstType = type.ToFullString().Split(' ')[0]; + + // sb.AppendLine($" private RelayCommand<{firstType}>? _{methodDeclaration.Identifier.Text}Command;"); + + // sb.AppendLine(); + + // sb.AppendLine($" public RelayCommand<{firstType}> {methodDeclaration.Identifier.Text}Command=>_{methodDeclaration.Identifier.Text}Command??new RelayCommand<{firstType}>({methodDeclaration.Identifier.Text});"); + + // sb.AppendLine(); + // } + // else + // { + // sb.AppendLine($" private RelayCommand? _{methodDeclaration.Identifier.Text}Command;"); + // sb.AppendLine(); + // sb.AppendLine($" public RelayCommand {methodDeclaration.Identifier.Text}Command=>_{methodDeclaration.Identifier.Text}Command??new RelayCommand({methodDeclaration.Identifier.Text});"); + // sb.AppendLine(); + // } + + // } + + + + // sb.AppendLine(" }"); + // sb.AppendLine("}"); + // // 添加到源代码,这样IDE才能感知 + // context.AddSource($"{classDeclarationSyntax.Identifier}.g.cs", sb.ToString()); + // // 保存一下类名,避免重复生成 + // classList.Add(classDeclarationSyntax.Identifier.ValueText); + //} + } + + public void Initialize(GeneratorInitializationContext context) + { +#if DEBUG + //Debugger.Launch(); +#endif + + context.RegisterForSyntaxNotifications(() => new RelayCommandSyntaxReceiver()); + } +} + +public class RelayCommandSyntaxReceiver : ISyntaxReceiver +{ + public List CandidateClasses { get; } = new List(); + + public void OnVisitSyntaxNode(SyntaxNode syntaxNode) + { + if (syntaxNode is AttributeSyntax cds && cds.Name is IdentifierNameSyntax identifierName && identifierName.Identifier.ValueText == "RelayCommand") + { + CandidateClasses.Add(cds); + } + } +} diff --git a/Vampirewal.Core.SourceGeneratorMvvm/LICENSE b/Vampirewal.Core.SourceGeneratorMvvm/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..ddbd00b437e877e43b09521e47a65ad43f04aa8a --- /dev/null +++ b/Vampirewal.Core.SourceGeneratorMvvm/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 vampirewal + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Vampirewal.Core.SourceGeneratorMvvm/SyntaxUtils.cs b/Vampirewal.Core.SourceGeneratorMvvm/SyntaxUtils.cs new file mode 100644 index 0000000000000000000000000000000000000000..5850f2b3336034e2cd9730246a5f49825ae77bf6 --- /dev/null +++ b/Vampirewal.Core.SourceGeneratorMvvm/SyntaxUtils.cs @@ -0,0 +1,134 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: SyntaxUtils +// 创建者: 杨程 +// 创建日期: 2023/2/4 21:56:45 + +//----------------------------------------------------------------*/ +#endregion + +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + + + +namespace Vampirewal.Core.SourceGeneratorMvvm; + +public class SyntaxUtils +{ + public static bool HasModifier(MemberDeclarationSyntax syntax, params SyntaxKind[] modifiers) + { + return syntax.Modifiers.Any(m => modifiers.Contains(m.Kind())); + } + + + public static bool HasModifiers(MemberDeclarationSyntax syntax, params SyntaxKind[] modifiers) + { + var syntaxKinds = syntax.Modifiers.Select(n => n.Kind()).ToList(); + return modifiers.All(m => syntaxKinds.Contains(m)); + } + + public static string GetName(SyntaxNode syntaxNode) + { + switch (syntaxNode) + { + case BaseTypeDeclarationSyntax baseTypeDeclarationSyntax: + return baseTypeDeclarationSyntax.Identifier.Text; + case BaseNamespaceDeclarationSyntax baseNamespaceDeclarationSyntax: + return baseNamespaceDeclarationSyntax.Name.ToString(); + case VariableDeclaratorSyntax variableDeclaratorSyntax: + return variableDeclaratorSyntax.Identifier.Text; + case NameEqualsSyntax nameEqualsSyntax: + return nameEqualsSyntax.Name.Identifier.Text; + default: + throw new NotImplementedException(); + } + } + + public static bool HasAttribute(MemberDeclarationSyntax classDeclaration, Func func) + { + return GetAttribute(classDeclaration, func) != null; + } + + public static bool HasAttribute(MemberDeclarationSyntax classDeclaration, string AttributeName) + { + var dto = GetAttribute(classDeclaration, AttributeName); + + return dto != null; + } + + public static AttributeSyntax GetAttribute(MemberDeclarationSyntax classDeclaration, Func func) + { + return classDeclaration.AttributeLists.SelectMany(m => m.Attributes) + .FirstOrDefault(m => func(m.Name.ToString())); + } + + public static AttributeSyntax GetAttribute(MemberDeclarationSyntax classDeclaration, string AttributeName) + { + var attributes = classDeclaration.AttributeLists.SelectMany(m => m.Attributes); + + var attr= attributes.FirstOrDefault(m => + { + var nameSyntax = m.Name as IdentifierNameSyntax; + if (nameSyntax.Identifier.Text.Equals(AttributeName)) + { + return true; + } + return false; + }); + + return attr; + } + + /// + /// 检查是否包含AOP特性 + /// + /// + /// + public static bool HasAopAttribute(MemberDeclarationSyntax classDeclaration,out AttributeSyntax attribute) + { + attribute = GetAopAttribute(classDeclaration); + + return attribute != null; + } + + /// + /// 获取已AOP结尾的特性 + /// + /// + /// + public static AttributeSyntax GetAopAttribute(MemberDeclarationSyntax classDeclaration) + { + var attributes= classDeclaration.AttributeLists.SelectMany(m => m.Attributes); + + var attr = attributes.FirstOrDefault(m => + { + var nameSyntax = m.Name as IdentifierNameSyntax; + if (nameSyntax.Identifier.ValueText.EndsWith("AOP")) + { + return true; + } + return false; + }); + + return attr; + } + + public static List GetUsings(ClassDeclarationSyntax classDeclarationSyntax) + { + var compilationUnitSyntax = classDeclarationSyntax.SyntaxTree.GetRoot() as CompilationUnitSyntax; + var usings = compilationUnitSyntax.Usings.Select(m => m.ToString()).ToList(); + return usings; + } +} diff --git a/Vampirewal.Core.SourceGeneratorMvvm/Template/AopTemplate/AopMethod.txt b/Vampirewal.Core.SourceGeneratorMvvm/Template/AopTemplate/AopMethod.txt new file mode 100644 index 0000000000000000000000000000000000000000..de1f4e373ec6764754574a2f898a31359b0e89be --- /dev/null +++ b/Vampirewal.Core.SourceGeneratorMvvm/Template/AopTemplate/AopMethod.txt @@ -0,0 +1,55 @@ +// +#pragma warning disable +#nullable enable + + +using System; +using System.Reflection; + +namespace Vampirewal.Core.SimpleMVVM +{ + + /// + /// Aop传递方法类 + /// + public class AopMethod + { + public AopMethod(object _TargetClass,MethodInfo method,params object[] para) + { + TargetClass=_TargetClass; + MethodTarget=method; + Paramters=para; + } + + /// + /// 使用方法的类 + /// + public object TargetClass {get; private set;} + + /// + /// 方法主体 + /// + public MethodInfo MethodTarget {get; private set;} + + /// + /// 方法的参数 + /// + public object[] Paramters {get; private set;} + + /// + /// 方法的返回值 + /// + public object ReturnValue {get; private set;} + + /// + /// 执行方法 + /// + public void Excute() + { + ReturnValue=MethodTarget.Invoke(TargetClass, Paramters); + } + + } + +} + diff --git a/Vampirewal.Core.SourceGeneratorMvvm/Template/AttributeTemplate/AopBaseAttribute.txt b/Vampirewal.Core.SourceGeneratorMvvm/Template/AttributeTemplate/AopBaseAttribute.txt new file mode 100644 index 0000000000000000000000000000000000000000..e1065bb2ed24dec49f0724f944c81b0229ba378e --- /dev/null +++ b/Vampirewal.Core.SourceGeneratorMvvm/Template/AttributeTemplate/AopBaseAttribute.txt @@ -0,0 +1,58 @@ +// +#pragma warning disable +#nullable enable + +using System; +using System.Reflection; +using Vampirewal.Core.SimpleMVVM; + + +namespace Vampirewal.Core.Attributes +{ + /// + /// AOP特性基类(派生特性命名需以AOP结尾) + /// + [AttributeUsage(AttributeTargets.Method)] + public abstract class AopBaseAttribute : Attribute + { + + /// + /// 执行位置 + /// + public InvokeLocation Location { set; get; } = InvokeLocation.Both; + + /// + /// 方法执行前 + /// + public abstract void ExcuteBefore(); + + /// + /// 方法执行中 + /// + public abstract void ExcuteMiddle(AopMethod method); + + /// + /// 方法执行后 + /// + public abstract void ExcuteAfter(AopMethod method,Exception ex); + } + + /// + /// 执行位置枚举 + /// + public enum InvokeLocation + { + /// + /// 中间 + /// + Both = 0, + /// + /// 执行前 + /// + Before = 1, + /// + /// 执行后 + /// + After = 2 + } +} \ No newline at end of file diff --git a/Vampirewal.Core.SourceGeneratorMvvm/Template/AttributeTemplate/DoNotifyPropertyAttributeStr.txt b/Vampirewal.Core.SourceGeneratorMvvm/Template/AttributeTemplate/DoNotifyPropertyAttributeStr.txt new file mode 100644 index 0000000000000000000000000000000000000000..4f34782fe04ae83a76f30cb5a5a141e5769ffa6f --- /dev/null +++ b/Vampirewal.Core.SourceGeneratorMvvm/Template/AttributeTemplate/DoNotifyPropertyAttributeStr.txt @@ -0,0 +1,17 @@ +// +#pragma warning disable +#nullable enable + +using System; + +namespace Vampirewal.Core.Attributes +{ + /// + /// 在字段上标记之后,自动生成对应的完整属性 + /// + [AttributeUsage(AttributeTargets.Field ,Inherited=true,AllowMultiple=false)] + public class DoNotifyPropertyAttribute:Attribute + { + + } +} \ No newline at end of file diff --git a/Vampirewal.Core.SourceGeneratorMvvm/Template/AttributeTemplate/DtoIgnoreAttributeStr.txt b/Vampirewal.Core.SourceGeneratorMvvm/Template/AttributeTemplate/DtoIgnoreAttributeStr.txt new file mode 100644 index 0000000000000000000000000000000000000000..d40761f3dff3a0442ed5131029f6b64e68b99548 --- /dev/null +++ b/Vampirewal.Core.SourceGeneratorMvvm/Template/AttributeTemplate/DtoIgnoreAttributeStr.txt @@ -0,0 +1,26 @@ +// +#pragma warning disable +#nullable enable + + +/* +* 该特性由程序自动生成 +*/ + + +using System; + +namespace Vampirewal.Core.Attributes +{ + /// + /// 标记之后在自动生成的DTO类中排除掉 + /// + [AttributeUsage( AttributeTargets.Property,Inherited=true,AllowMultiple=false)] + public class DtoIgnoreAttribute:Attribute + { + public DtoIgnoreAttribute() + { + + } + } +} \ No newline at end of file diff --git a/Vampirewal.Core.SourceGeneratorMvvm/Template/AttributeTemplate/GeneratorAopProxy.txt b/Vampirewal.Core.SourceGeneratorMvvm/Template/AttributeTemplate/GeneratorAopProxy.txt new file mode 100644 index 0000000000000000000000000000000000000000..fbae587d78ab49f282325e82b64c0e95005f8065 --- /dev/null +++ b/Vampirewal.Core.SourceGeneratorMvvm/Template/AttributeTemplate/GeneratorAopProxy.txt @@ -0,0 +1,31 @@ +// +#pragma warning disable +#nullable enable + + +/* +* 该特性由程序自动生成 +*/ + + +using System; + +namespace Vampirewal.Core.Attributes +{ + /// + /// 标记之后会生成一个Proxy代理类,配合AopBase的派生特性实现AOP功能 + /// + [AttributeUsage( AttributeTargets.Class,Inherited=true,AllowMultiple=false)] + public class GeneratorAopProxyAttribute:Attribute + { + /// + /// + /// + public GeneratorAopProxyAttribute() + { + + } + + } +} + diff --git a/Vampirewal.Core.SourceGeneratorMvvm/Template/AttributeTemplate/GeneratorDTOStr.txt b/Vampirewal.Core.SourceGeneratorMvvm/Template/AttributeTemplate/GeneratorDTOStr.txt new file mode 100644 index 0000000000000000000000000000000000000000..a05c32bd1044d61c02d6e59adf0a3481987744c9 --- /dev/null +++ b/Vampirewal.Core.SourceGeneratorMvvm/Template/AttributeTemplate/GeneratorDTOStr.txt @@ -0,0 +1,33 @@ +// +#pragma warning disable +#nullable enable + + +/* +* 该特性由程序自动生成 +*/ + + +using System; + +namespace Vampirewal.Core.Attributes +{ + /// + /// 标记之后自动生成DTO类 + /// + [AttributeUsage( AttributeTargets.Class,Inherited=true,AllowMultiple=false)] + public class GeneratorDTOAttribute:Attribute + { + /// + /// + /// + /// 当前Entity的Type,传入typeof + public GeneratorDTOAttribute() + { + //this.EntityType = entityType; + } + + public Type EntityType { get; set; } + } +} + diff --git a/Vampirewal.Core.SourceGeneratorMvvm/Template/AttributeTemplate/PropertyStr.txt b/Vampirewal.Core.SourceGeneratorMvvm/Template/AttributeTemplate/PropertyStr.txt new file mode 100644 index 0000000000000000000000000000000000000000..b408b2550e73167580cf2d6ec8fdb57f589ca3b4 --- /dev/null +++ b/Vampirewal.Core.SourceGeneratorMvvm/Template/AttributeTemplate/PropertyStr.txt @@ -0,0 +1,21 @@ +// +#pragma warning disable +#nullable enable + +/* +* 该特性由程序自动生成 +*/ + +using System; + +namespace Vampirewal.Core.Attributes +{ + /// + /// 在字段上标记之后,自动生成对应的完整属性 + /// + [AttributeUsage(AttributeTargets.Field ,Inherited=true,AllowMultiple=false)] + public class PropertyAttribute:Attribute + { + public const string Name = "Property"; + } +} \ No newline at end of file diff --git a/Vampirewal.Core.SourceGeneratorMvvm/Template/AttributeTemplate/RelayCommandStr.txt b/Vampirewal.Core.SourceGeneratorMvvm/Template/AttributeTemplate/RelayCommandStr.txt new file mode 100644 index 0000000000000000000000000000000000000000..08476937c972fa42b8da42dc41f0b400c6ec9c41 --- /dev/null +++ b/Vampirewal.Core.SourceGeneratorMvvm/Template/AttributeTemplate/RelayCommandStr.txt @@ -0,0 +1,22 @@ + +// +#pragma warning disable +#nullable enable + +/* +* 该特性由程序自动生成 +*/ + +using System; + +namespace Vampirewal.Core.Attributes +{ + /// + /// 在字段上标记之后,自动生成对应的ICommand命令 + /// + [AttributeUsage(AttributeTargets.Method,Inherited=true,AllowMultiple=false)] + public class RelayCommandAttribute:Attribute + { + + } +} \ No newline at end of file diff --git a/Vampirewal.Core.SourceGeneratorMvvm/Template/InterfaceTemplate/IAopIntercept.txt b/Vampirewal.Core.SourceGeneratorMvvm/Template/InterfaceTemplate/IAopIntercept.txt new file mode 100644 index 0000000000000000000000000000000000000000..67051407ead1cf67bb2b8d8a60204d84cb836cc3 --- /dev/null +++ b/Vampirewal.Core.SourceGeneratorMvvm/Template/InterfaceTemplate/IAopIntercept.txt @@ -0,0 +1,20 @@ + + +namespace Vampirewal.Core.SimpleMVVM +{ + /// + /// Aop拦截器接口 + /// + public interface IAopIntercept + { + /// + /// 执行前 + /// + void ExcuteBefore(); + + /// + /// 执行后 + /// + void ExcuteAfter(); + } +} diff --git a/Vampirewal.Core/SimpleMVVM/NotifyBase.cs b/Vampirewal.Core.SourceGeneratorMvvm/Template/NotifyChangedTemplate/NotifyBase.txt similarity index 34% rename from Vampirewal.Core/SimpleMVVM/NotifyBase.cs rename to Vampirewal.Core.SourceGeneratorMvvm/Template/NotifyChangedTemplate/NotifyBase.txt index 31c0f90bbe40adce84a724b8ed9b559a40367e47..95c3e10ad2670dacd478d88b7e687ef7b8499cfe 100644 --- a/Vampirewal.Core/SimpleMVVM/NotifyBase.cs +++ b/Vampirewal.Core.SourceGeneratorMvvm/Template/NotifyChangedTemplate/NotifyBase.txt @@ -1,40 +1,23 @@ -/* 项目名称: NotifyBase.cs - * 命名空间: Common - * 类 名 称: NotifyBase - * 作 者 : 杨程 - * 概 述 : - * 创建时间 : 2021/2/10 21:46:31 - * 更新时间 : 2021/2/10 21:46:31 - * CLR版本 : 4.0.30319.42000 - * ****************************************************** - * Copyright@Administrator 2021 .All rights reserved. - * ****************************************************** - */ - -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; +// +#pragma warning disable +#nullable enable namespace Vampirewal.Core.SimpleMVVM { /// /// 属性通知基类 /// - public class NotifyBase : INotifyPropertyChanged + public class NotifyBase : System.ComponentModel.INotifyPropertyChanged { - public event PropertyChangedEventHandler PropertyChanged; + public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; /// /// 属性变化通知 /// /// - public void DoNotify([CallerMemberName] string propName = "") + public void DoNotify([System.Runtime.CompilerServices.CallerMemberName] string propName = "") { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); + PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(propName)); } /// @@ -44,7 +27,7 @@ namespace Vampirewal.Core.SimpleMVVM /// /// /// - public void Set(ref T field,T value,[CallerMemberName]string propName = "") + public void Set(ref T field,T value,[System.Runtime.CompilerServices.CallerMemberName]string propName = "") { if (EqualityComparer.Default.Equals(field,value)) { @@ -53,5 +36,26 @@ namespace Vampirewal.Core.SimpleMVVM field = value; DoNotify(propName); } + + /// + /// 带的属性变化通知 + /// + /// + /// + /// + /// 属性变化的时候执行的方法 + /// + public void ActionSet(ref T field, T value,Action OnChanged=null, [System.Runtime.CompilerServices.CallerMemberName] string propName = "") + { + if (EqualityComparer.Default.Equals(field, value)) + { + return; + } + + + field = value; + OnChanged?.Invoke(value); + DoNotify(propName); + } } -} +} \ No newline at end of file diff --git a/Vampirewal.Core/SimpleMVVM/RelayCommand.cs b/Vampirewal.Core.SourceGeneratorMvvm/Template/RelayCommandTemplate/RelayCommand.txt similarity index 39% rename from Vampirewal.Core/SimpleMVVM/RelayCommand.cs rename to Vampirewal.Core.SourceGeneratorMvvm/Template/RelayCommandTemplate/RelayCommand.txt index c57d8b2fb3a903d7601176023437036f49e1d6dc..6766c8edd085db58a5359533239e8850ddae020c 100644 --- a/Vampirewal.Core/SimpleMVVM/RelayCommand.cs +++ b/Vampirewal.Core.SourceGeneratorMvvm/Template/RelayCommandTemplate/RelayCommand.txt @@ -1,52 +1,38 @@ -/* 项目名称: RelayCommand.cs - * 命名空间: Vampirewal.Core.SimpleMVVM - * 类 名 称: RelayCommand - * 作 者 : 杨程 - * 概 述 : - * 创建时间 : 2021/2/20 18:26:51 - * 更新时间 : 2021/2/20 18:26:51 - * CLR版本 : 4.0.30319.42000 - * ****************************************************** - * Copyright@Administrator 2021 .All rights reserved. - * ****************************************************** - */ +// +#pragma warning disable +#nullable enable + using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Text; -using System.Threading.Tasks; + using System.Windows.Input; namespace Vampirewal.Core.SimpleMVVM { /// - /// - /// - /// - /// - public delegate void DelegateCommand(T parameter); - /// - /// + /// ICommand命令 /// - public delegate void DelegateCommand(); - - public class RelayCommand : ICommand { /// /// /// /// - public RelayCommand(DelegateCommand command) + public RelayCommand(Action execute) { - this.delCommand = command; + this.ExecuteCommand = execute; } + public RelayCommand(Action execute,Func canExcute) + { + this.ExecuteCommand = execute; + this._canExecute = canExcute; + } - private DelegateCommand delCommand; + private readonly Action ExecuteCommand; + + private readonly Func _canExecute; /// /// @@ -62,11 +48,12 @@ namespace Vampirewal.Core.SimpleMVVM { - if (delCommand == null) + if (ExecuteCommand == null) { return false; } - return true; + + return _canExecute == null ? true : _canExecute.Invoke(); } /// @@ -78,58 +65,25 @@ namespace Vampirewal.Core.SimpleMVVM if (CanExecute(parameter)) { CanExecuteChanged?.Invoke(this, null); - delCommand.Invoke(); + ExecuteCommand.Invoke(); } } + + + + /// + /// 刷新该命令是否能执行的状态 + /// + public void RaiseCanExecuteChanged() + { + CanExecuteChanged?.Invoke(this,null); + } } - //public class RelayCommand : ICommand - //{ - // /// - // /// - // /// - // /// - // public RelayCommand(DelegateCommand command) - // { - // delCommand = command; - // } - - // DelegateCommand delCommand; - - // /// - // /// - // /// - // public event EventHandler CanExecuteChanged; - - // /// - // /// - // /// - // /// - // /// - // public bool CanExecute(object parameter) - // { - - // if (delCommand == null) - // { - // return false; - // } - // return true; - // } - // /// - // /// - // /// - // /// - // public void Execute(object parameter) - // { - // T t = (T)parameter; - // if (CanExecute(parameter)) - // { - // CanExecuteChanged?.Invoke(this, null); - // delCommand.Invoke(t); - // } - // } - //} + /// + /// 带参数的ICommand命令 + /// public class RelayCommand : ICommand { private readonly Action _execute; @@ -152,34 +106,18 @@ namespace Vampirewal.Core.SimpleMVVM _canExecute = canExecute; } - public event EventHandler CanExecuteChanged - { - add - { - if (_canExecute != null) - { - CommandManager.RequerySuggested += value; - } - } - remove - { - if (_canExecute != null) - { - CommandManager.RequerySuggested -= value; - } - } - } + public event EventHandler? CanExecuteChanged; - [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", - Justification = "The this keyword is used in the Silverlight version")] - [SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate", - Justification = "This cannot be an event")] + /// + /// 刷新该命令是否能执行的状态 + /// public void RaiseCanExecuteChanged() { - CommandManager.InvalidateRequerySuggested(); + CanExecuteChanged?.Invoke(this, null); } + public bool CanExecute(object parameter) { return _canExecute == null ? true : _canExecute((T)parameter); @@ -190,4 +128,5 @@ namespace Vampirewal.Core.SimpleMVVM _execute((T)parameter); } } -} + +} \ No newline at end of file diff --git a/Vampirewal.Core.SourceGeneratorMvvm/Utils.cs b/Vampirewal.Core.SourceGeneratorMvvm/Utils.cs new file mode 100644 index 0000000000000000000000000000000000000000..93dcf99df21b2663e4bed177973f751d06c51863 --- /dev/null +++ b/Vampirewal.Core.SourceGeneratorMvvm/Utils.cs @@ -0,0 +1,122 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: Utils +// 创建者: 杨程 +// 创建日期: 2023/2/6 14:04:02 + +//----------------------------------------------------------------*/ +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; + +namespace Vampirewal.Core.SourceGeneratorMvvm; + +/// +/// 工具类 +/// +public static class Utils +{ + #region 代码规范风格化 + /// + /// 转换为Pascal风格-每一个单词的首字母大写 + /// + /// 字段名 + /// 分隔符 + /// + public static string ConvertToPascal(string fieldName, string fieldDelimiter) + { + string result = string.Empty; + if (fieldName.Contains(fieldDelimiter)) + { + //全部小写 + string[] array = fieldName.ToLower().Split(fieldDelimiter.ToCharArray()); + foreach (var t in array) + { + //首字母大写 + result += t.Substring(0, 1).ToUpper() + t.Substring(1); + } + } + else if (string.IsNullOrWhiteSpace(fieldName)) + { + result = fieldName; + } + else if (fieldName.Length == 1) + { + result = fieldName.ToUpper(); + } + else + { + result = fieldName.Substring(0, 1).ToUpper() + fieldName.Substring(1); + } + return result; + } + /// + /// 转换为Camel风格-第一个单词小写,其后每个单词首字母大写 + /// + /// 字段名 + /// 分隔符 + /// + public static string ConvertToCamel(string fieldName, string fieldDelimiter) + { + //先Pascal + string result = ConvertToPascal(fieldName, fieldDelimiter); + //然后首字母小写 + if (result.Length == 1) + { + result = result.ToLower(); + } + else + { + result = result.Substring(0, 1).ToLower() + result.Substring(1); + } + + return result; + } + #endregion + + /// + /// 获取模版文件并转成string + /// + /// 文件名称 + /// string + internal static string GetTemplateByFileName(string FileRelativePath) + { + Assembly assembly = Assembly.GetExecutingAssembly(); + + string[] resNames = assembly.GetManifestResourceNames(); + using (Stream stream = assembly.GetManifestResourceStream($"{assembly.GetName().Name}.Template.{FileRelativePath}")) + { + if (stream != null) + { + using (StreamReader sr = new StreamReader(stream)) + { + string context = sr.ReadToEnd(); + + return context; + } + } + else + { + return ""; + } + + } + } + + internal static string GetContentInParentheses(string value) + { + var match = Regex.Match(value, @"\(([^)]*)\)"); + return match.Groups[1].Value; + } +} diff --git a/Vampirewal.Core.SourceGeneratorMvvm/Vampirewal-Logo.png b/Vampirewal.Core.SourceGeneratorMvvm/Vampirewal-Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..3d150ba56db89235caebb1676f05415ddc65740d Binary files /dev/null and b/Vampirewal.Core.SourceGeneratorMvvm/Vampirewal-Logo.png differ diff --git a/Vampirewal.Core.SourceGeneratorMvvm/Vampirewal.Core.SourceGeneratorMvvm.csproj b/Vampirewal.Core.SourceGeneratorMvvm/Vampirewal.Core.SourceGeneratorMvvm.csproj new file mode 100644 index 0000000000000000000000000000000000000000..3e932cef82cd1bb5a4f073ff13fcb0ec702ec313 --- /dev/null +++ b/Vampirewal.Core.SourceGeneratorMvvm/Vampirewal.Core.SourceGeneratorMvvm.csproj @@ -0,0 +1,105 @@ + + + + netstandard2.0 + preview + vampirewal + true + 1.0.17 + false + false + false + false + 该类为尝试Source Generator写的MVVM帮助类,会自动生成基础的一些代码 + Analyzer + false + Vampirewal-Logo.png + + LICENSE + True + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + $(GetTargetPathDependsOn);GetDependencyTargetPaths + + + + + + + + + + + + + + + + + + + + + + + + + True + \ + + + \ + True + + + diff --git a/Vampirewal.Core.SubMessageService/ISubMessageService.cs b/Vampirewal.Core.SubMessageService/ISubMessageService.cs new file mode 100644 index 0000000000000000000000000000000000000000..fa34f3806b09ba2a9817da3fe3cbdc504e5bbea1 --- /dev/null +++ b/Vampirewal.Core.SubMessageService/ISubMessageService.cs @@ -0,0 +1,203 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: ISubMessageService +// 创建者: 杨程 +// 创建日期: 2022/11/12 13:50:48 + +//----------------------------------------------------------------*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +// + +namespace Vampirewal.Core.SubMessageService +{ + /// + /// + /// + public interface ISubMessageService + { + /// + /// 订阅消息 + /// + /// 继承自SubMessage的消息类 + /// + /// + /// + void Subscribe(object recipient, Action action, + ThreadOption threadOption = ThreadOption.PublisherThread) where TMessage : SubMessage; + + /// + /// 取消订阅 + /// + /// + /// + /// + void Unsubscribe(object recipient, Action? action = null) where TMessage : SubMessage; + + /// + /// 消息推送 + /// + /// + /// + /// + void Publish(object sender, TMessage message) where TMessage : SubMessage; + } + + public enum ThreadOption + { + PublisherThread, + BackgroundThread, + UiThread + } + + public class VampirewalSubMessageService : ISubMessageService + { + public static readonly VampirewalSubMessageService Default = new VampirewalSubMessageService(); + private readonly object registerLock = new object(); + + private Dictionary>? recipientsOfSubclassesAction; + + public void Subscribe(object recipient, Action action, ThreadOption threadOption) + where TMessage : SubMessage + { + lock (this.registerLock) + { + var messageType = typeof(TMessage); + + this.recipientsOfSubclassesAction ??= new Dictionary>(); + + List list; + + if (!this.recipientsOfSubclassesAction.ContainsKey(messageType)) + { + list = new List(); + this.recipientsOfSubclassesAction.Add(messageType, list); + } + else + { + list = this.recipientsOfSubclassesAction[messageType]; + } + + var item = new WeakActionAndToken + { + Recipient = recipient, + ThreadOption = threadOption, + Action = action + }; + + list.Add(item); + } + } + + public void Unsubscribe(object? recipient, Action? action) where TMessage : SubMessage + { + var messageType = typeof(TMessage); + + if (recipient == null || this.recipientsOfSubclassesAction == null || + this.recipientsOfSubclassesAction.Count == 0 || !this.recipientsOfSubclassesAction.ContainsKey(messageType)) + { + return; + } + + var lstActions = this.recipientsOfSubclassesAction[messageType]; + for (var i = lstActions.Count - 1; i >= 0; i--) + { + var item = lstActions[i]; + var pastAction = item.Action; + + if (pastAction != null + && recipient == pastAction.Target + && (action == null || action.Method.Name == pastAction.Method.Name)) + { + lstActions.Remove(item); + } + } + } + + public void Publish(object sender, TMessage message) where TMessage : SubMessage + { + var messageType = typeof(TMessage); + + if (this.recipientsOfSubclassesAction != null) + { + var listClone = this.recipientsOfSubclassesAction.Keys.Take(this.recipientsOfSubclassesAction.Count) + .ToList(); + + foreach (var type in listClone) + { + List? list = null; + + if (messageType == type || messageType.IsSubclassOf(type) || type.IsAssignableFrom(messageType)) + { + list = this.recipientsOfSubclassesAction[type] + .Take(this.recipientsOfSubclassesAction[type].Count) + .ToList(); + } + + if (list is { Count: > 0 }) + { + this.SendToList(message, list); + } + } + } + } + + private void SendToList(TMessage message, IEnumerable weakActionsAndTokens) + where TMessage : SubMessage + { + var list = weakActionsAndTokens.ToList(); + var listClone = list.Take(list.Count()).ToList(); + + foreach (var item in listClone) + { + if (item.Action is { Target: { } }) + { + switch (item.ThreadOption) + { + case ThreadOption.BackgroundThread: + Task.Run(() => { item.ExecuteWithObject(message); }); + break; + case ThreadOption.UiThread: + SynchronizationContext.Current!.Post(_ => { item.ExecuteWithObject(message); }, null); + break; + default: + item.ExecuteWithObject(message); + break; + } + } + } + } + } + + public class WeakActionAndToken + { + public object? Recipient { get; set; } + + public ThreadOption ThreadOption { get; set; } + + public Delegate? Action { get; set; } + + public string? Tag { get; set; } + + public void ExecuteWithObject(TMessage message) where TMessage : SubMessage + { + if (this.Action is Action factAction) + { + factAction.Invoke(message); + } + } + } +} diff --git a/Vampirewal.Core.SubMessageService/SubMessage.cs b/Vampirewal.Core.SubMessageService/SubMessage.cs new file mode 100644 index 0000000000000000000000000000000000000000..d0a8fe76f756a65bb2444bf66a0e6c997a4c92bc --- /dev/null +++ b/Vampirewal.Core.SubMessageService/SubMessage.cs @@ -0,0 +1,42 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: SubMessage +// 创建者: 杨程 +// 创建日期: 2022/11/12 13:47:31 + +//----------------------------------------------------------------*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + + + +namespace Vampirewal.Core.SubMessageService +{ + /// + /// 消息抽象类,用于定义消息类型,具体的消息需要继承该类 + /// + public abstract class SubMessage + { + /// + /// + /// + protected SubMessage(object sender) + { + //构造函数 + this.Sender = sender ?? throw new ArgumentNullException(nameof(sender)); + } + + public object Sender { get; set; } + } +} diff --git a/Vampirewal.Core.SubMessageService/Vampirewal.Core.SubMessageService.csproj b/Vampirewal.Core.SubMessageService/Vampirewal.Core.SubMessageService.csproj new file mode 100644 index 0000000000000000000000000000000000000000..f208d303c9811fa05807ef8f72685b8ebb536a37 --- /dev/null +++ b/Vampirewal.Core.SubMessageService/Vampirewal.Core.SubMessageService.csproj @@ -0,0 +1,7 @@ + + + + net5.0 + + + diff --git a/Vampirewal.Core.VContainer/BaseSingleton.cs b/Vampirewal.Core.VContainer/BaseSingleton.cs new file mode 100644 index 0000000000000000000000000000000000000000..aa64a484d4a1706c584f5ce232fa2152f154565c --- /dev/null +++ b/Vampirewal.Core.VContainer/BaseSingleton.cs @@ -0,0 +1,46 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:BaseSingleton +// 创 建 人:YangCheng +// 创建时间:2022/5/24 19:18:31 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Vampirewal.Core.VContainer +{ + /// + /// 所有使用单例模式的基类,需要被继承 + /// + /// 填写类的名称 + public class BaseSingleton where T : class, new() + { + private static T _instance; + private static object _objLock = new object(); + public static T GetInstance() + { + + if (_instance == null) + { + lock (_objLock) + { + if (_instance == null) + { + _instance = new T(); + } + } + } + return _instance; + } + } +} diff --git a/Vampirewal.Core.VContainer/IIocManager.cs b/Vampirewal.Core.VContainer/IIocManager.cs new file mode 100644 index 0000000000000000000000000000000000000000..bb2e8c7657730eafac1354b3c073cd81b176fd1c --- /dev/null +++ b/Vampirewal.Core.VContainer/IIocManager.cs @@ -0,0 +1,347 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:IIocManager +// 创 建 人:YangCheng +// 创建时间:2022/5/24 18:40:43 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + +//using System; +//using System.Collections.Generic; +//using System.Linq; +//using System.Reflection; +//using System.Text; +//using System.Threading.Tasks; + +/* + * 代码来源: + * https://github.com/sunshine5516/ABP_SunFramework/tree/f20f6346063ac749c309d167192348c67cc5b2dd/src/AbpFramework/Dependency + */ + +//namespace Vampirewal.Core.VContainer +//{ +// /// +// /// IOC容器接口 +// /// +// public interface IIocManager: IIocRegistrar, IIocResolver, IDisposable +// { +// /// +// /// IWindsorContainer注入容器 +// /// +// //IWindsorContainer IocContainer { get; } +// /// +// /// 类型是否已经注册 +// /// +// /// +// /// +// new bool IsRegistered(Type type); +// /// +// /// 类型是否已经注册 +// /// +// /// Type to check +// new bool IsRegistered(); +// } + +// public interface IIocRegistrar +// { +// /// +// /// 添加常规注册的依赖注册器。 +// /// +// /// 依赖注入 +// void AddConventionalRegistrar(IConventionalDependencyRegistrar registrar); +// void RegisterAssemblyByConvention(Assembly assembly); +// /// +// /// 注册程序集 +// /// +// /// Assembly to register +// /// Additional configuration +// void RegisterAssemblyByConvention(Assembly assembly, ConventionalRegistrationConfig config); + +// void Register(DependencyLifeStyle lifeStyle = DependencyLifeStyle.Singleton) +// where T : class; +// void Register(Type type, DependencyLifeStyle lifeStyle = DependencyLifeStyle.Singleton); + + +// /// +// /// Registers a type with it's implementation. +// /// +// /// Registering type +// /// The type that implements +// /// Lifestyle of the objects of this type +// void Register(DependencyLifeStyle lifeStyle = DependencyLifeStyle.Singleton) +// where TType : class +// where TImpl : class, TType; + +// /// +// /// Registers a type with it's implementation. +// /// +// /// Type of the class +// /// The type that implements +// /// Lifestyle of the objects of this type +// void Register(Type type, Type impl, DependencyLifeStyle lifeStyle = DependencyLifeStyle.Singleton); + +// /// +// /// Checks whether given type is registered before. +// /// +// /// Type to check +// bool IsRegistered(Type type); + +// /// +// /// Checks whether given type is registered before. +// /// +// /// Type to check +// bool IsRegistered(); +// } + +// public interface IIocResolver +// { +// /// +// /// 从IOC容器获取对象。 +// /// Returning object must be Released (see ) after usage. +// /// +// /// 获取的对象的类型 +// /// 对象实例 +// T Resolve(); +// /// +// /// 从IOC容器获取对象. +// /// Returning object must be Released (see ) after usage. +// /// +// /// 要投射的物体的类型 +// /// 要解析的对象的类型 +// /// 对象实例 +// T Resolve(Type type); +// /// +// /// 从IOC容器获取对象 +// /// Returning object must be Released (see ) after usage. +// /// +// /// 要获取的对象的类型 +// /// 构造函数参数 +// /// 对象实例 +// T Resolve(object argumentsAsAnonymousType); +// /// +// /// 从IOC容器获取对象 +// /// +// /// 要获取的对象的类型 +// /// 对象实例 +// object Resolve(Type type); +// /// +// /// 从IOC容器获取对象. +// /// Returning object must be Released (see ) after usage. +// /// +// /// 要获取的对象的类型 +// /// 构造函数参数s +// /// 对象实例 +// object Resolve(Type type, object argumentsAsAnonymousType); +// /// +// /// 获取给定类型的所有实现 +// /// +// /// 要解析的对象的类型 +// /// 对象实例 +// T[] ResolveAll(); +// /// +// /// 获取给定类型的所有实现. +// /// Returning objects must be Released (see ) after usage. +// /// +// /// 要解析的对象的类型 +// /// 构造函数参数 +// /// 对象实例 +// T[] ResolveAll(object argumentsAsAnonymousType); +// /// +// /// 获取给定类型的所有实现 +// /// Returning objects must be Released (see ) after usage. +// /// +// /// 要解析的对象的类型 +// /// 对象实例 +// object[] ResolveAll(Type type); +// /// +// /// 获取给定类型的所有实现. +// /// Returning objects must be Released (see ) after usage. +// /// +// /// 要解析的对象的类型 +// /// 构造函数名 +// /// 对象实例 +// object[] ResolveAll(Type type, object argumentsAsAnonymousType); +// /// +// /// 释放预先解析的对象。 请参阅解析方法。 +// /// +// /// 要释放的对象d +// void Release(object obj); +// /// +// /// 检查给定类型是否在之前注册. +// /// +// /// 检测类型 +// bool IsRegistered(Type type); +// /// +// /// Checks whether given type is registered before. +// /// +// /// Type to check +// bool IsRegistered(); +// } + +// public interface IConventionalDependencyRegistrar +// { +// /// +// /// 注册程序集 +// /// +// /// +// void RegisterAssembly(IConventionalRegistrationContext context); +// } + +// public interface IConventionalRegistrationContext +// { +// /// +// /// 要注册的程序集 +// /// +// Assembly Assembly { get; } +// IIocManager IocManager { get; } +// /// +// /// 注册的配置 +// /// +// ConventionalRegistrationConfig Config { get; } +// } + +// /// +// /// 用来注册基本的依赖实现,比如 +// /// 和。 +// /// +// public class BasicConventionalRegistrar : IConventionalDependencyRegistrar +// { +// public void RegisterAssembly(IConventionalRegistrationContext context) +// { + +// //注册拦截器 +// //context.IocManager.IocContainer.Register( +// // Classes.FromThisAssembly() +// // .BasedOn() +// // .WithService.Self() +// // .LifestyleTransient()); + +// //Transient +// //context.IocManager.IocContainer.Register( +// // Classes.FromAssembly(context.Assembly) +// // .IncludeNonPublicTypes() +// // .BasedOn() +// // .If(type => !type.GetTypeInfo().IsGenericTypeDefinition) +// // .WithService.Self() +// // .WithService.DefaultInterfaces() +// // .LifestyleTransient() +// // ); +// //context.IocManager.IocContainer.Register( +// // Classes.FromAssembly(context.Assembly) +// // .IncludeNonPublicTypes() +// // .BasedOn() +// // .If(type => !type.GetTypeInfo().IsGenericTypeDefinition) +// // .WithService.Self() +// // .WithService.DefaultInterfaces() +// // .LifestyleSingleton() +// // ); +// ////Windsor Interceptors +// //context.IocManager.IocContainer.Register( +// // Classes.FromAssembly(context.Assembly) +// // .IncludeNonPublicTypes() +// // .BasedOn() +// // .If(type => !type.GetTypeInfo().IsGenericTypeDefinition) +// // .WithService.Self() +// // .LifestyleTransient() +// // ); + +// } +// } + +// /// +// /// 类用于以传统方式注册类时传递配置 +// /// +// public class ConventionalRegistrationConfig +// { +// /// +// /// 是否注册所有的实现。 +// /// 默认: true. +// /// +// public bool InstallInstallers { get; set; } + +// /// +// /// +// /// +// public ConventionalRegistrationConfig() +// { +// InstallInstallers = true; +// } +// } + +// public enum DependencyLifeStyle +// { +// Singleton, + +// /// +// /// Transient object. Created one object for every resolving. +// /// +// Transient +// } + +// internal class DisposableDependencyObjectWrapper : DisposableDependencyObjectWrapper, IDisposableDependencyObjectWrapper +// { +// public DisposableDependencyObjectWrapper(IIocResolver iocResolver, object obj) +// : base(iocResolver, obj) +// { + +// } +// } +// internal class DisposableDependencyObjectWrapper : IDisposableDependencyObjectWrapper +// { +// private readonly IIocResolver _iocResolver; +// public T Object { get; private set; } +// public DisposableDependencyObjectWrapper(IIocResolver iocResolver, T obj) +// { +// _iocResolver = iocResolver; +// Object = obj; +// } +// public void Dispose() +// { +// _iocResolver.Release(Object); +// } +// } + +// /// +// /// 该接口用于包装从IOC容器解析的对象 +// /// +// public interface IDisposableDependencyObjectWrapper : IDisposableDependencyObjectWrapper +// { + +// } + +// /// +// /// 该接口用于包装从IOC容器解析的对象 +// /// +// /// +// public interface IDisposableDependencyObjectWrapper : IDisposable +// { +// /// +// /// 解析对象 +// /// +// T Object { get; } +// } + +// /// +// /// 此接口用于在单个语句中包装批处理解析的范围 +// /// +// public interface IScopedIocResolver : IIocResolver, IDisposable { } + +// /// +// /// 所有实现这个接口的类都被自动注册为依赖注入作为单例对象 +// /// +// public interface ISingletonDependency +// { +// } + +// /// +// /// 实现这个接口的所有类都会自动注册为依赖注入作为临时对象。 +// /// +// public interface ITransientDependency +// { +// } +//} diff --git a/Vampirewal.Core.VContainer/LICENSE b/Vampirewal.Core.VContainer/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..ddbd00b437e877e43b09521e47a65ad43f04aa8a --- /dev/null +++ b/Vampirewal.Core.VContainer/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 vampirewal + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Vampirewal.Core.VContainer/VIoC.cs b/Vampirewal.Core.VContainer/VIoC.cs new file mode 100644 index 0000000000000000000000000000000000000000..40b1854713cc45ee2a6c4388faebdcd3487b470a --- /dev/null +++ b/Vampirewal.Core.VContainer/VIoC.cs @@ -0,0 +1,432 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:TinyIOC +// 创 建 人:YangCheng +// 创建时间:2022/5/24 19:07:22 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Formats.Asn1; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Vampirewal.Core.VContainer +{ + #region 注册进IOC特性 + /// + /// 注册IOC容器 + /// + [AttributeUsage(AttributeTargets.Class,AllowMultiple =false)] + public class VIocRegisterAttribute : Attribute + { + /// + /// 使用typeof(接口) + /// + public Type ServiceType { get; set; } + + /// + /// 注入类型 + /// + public RegisterType Way { get; set; } + + /// + /// 是否注册单例模式(仅Way为OnlyClass有效) + /// + public bool IsSingleton { get; set; } + + + /// + /// 注册IOC容器 + /// + /// 方式 + /// 是否注册单例模式 + public VIocRegisterAttribute(RegisterType way, bool isSingleton = false) + { + //构造函数 + Way = way; + IsSingleton = isSingleton; + } + } + + /// + /// 方式 + /// + public enum RegisterType + { + /// + /// 仅类 + /// + OnlyClass, + /// + /// 服务 + /// + Service + } + #endregion + + #region 通过IOC获取实例特性 + [AttributeUsage(AttributeTargets.Property)] + public class VIoCGetInstanceAttribute : Attribute + { + public string ClassName { get; set; } + + public Type type { get; set; } + + /// + /// 注入类型 + /// + public RegisterType Way { get; set; } + + public VIoCGetInstanceAttribute(RegisterType Way, string className = "") + { + ClassName = className; + this.Way = Way; + } + } + + + #endregion + + /// + /// Vampirewal.IoC容器 + /// 1、支持特性注册,标记在类上,初始化程序时,调用VIoC.GetInstance().RegisterAll();即可 + /// 2、支持类名注入,可进一步解耦,VIoC.GetInstance().GetInstance("Test3"); + /// 3、支持属性注入,标记在属性上即可,同时也支持传入类名() + /// + public class VIoC : BaseSingleton + { + Dictionary RegisteredServices { get; set; } = new Dictionary(); + Dictionary instances { get; set; } = new Dictionary(); + + /// + /// 注册所有标记了特性的类 + /// + public void RegisterAll() + { + /* + * 注意事项: + * 1、如果是WPF使用的话,建议把ViewModelLocator放在VM类库中 + * 2、然后再调用这个,才能在初始化的时候,找到VM这个类库,然后加载里面的ViewModel,不然的话,找不到VM这个程序集,会无法加载ViewModel + */ + + var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).Where(w => w.GetCustomAttribute() != null).ToArray(); + + foreach (var v in types) + { + var Attribute = v.GetCustomAttribute(); + + if (Attribute != null) + { + if (Attribute.Way == RegisterType.OnlyClass) + { + if (Attribute.IsSingleton) + { + ConstructorInfo[] infoCollection = GatherConstructors(v); + this.instances.Add(v, ConstructService(v, infoCollection)); + } + else + { + this.RegisteredServices.Add(v, v); + } + } + else if (Attribute.Way == RegisterType.Service) + { + this.RegisteredServices.Add(Attribute.ServiceType, v); + } + } + + } + } + + + #region 注册 + /// + /// 注册 + /// + /// 接口 + /// 实现 + public void Register() where TInterface : class where TClass : class + { + if (!this.RegisteredServices.ContainsKey(typeof(TInterface))) + this.RegisteredServices.Add(typeof(TInterface), typeof(TClass)); + else + throw new ArgumentException($"重复的Key值:{typeof(TInterface).Name}"); + } + + /// + /// 注册 + /// + /// 接口 + /// 实现 + public void RegisterSingleton() where TInterface : class where TClass : class + { + if (!this.instances.ContainsKey(typeof(TInterface))) + { + ConstructorInfo[] infoCollection = GatherConstructors(typeof(TClass)); + this.instances.Add(typeof(TInterface), ConstructService(typeof(TClass), infoCollection)); + } + + else + throw new ArgumentException($"重复的Key值:{typeof(TInterface).Name}"); + } + + /// + /// 注册 + /// + /// + public void Register() + { + if (!this.RegisteredServices.ContainsKey(typeof(TClass))) + this.RegisteredServices.Add(typeof(TClass), typeof(TClass)); + else + throw new ArgumentException($"重复的Key值:{typeof(TClass).Name}"); + } + + /// + /// 注册 + /// + /// + /// + /// + public void Register(TClass @class) + { + if (!this.RegisteredServices.ContainsKey(typeof(TClass))) + this.RegisteredServices.Add(typeof(TClass), typeof(TClass)); + else + throw new ArgumentException($"重复的Key值:{typeof(TClass).Name}"); + } + + /// + /// 注册单例模式 + /// + /// + public void RegisterSingleton() + { + if (!this.instances.ContainsKey(typeof(TClass))) + { + ConstructorInfo[] infoCollection = GatherConstructors(typeof(TClass)); + this.instances.Add(typeof(TClass), ConstructService(typeof(TClass), infoCollection)); + } + + + else + throw new ArgumentException($"重复的Key值:{typeof(TClass).Name}"); + } + + /// + /// 注册单例模式 + /// + /// + /// + public void RegisterSingleton(TClass instance) where TClass : class + { + if (!this.instances.ContainsKey(typeof(TClass))) + this.instances.Add(typeof(TClass), instance); + else + throw new ArgumentException($"重复的Key值:{typeof(TClass).Name}"); + } + #endregion + + #region 获取实例 + /// + /// 获取实例 + /// + /// 类型 + /// + public T GetInstance() where T : class + { + return (T)this.GetInstance(typeof(T)); + } + + /// + /// 获取实例 + /// + /// + /// + /// + public object GetInstance(Type type) + { + + if (instances.TryGetValue(type, out object value)) + { + return value; + } + + if (RegisteredServices.TryGetValue(type, out Type implementation)) + { + ConstructorInfo[] infoCollection = GatherConstructors(implementation); + return ConstructService(implementation, infoCollection); + } + throw new ArgumentException($"没有注册实现给定类型的服务: {type.ToString()}"); + } + + /// + /// 通过类名获取实例 + /// + /// + /// + public object GetInstance(string ClassName) + { + Type type = null; + + type = instances.Keys.FirstOrDefault(f => f.Name == ClassName); + + if (type == null) + { + type = RegisteredServices.Keys.FirstOrDefault(f => f.Name == ClassName); + } + + if (type != null) + { + return GetInstance(type); + } + + return type; + } + + /// + /// 指定返回类型和类名获取实例 + /// + /// + /// + /// + public T GetInstance(string ClassName) + { + return (T)this.GetInstance(ClassName); + } + #endregion + + #region 内部方法 + /// + /// 处理注入 + /// + /// + /// + /// + /// + private object ConstructService(Type implementation, ConstructorInfo[] infoCollection) + { + for (int i = 0; i < infoCollection.Length; i++) + { + ConstructorInfo constructorInfo = infoCollection[i]; + ParameterInfo[] parameters = constructorInfo.GetParameters(); + + if (parameters.Length == 0) + { + var obj = Activator.CreateInstance(implementation); + + CheckPropertyDI(implementation, obj); + return obj; + } + + try + { + List paramInstances = ResolveParameters(parameters); + + var obj = Activator.CreateInstance(implementation, paramInstances.ToArray()); + + CheckPropertyDI(implementation, obj); + return obj; + } + catch + { + if (i < infoCollection.Length - 1) + { + continue; + } + + throw; + } + } + + throw new ArgumentException($"无法解决服务问题 {implementation.FullName}"); + } + + /// + /// 获取构造函数及构造函数的数量 + /// + /// + /// + /// + private static ConstructorInfo[] GatherConstructors(Type implementation) + { + ConstructorInfo[] infoCollection = implementation.GetConstructors(); + + if (infoCollection.Length <= 0) + { + throw new ArgumentException($"在这个类型上没有找到公共构造函数: {implementation.FullName}"); + } + + return infoCollection; + } + + /// + /// 获取这个构造函数里的参数并实例化出来 + /// + /// + /// + private List ResolveParameters(ParameterInfo[] parameters) + { + var paramInstances = new List(); + foreach (var par in parameters) + { + var paramType = par.ParameterType; + var instance = this.GetInstance(paramType); + paramInstances.Add(instance); + } + + return paramInstances; + } + + /// + /// 属性注入 + /// + /// + /// + private void CheckPropertyDI(Type type, object obj) + { + var Properties = type.GetProperties().Where(w => w.GetCustomAttribute() != null).ToArray(); + + foreach (var item in Properties) + { + var Attribute = item.GetCustomAttribute(); + + if (!string.IsNullOrEmpty(Attribute.ClassName)) + { + var entity = GetInstance(Attribute.ClassName); + item.SetValue(obj, entity); + + continue; + } + + if (Attribute.Way == RegisterType.OnlyClass) + { + item.SetValue(obj, GetInstance(item.PropertyType.Name)); + } + else + { + Type cur; + + cur = instances.Keys.FirstOrDefault(f => f.Name == item.PropertyType.Name); + + if (cur == null) + { + cur = RegisteredServices.Keys.FirstOrDefault(f => f.Name == item.PropertyType.Name); + } + + item.SetValue(obj, GetInstance(cur)); + } + } + } + #endregion + } +} diff --git a/Vampirewal.Core.VContainer/Vampirewal-Logo.png b/Vampirewal.Core.VContainer/Vampirewal-Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..3d150ba56db89235caebb1676f05415ddc65740d Binary files /dev/null and b/Vampirewal.Core.VContainer/Vampirewal-Logo.png differ diff --git a/Vampirewal.Core.VContainer/Vampirewal.Core.VContainer.csproj b/Vampirewal.Core.VContainer/Vampirewal.Core.VContainer.csproj new file mode 100644 index 0000000000000000000000000000000000000000..a7a7bf1150d813d5843e364426f7560ab4f1d32f --- /dev/null +++ b/Vampirewal.Core.VContainer/Vampirewal.Core.VContainer.csproj @@ -0,0 +1,31 @@ + + + + net5.0 + True + vampirewal + 1.0.0.2 + IoC容器 + Vampirewal-Logo.png + LICENSE + True + + + + + + + + + + + + + + True + \ + + + + + diff --git a/Vampirewal.Core.YuQueHelper/HttpWebClientHelper.cs b/Vampirewal.Core.YuQueHelper/HttpWebClientHelper.cs new file mode 100644 index 0000000000000000000000000000000000000000..32b73638fbe198e369e057d51c9b4530f62ba071 --- /dev/null +++ b/Vampirewal.Core.YuQueHelper/HttpWebClientHelper.cs @@ -0,0 +1,106 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:HttpWebClientHelper +// 创 建 者:杨程 +// 创建时间:2022/2/23 14:28:39 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading.Tasks; +using System.Web; + +namespace Vampirewal.Core.YuQueHelper +{ + internal static class HttpWebClientHelper + { + /// + /// get请求 + /// + /// 请求地址 + /// 语雀个人设置的token + /// 语雀需要收集的用户标识 + /// 请求到的数据 + public static string HttpGet(string url, string token, string userAgent = "netCoreSdk") + { + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); + + request.Headers.Add("User-Agent", HttpUtility.UrlEncode(userAgent)); + request.Headers.Add("X-Auth-Token", HttpUtility.UrlEncode(token)); + + using HttpWebResponse response = (HttpWebResponse)request.GetResponse(); + using StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8); + + return reader.ReadToEnd(); + } + + /// + /// get请求 + /// + /// 请求地址 + /// 语雀个人设置的token + /// 语雀需要收集的用户标识 + /// 请求到的数据 + public static async Task HttpGetAsync(string url, string token, string userAgent = "netCoreSdk") + { + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); + + request.Headers.Add("User-Agent", HttpUtility.UrlEncode(userAgent)); + request.Headers.Add("X-Auth-Token", HttpUtility.UrlEncode(token)); + + using HttpWebResponse response = (HttpWebResponse)request.GetResponse(); + using StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8); + + return await reader.ReadToEndAsync(); + } + + public static string HttpPost(string data,string url, string token, string userAgent = "netCoreSdk") + { + HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); + request.Method = "POST"; + + //string retval = null; + + + request.Headers.Add("User-Agent", HttpUtility.UrlEncode(userAgent)); + request.Headers.Add("X-Auth-Token", HttpUtility.UrlEncode(token)); + request.Headers.Add("Content-Type", "application/json"); + + var bytes = System.Text.UTF8Encoding.UTF8.GetBytes(data); + + using (var stream = request.GetRequestStream()) + { + stream.Write(bytes, 0, bytes.Length); + } + + using (var response = (HttpWebResponse)request.GetResponse()) + { + using (var reader = new System.IO.StreamReader(response.GetResponseStream())) + { + return reader.ReadToEnd(); + } + } + + //HttpWebResponse response = (HttpWebResponse)request.GetResponse();//获取服务器返回的结果 + //Stream getStream = response.GetResponseStream(); + //StreamReader streamreader = new StreamReader(getStream); + //String result = streamreader.ReadToEnd(); + + //return result; + + + //using HttpWebResponse response = (HttpWebResponse)request.GetResponse(); + //using StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8); + } + } +} diff --git a/Vampirewal.Core/Interface/ISubFile.cs b/Vampirewal.Core.YuQueHelper/Model/AbilitiesModel.cs similarity index 54% rename from Vampirewal.Core/Interface/ISubFile.cs rename to Vampirewal.Core.YuQueHelper/Model/AbilitiesModel.cs index 6ab5c54dc00990151ad3699b451a09e5edb24b64..5ef5057c268bef84a9939f3f48d2531667125928 100644 --- a/Vampirewal.Core/Interface/ISubFile.cs +++ b/Vampirewal.Core.YuQueHelper/Model/AbilitiesModel.cs @@ -1,8 +1,8 @@ #region << 文 件 说 明 >> /*---------------------------------------------------------------- -// 文件名称:ISubFile +// 文件名称:AbilitiesModel // 创 建 者:杨程 -// 创建时间:2021/9/16 11:12:06 +// 创建时间:2022/2/23 15:22:20 // 文件版本:V1.0.0 // =============================================================== // 功能描述: @@ -16,14 +16,19 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using Vampirewal.Core.Models; -namespace Vampirewal.Core.Interface +namespace Vampirewal.Core.YuQueHelper.Model { - public interface ISubFile + public class AbilitiesModel { - Guid FileId { get; set; } - FileAttachment File { get; set; } - int order { get; set; } + /// + /// 是否有权限修改 + /// + public bool Update { get; set; } + + /// + /// 是否有权限销毁 + /// + public bool Destroy { get; set; } } } diff --git a/Vampirewal.Core/Models/PersistModel.cs b/Vampirewal.Core.YuQueHelper/Model/DocDetail.cs similarity index 52% rename from Vampirewal.Core/Models/PersistModel.cs rename to Vampirewal.Core.YuQueHelper/Model/DocDetail.cs index 5e7576ad4a21d3a510ab66c4cbd0d7a56524efd9..178f480d2fe6e5421e2b1d821ce10ced93adc1d7 100644 --- a/Vampirewal.Core/Models/PersistModel.cs +++ b/Vampirewal.Core.YuQueHelper/Model/DocDetail.cs @@ -1,8 +1,8 @@ #region << 文 件 说 明 >> /*---------------------------------------------------------------- -// 文件名称:PersistModel +// 文件名称:DocDetail // 创 建 者:杨程 -// 创建时间:2021/9/16 10:49:51 +// 创建时间:2022/2/23 15:22:44 // 文件版本:V1.0.0 // =============================================================== // 功能描述: @@ -13,25 +13,25 @@ using System; using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text; using System.Threading.Tasks; -using System.Xml.Linq; -namespace Vampirewal.Core.Models +namespace Vampirewal.Core.YuQueHelper.Model { /// - /// 所有持久化model的基类,所有的不应被物理删除的model都应该继承这个类 + /// 语雀文档详情 /// - public class PersistModel : BaseModel + public class DocDetail { + /// + /// 文章详情的数据 + /// + public DocDetailData Data { get; set; } - private bool _IsValid; /// - /// IsValid + /// 拥有的权限 /// - [Display(Name = "IsValid")] - public bool IsValid { get => _IsValid; set { _IsValid = value; DoNotify(); } } + public AbilitiesModel Abilities { get; set; } } } diff --git a/Vampirewal.Core/Interface/ISearcher.cs b/Vampirewal.Core.YuQueHelper/Model/DocDetailData.cs similarity index 35% rename from Vampirewal.Core/Interface/ISearcher.cs rename to Vampirewal.Core.YuQueHelper/Model/DocDetailData.cs index 20414c7bc322fefd66d5a42dd7f253bef1af9ea9..e3d5cac0a13953aeec2d3ba8f09ff5a8d2a69f82 100644 --- a/Vampirewal.Core/Interface/ISearcher.cs +++ b/Vampirewal.Core.YuQueHelper/Model/DocDetailData.cs @@ -1,8 +1,8 @@ #region << 文 件 说 明 >> /*---------------------------------------------------------------- -// 文件名称:ISearcher +// 文件名称:DocDetailData // 创 建 者:杨程 -// 创建时间:2021/9/16 12:53:19 +// 创建时间:2022/2/23 15:23:06 // 文件版本:V1.0.0 // =============================================================== // 功能描述: @@ -11,106 +11,124 @@ //----------------------------------------------------------------*/ #endregion +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using Vampirewal.Core.Models; -namespace Vampirewal.Core.Interface +namespace Vampirewal.Core.YuQueHelper.Model { - public interface ISearcher + /// + /// 文章详情的数据 + /// + public class DocDetailData { - #region Property - - #region 分页相关 /// - /// 当前页 + /// 文档编号 /// - int Page { get; set; } + public string Id { get; set; } + /// - /// 每页数 + /// 文档路径 /// - int Limit { get; set; } + public string slug { get; set; } + /// - /// 记录数 + /// 标题 /// - long Count { get; set; } + public string title { get; set; } + /// - /// 分页数 + /// 仓库编号就是repoid /// - int PageCount { get; set; } - #endregion + public string Book_Id { get; set; } /// - /// 记录 Controller 中的表单数据 + /// 仓库信息 /// - Dictionary FC { get; set; } + public object Book { get; set; } - IDataContext DC { get; set; } /// - /// VMFullName + /// 用户/团队编号 /// - string VMFullName { get; } + public string User_Id { get; set; } + /// + /// 用户/团队信息 + /// + public object User { get; set; } - LoginUserInfo LoginUserInfo { get; set; } - #region 未使用 /// - /// 排序信息 + /// 表述了正文的格式[lake,markdown] /// - SortInfo SortInfo { get; set; } + public string format { get; set; } + /// - /// 是否搜索树形结构数据 + /// 正文 Markdown 源代码 /// - bool TreeMode { get; set; } + public string body { get; set; } + /// - /// 树形结构数据父Id + /// 草稿 Markdown 源代码 /// - Guid? ParentId { get; set; } + public string Body_Draft { get; set; } + /// - /// 是否有效,针对继承PersistPoco的Model + /// 转换过后的正文 HTML /// - bool? IsValid { get; set; } + public string Body_Html { get; set; } + /// - /// 用于框架判断列表页是否全局刷新 + /// 语雀 lake 格式的文档内容 /// - bool IsPostBack { get; set; } - #endregion + public string Body_Lake { get; set; } - #endregion + /// + /// 文档创建人 User Id + /// + public string Creator_Id { get; set; } - #region Event + /// + /// 公开级别 [0 - 私密, 1 - 公开] + /// + [JsonProperty("public")] + public int Public { get; set; } /// - /// InitVM 完成后触发的事件 + /// 状态 [0 - 草稿, 1 - 发布] /// - event Action OnAfterInit; + public int Status { get; set; } + /// - /// ReInitVM 完成后触发的事件 + /// 赞数量 /// - event Action OnAfterReInit; + public int Likes_Count { get; set; } - #endregion + /// + /// 评论数量 + /// + public int Comments_Count { get; set; } - #region Method /// - /// 将源 VM 的 FC 等内容复制到本VM中 + /// 文档内容更新时间 /// - /// - //void CopyContext(IBaseVM vm); + public DateTime Content_Updated_At { get; set; } /// - /// 调用 InitVM 并触发 OnAfterInit 事件 + /// 删除时间,未删除为 null /// - void DoInit(); + public DateTime? Deleted_At { get; set; } /// - /// 调用 ReInitVM 并触发 OnAfterReInit 事件 + /// 创建时间 /// - void DoReInit(); + public DateTime Created_At { get; set; } - #endregion + /// + /// 更新时间 + /// + public DateTime Updated_At { get; set; } } } diff --git a/Vampirewal.Core/Interface/IBaseCRUDVM.cs b/Vampirewal.Core.YuQueHelper/Model/Topic.cs similarity index 45% rename from Vampirewal.Core/Interface/IBaseCRUDVM.cs rename to Vampirewal.Core.YuQueHelper/Model/Topic.cs index 36cac8f0e0bcaf0b6b0bb1a463a7fec07eea533a..f2305dfd95c74a6099ea82650b5af1ffb34a214f 100644 --- a/Vampirewal.Core/Interface/IBaseCRUDVM.cs +++ b/Vampirewal.Core.YuQueHelper/Model/Topic.cs @@ -1,8 +1,8 @@ #region << 文 件 说 明 >> /*---------------------------------------------------------------- -// 文件名称:IBaseCRUDVM +// 文件名称:Topic // 创 建 者:杨程 -// 创建时间:2021/9/16 10:04:43 +// 创建时间:2022/2/23 15:23:34 // 文件版本:V1.0.0 // =============================================================== // 功能描述: @@ -12,78 +12,81 @@ #endregion using System; -using System.Buffers.Text; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using Vampirewal.Core.Models; -namespace Vampirewal.Core.Interface +namespace Vampirewal.Core.YuQueHelper.Model { /// - /// 单表增删改查VM的接口 + /// 目录 /// - public interface IBaseCRUDVM where T : TopBaseModel, new() + public class Topic { /// - /// 实体类 + /// 节点类型 /// - T Entity { get; } + public string Type { get; set; } + /// - /// 根据主键Id获取Entity + /// 节点名称 /// - /// 主键Id - void SetEntityById(object id); + public string Title { get; set; } /// - /// 设置Entity + /// 节点唯一 id /// - /// 要设定的TopBasePoco - void SetEntity(object entity); + public string Uuid { get; set; } /// - /// 添加 + /// 链接或文档 slug /// - void DoAdd(); + public string Url { get; set; } /// - /// 异步添加 + /// 上一个节点 uuid /// - Task DoAddAsync(); + public string Prev_Uuid { get; set; } /// - /// 修改 + /// 下一个节点 uuid /// - void DoEdit(bool updateAllFields); + public string Sibling_uuid { get; set; } + /// - /// 异步修改 + /// 第一个子节点 uuid /// - /// - Task DoEditAsync(bool updateAllFields); + public string Child_uuid { get; set; } /// - /// 删除,对于TopBaseModel进行物理删除,对于PersistPoco把IsValid修改为false + /// 父亲节点 uuid /// - void DoDelete(); + public string Parent_uuid { get; set; } + /// - /// 异步删除 + /// 仅文档类型节点,doc id /// - Task DoDeleteAsync(); + public string Doc_id { get; set; } /// - /// 彻底删除,进行物理删除 + /// 节点层级 /// - void DoRealDelete(); + public int Level { get; set; } + + /// + /// 节点id + /// + public string Id { get; set; } + /// - /// 异步真删除 + /// 链接是否在新窗口打开,0 在当前页面打开,1 在新窗口打开 /// - Task DoRealDeleteAsync(); + public int Open_window { get; set; } - /// - /// 错误验证 + /// 节点是否可见,0 不可见,1 可见 /// - void Validate(); + public int Visible { get; set; } } } diff --git a/YC.WPF.Theme/Style/CutomControl/Container/GridEx.cs b/Vampirewal.Core.YuQueHelper/Model/TopicInfo.cs similarity index 64% rename from YC.WPF.Theme/Style/CutomControl/Container/GridEx.cs rename to Vampirewal.Core.YuQueHelper/Model/TopicInfo.cs index 4f782d7be163d92e5a394a793a81622c6c470e37..12fb7459a646f5b59f5fe8e9e59588115d7a20c6 100644 --- a/YC.WPF.Theme/Style/CutomControl/Container/GridEx.cs +++ b/Vampirewal.Core.YuQueHelper/Model/TopicInfo.cs @@ -1,8 +1,8 @@ #region << 文 件 说 明 >> /*---------------------------------------------------------------- -// 文件名称:GridEx +// 文件名称:TopicInfo // 创 建 者:杨程 -// 创建时间:2021/8/13 17:53:04 +// 创建时间:2022/2/23 15:24:00 // 文件版本:V1.0.0 // =============================================================== // 功能描述: @@ -16,15 +16,17 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using System.Windows.Controls; -namespace YC.WPF.Theme.Style.CutomControl.Container +namespace Vampirewal.Core.YuQueHelper.Model { /// - /// Grid控件增强 + /// 目录信息 /// - public class GridEx:Grid + public class TopicInfo { - + /// + /// 目录 + /// + public List Data { get; set; } } } diff --git a/Vampirewal.Core/AppConfig/CS.cs b/Vampirewal.Core.YuQueHelper/Model/TopicTree.cs similarity index 57% rename from Vampirewal.Core/AppConfig/CS.cs rename to Vampirewal.Core.YuQueHelper/Model/TopicTree.cs index 5ba23607bd0118d962bcd17bf6b15a83a5434260..b20f9738113cbed60756e4cac23916f4a1f10d27 100644 --- a/Vampirewal.Core/AppConfig/CS.cs +++ b/Vampirewal.Core.YuQueHelper/Model/TopicTree.cs @@ -1,8 +1,8 @@ #region << 文 件 说 明 >> /*---------------------------------------------------------------- -// 文件名称:CS +// 文件名称:TopicTree // 创 建 者:杨程 -// 创建时间:2021/9/15 20:11:59 +// 创建时间:2022/2/23 15:24:22 // 文件版本:V1.0.0 // =============================================================== // 功能描述: @@ -17,18 +17,16 @@ using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Vampirewal.Core.AppConfig +namespace Vampirewal.Core.YuQueHelper.Model { /// - /// 连接字符串设置 + /// 目录树形结构的输出对象 /// - public class CS + public class TopicTree : Topic { - - public string Key { get; set; } - public string Value { get; set; } - public DBTypeEnum? DbType { get; set; } - public string Version { get; set; } - public string DbContext { get; set; } + /// + /// 树结构的子集 + /// + public List Child { get; set; } } } diff --git a/Vampirewal.Core.YuQueHelper/Vampirewal.Core.YuQueHelper.csproj b/Vampirewal.Core.YuQueHelper/Vampirewal.Core.YuQueHelper.csproj new file mode 100644 index 0000000000000000000000000000000000000000..47c5a7047f647941bdac810204bf459bf6a15292 --- /dev/null +++ b/Vampirewal.Core.YuQueHelper/Vampirewal.Core.YuQueHelper.csproj @@ -0,0 +1,11 @@ + + + + net5.0 + + + + + + + diff --git a/Vampirewal.Core.YuQueHelper/YuQueClient.cs b/Vampirewal.Core.YuQueHelper/YuQueClient.cs new file mode 100644 index 0000000000000000000000000000000000000000..dec07a874bda9bafe654ce78c674836d727ac5f8 --- /dev/null +++ b/Vampirewal.Core.YuQueHelper/YuQueClient.cs @@ -0,0 +1,246 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:YuQueClient +// 创 建 者:杨程 +// 创建时间:2022/2/23 15:15:18 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Vampirewal.Core.YuQueHelper.Model; + +namespace Vampirewal.Core.YuQueHelper +{ + public interface IYuQueClient + { + /// + /// 语雀个人设置的Token + /// + string Token { get; } + + /// + /// 语雀收集的用户标识 + /// + string UserAgent { get; } + + /// + /// 语雀基础的api域名 + /// + string baseUrl { get; } + + List DocRepos { get; } + + /// + /// 添加知识库名称 + /// + /// + void AddDocRepos(string DocReposName); + + /// + /// 批量添加知识库名称 + /// + /// + void AddRangeDocRepos(List DocReposNames); + /// + /// 设置基础配置 + /// + /// 语雀个人设置的skd + /// 语雀收集的用户标识 + void SetConfig(string token, string userAgent = "Vampirewal.Core"); + + /// + /// 获取单篇文档的详细信息 + /// + /// 文档所属的知识库 如:https://www.yuque.com/yuque/developer/repo 中的【yuque/developer】 + /// 文档的路径 如:https://www.yuque.com/yuque/developer/repo 中的【repo】 + /// 文档的详细信息 + DocDetail GetDocDetail(string docRepo, string slug); + + + /// + /// 新增1条文档 + /// + /// 文档所属的知识库 如:https://www.yuque.com/yuque/developer/repo 中的【yuque/developer】 + /// Json数据 + string PostDocDetail(string docRepo, string data); + + + /// + /// 获取知识库下的目录 + /// + /// 文档所属的知识库 如:https://www.yuque.com/yuque/developer/repo 中的【yuque/developer】 + /// 目录信息 + List GetRepoTopic(string docRepo); + + /// + /// 获取知识库下的目录(树结构) + /// + /// 文档所属的知识库 如:https://www.yuque.com/yuque/developer/repo 中的【yuque/developer】 + /// 目录信息 + List GetRepoTopicTree(string docRepo); + } + + public sealed class YuQueClient: IYuQueClient + { + /// + /// 语雀个人设置的skd + /// + public string Token { get;private set; } + + /// + /// 语雀收集的用户标识 + /// + public string UserAgent { get;private set; } + + /// + /// 语雀基础的api域名 + /// + public string baseUrl { get; private set; } = "https://www.yuque.com/api/v2/"; + + /// + /// 设置基础配置 + /// + /// 语雀个人设置的skd + /// 语雀收集的用户标识 + public void SetConfig(string token, string userAgent = "Vampirewal.Core") + { + Token = token; + UserAgent = userAgent; + } + + + + #region 知识库 + /// + /// 知识库列表 + /// + public List DocRepos { get; private set; } + /// + /// 添加知识库名称 + /// + /// + public void AddDocRepos(string DocReposName) + { + DocRepos.Add(DocReposName); + } + + /// + /// 批量添加知识库名称 + /// + /// + public void AddRangeDocRepos(List DocReposNames) + { + DocRepos.AddRange(DocReposNames); + } + #endregion + + + /// + /// 获取单篇文档的详细信息 + /// + /// 文档所属的知识库 如:https://www.yuque.com/yuque/developer/repo 中的【yuque/developer】 + /// 文档的路径 如:https://www.yuque.com/yuque/developer/repo 中的【repo】 + /// 文档的详细信息 + public DocDetail GetDocDetail(string docRepo, string slug) + { + string jsonStr = HttpWebClientHelper.HttpGet($"{baseUrl}repos/{docRepo}/docs/{slug}", Token, UserAgent); + return JsonConvert.DeserializeObject(jsonStr); + } + + /// + /// 新增1条文档 + /// + /// 文档所属的知识库 如:https://www.yuque.com/yuque/developer/repo 中的【yuque/developer】 + /// Json数据 + public string PostDocDetail(string docRepo,string data) + { + return HttpWebClientHelper.HttpPost(data, $"{baseUrl}repos/{docRepo}/docs", Token, UserAgent); + } + + /// + /// 获取知识库下的目录 + /// + /// 文档所属的知识库 如:https://www.yuque.com/yuque/developer/repo 中的【yuque/developer】 + /// 目录信息 + public List GetRepoTopic(string docRepo) + { + string jsonStr = HttpWebClientHelper.HttpGet($"{baseUrl}repos/{docRepo}/toc", Token, UserAgent); + return JsonConvert.DeserializeObject(jsonStr).Data; + } + + /// + /// 获取知识库下的目录(树结构) + /// + /// 文档所属的知识库 如:https://www.yuque.com/yuque/developer/repo 中的【yuque/developer】 + /// 目录信息 + public List GetRepoTopicTree(string docRepo) + { + string jsonStr = HttpWebClientHelper.HttpGet($"{baseUrl}repos/{docRepo}/toc", Token, UserAgent); + List topicList = JsonConvert.DeserializeObject(jsonStr).Data; + List result = new List(); + var firstList = topicList.Where(x => x.Level == 0);//第一级 + return ProcessTree(firstList, topicList); + } + + /// + /// 递归处理树结构 + /// + /// + /// + /// + private List ProcessTree(IEnumerable child, List allList) + { + List result = new List(); + + foreach (Topic item in child) + { + TopicTree topicTree = item.ToEntity(); + var childList = allList.Where(x => x.Parent_uuid == item.Uuid); + if (childList.Count() > 0) + { + topicTree.Child = ProcessTree(childList, allList); + } + result.Add(topicTree); + } + + return result; + } + + } + + internal static class TopicExtension + { + internal static TopicTree ToEntity(this Topic topic) + { + TopicTree result = new TopicTree + { + Child = new List(), + Child_uuid = topic.Child_uuid, + Doc_id = topic.Doc_id, + Id = topic.Id, + Level = topic.Level, + Open_window = topic.Open_window, + Parent_uuid = topic.Parent_uuid, + Prev_Uuid = topic.Prev_Uuid, + Sibling_uuid = topic.Sibling_uuid, + Title = topic.Title, + Type = topic.Type, + Url = topic.Url, + Uuid = topic.Uuid, + Visible = topic.Visible + }; + + return result; + } + } +} diff --git a/Vampirewal.Core/AOP/Attributes/TryCatchAttribute.cs b/Vampirewal.Core/AOP/Attributes/TryCatchAttribute.cs new file mode 100644 index 0000000000000000000000000000000000000000..89e23b0f74098f750cc97ee465391b8e0687ed53 --- /dev/null +++ b/Vampirewal.Core/AOP/Attributes/TryCatchAttribute.cs @@ -0,0 +1,56 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: TryCatchAttrubute +// 创建者: 杨程 +// 创建日期: 2022/12/13 13:48:05 + +//----------------------------------------------------------------*/ +#endregion + + + + + +namespace Vampirewal.Core.AOP; + +/// +/// 通过AOP的方式执行TryCatch(案例) +/// +public class TryCatchAttribute : VampirewalAopAttribute +{ + public TryCatchAttribute() + { + this.IsInnerInvoke = true; + } + + public override void After(IInvocation invocation, Exception exp) + { + if (exp != null) + { + Debug.WriteLine("处理错误,错误信息为:" + exp.InnerException.Message ?? exp.Message); + } + } + + public override void Before() + { + Debug.WriteLine("开始捕捉异常"); + } + + public override void Middle(IInvocation invocation) + { + try + { + invocation.Proceed(); + } + catch (Exception exp) + { + Debug.WriteLine(string.IsNullOrEmpty(exp.Message) ? exp.InnerException.Message : exp.Message); + } + } +} diff --git a/Vampirewal.Core/AOP/Attributes/VampirewalAopAttribute.cs b/Vampirewal.Core/AOP/Attributes/VampirewalAopAttribute.cs new file mode 100644 index 0000000000000000000000000000000000000000..cfcc148519f93ee43fca41b1999593c49fd927fc --- /dev/null +++ b/Vampirewal.Core/AOP/Attributes/VampirewalAopAttribute.cs @@ -0,0 +1,71 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: VampirewalAopAttribute +// 创建者: 杨程 +// 创建日期: 2022/12/13 13:37:57 + +//----------------------------------------------------------------*/ +#endregion + + + +namespace Vampirewal.Core.AOP; + +/// +/// VampirewalAop特性基类 +/// +[AttributeUsage(AttributeTargets.Method)] +public abstract class VampirewalAopAttribute : Attribute +{ + /// + /// + /// + public bool IsInnerInvoke { set; get; } + /// + /// 执行位置 + /// + public InvokeLocation Location { set; get; } + + /// + /// 方法执行后 + /// + /// + /// + public abstract void After(IInvocation invocation, Exception exp); + + /// + /// 方法执行中 + /// + /// + public abstract void Middle(IInvocation invocation); + + /// + /// 方法执行前 + /// + public abstract void Before(); +} + +/// +/// 执行位置枚举 +/// +public enum InvokeLocation +{ + /// + /// 中间 + /// + Both = 0, + /// + /// 执行前 + /// + Before = 1, + /// + /// 执行后 + /// + After = 2 +} diff --git a/Vampirewal.Core/AOP/InterceptClassFactory.cs b/Vampirewal.Core/AOP/InterceptClassFactory.cs new file mode 100644 index 0000000000000000000000000000000000000000..40739ce9ea240fd73f01d4da8fc553c59556f998 --- /dev/null +++ b/Vampirewal.Core/AOP/InterceptClassFactory.cs @@ -0,0 +1,56 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: InterceptClassFactory +// 创建者: 杨程 +// 创建日期: 2022/12/13 13:20:45 + +//----------------------------------------------------------------*/ +#endregion + + + +namespace Vampirewal.Core.AOP; + +/// +/// 拦截代理类生成工厂 +/// +public class InterceptClassFactory +{ + /// + /// 获取方法拦截代理类实例 + /// + /// 被代理类 + /// 构造参数 + /// + public static T GetInterceptClass(params object[] args) where T : class + { + ProxyGenerator generator = new ProxyGenerator();//实例化【代理类生成器】 + + var test = typeof(T).GetCustomAttributes(typeof(IInterceptor), true).Cast().ToArray(); + + T result = generator.CreateClassProxy(typeof(T), args, test) as T;//创建方法拦截代理类实例。 + return result; + } + + /// + /// 获取方法拦截代理类实例 + /// + /// 被代理类的类型 + /// 构造函数参数 + /// + public static object GetInterceptClass(Type type,params object[] args) + { + ProxyGenerator generator = new ProxyGenerator();//实例化【代理类生成器】 + + var test = type.GetCustomAttributes(typeof(IInterceptor), true).Cast().ToArray(); + + object result = generator.CreateClassProxy(type, args, test) ;//创建方法拦截代理类实例。 + return result; + } +} diff --git a/Vampirewal.Core/AOP/Intercepts/AddPropertyNotifyIntercept.cs b/Vampirewal.Core/AOP/Intercepts/AddPropertyNotifyIntercept.cs new file mode 100644 index 0000000000000000000000000000000000000000..681a4782ceb15f4e9f32357508d89e8441f6271f --- /dev/null +++ b/Vampirewal.Core/AOP/Intercepts/AddPropertyNotifyIntercept.cs @@ -0,0 +1,40 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: PropertyNotifyIntercept +// 创建者: 杨程 +// 创建日期: 2022/12/13 10:03:52 + +//----------------------------------------------------------------*/ +#endregion + + + +namespace Vampirewal.Core.AOP; + +/// +/// 属性更新拦截器,用于MVVM +/// +[AttributeUsage(AttributeTargets.Class)] +public class AddPropertyNotifyIntercept : Attribute, IInterceptor +{ + public void Intercept(IInvocation invocation) + { + //正常执行 + invocation.Proceed(); + + //获取方法名称 + var methodName = invocation.Method.Name; + //如果方法名是set开头,那么调用一下属性通知 + if (methodName.StartsWith("set_")) + { + //var Target = invocation.InvocationTarget as ObservableObject; + //Target. (invocation.Method.Name.Substring(4)); + } + } +} diff --git a/Vampirewal.Core/AOP/Intercepts/VampirewalAopIntercept.cs b/Vampirewal.Core/AOP/Intercepts/VampirewalAopIntercept.cs new file mode 100644 index 0000000000000000000000000000000000000000..fec95f21f9892fbf9434a044c65ab1ae82171777 --- /dev/null +++ b/Vampirewal.Core/AOP/Intercepts/VampirewalAopIntercept.cs @@ -0,0 +1,83 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: AopIntercept +// 创建者: 杨程 +// 创建日期: 2022/12/13 10:02:14 + +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.AOP; + +/// +/// AOP拦截器 +/// +[AttributeUsage(AttributeTargets.Class)] +public class VampirewalAopIntercept : Attribute, IInterceptor +{ + public void Intercept(IInvocation invocation) + { + var Attributes = invocation.MethodInvocationTarget.GetCustomAttributes(true); + + foreach (var attribute in Attributes) + { + if (attribute is VampirewalAopAttribute) + { + if ((attribute as VampirewalAopAttribute).Location == InvokeLocation.Before + || (attribute as VampirewalAopAttribute).Location == InvokeLocation.Both) + { + (attribute as VampirewalAopAttribute).Before(); + } + } + } + + if (Regex.IsMatch(invocation.Method.Name, @"[gs]et_") || Attributes.Count(p => + { return (p is VampirewalAopAttribute && (p as VampirewalAopAttribute).IsInnerInvoke == true); }) <= 0) + { + invocation.Proceed(); + } + + foreach (var attribute in Attributes) + { + if (attribute is VampirewalAopAttribute) + { + (attribute as VampirewalAopAttribute).Middle(invocation); + } + } + + + if (invocation.ReturnValue is Task) + { + (invocation.ReturnValue as Task).ContinueWith(delegate (Task t) { + AfterInvoke(Attributes, invocation, t.Exception); + }); + } + else + { + AfterInvoke(Attributes, invocation, null); + } + } + private void AfterInvoke(object[] Attributes, IInvocation invocation, Exception exp) + { + foreach (var attribute in Attributes) + { + if (attribute is VampirewalAopAttribute) + { + if ((attribute as VampirewalAopAttribute).Location == InvokeLocation.After + || (attribute as VampirewalAopAttribute).Location == InvokeLocation.Both) + { + (attribute as VampirewalAopAttribute).After(invocation, exp); + } + } + } + } +} diff --git a/Vampirewal.Core/AppConfig/AppConfig.cs b/Vampirewal.Core/AppConfig/AppConfig.cs deleted file mode 100644 index f7339b8d55227ad92b1ccba34ef102871fb8443d..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/AppConfig/AppConfig.cs +++ /dev/null @@ -1,422 +0,0 @@ -#region<<文 件 说 明>> -/*---------------------------------------------------------------- -// 文件名称:AppConfig -// 创 建 者:杨程 -// 创建时间:2021/3/4 星期四 15:59:25 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using Vampirewal.Core.AppConfig; -using Vampirewal.Core.Models; - -namespace Vampirewal.Core -{ - /// - /// 对应config.json文件 - /// - /// 配置文件实体类 - [Obsolete("该类属于代码演示使用,不用于实际开发", true)] - public static class AppConfig where T : AppConfigBaseModel, new() - { - /// - /// 配置文件 - /// - public static T Config { get; set; } - - /// - /// 读取配置文件 - /// - public static void LoadAppConfig() - { - if (Config == null) - { - var configFile = $"{AppDomain.CurrentDomain.BaseDirectory}config.json"; - - if (File.Exists(configFile)) - { - Config = JsonConvert.DeserializeObject(JsonHelper.Readjson(configFile)); - } - else - { - T t = new T(); - var json = JsonConvert.SerializeObject(t); - var formatStr = JsonHelper.FormatJsonString(json); - FileStream fs = File.Create(configFile); - fs.Dispose(); - File.AppendAllText(configFile, formatStr); - - Config = t; - } - } - } - - /// - /// 保存配置文件 - /// - public static void Save(T entity) - { - var jsonStr = JsonConvert.SerializeObject(entity); - var formatStr = JsonHelper.FormatJsonString(jsonStr); - var configFile = $"{AppDomain.CurrentDomain.BaseDirectory}config.json"; - if (File.Exists(configFile)) - { - File.Delete(configFile); - } - File.AppendAllText(configFile, formatStr); - } - - } - - /// - /// AppConfig配置model基类,需继承 - /// - public class AppConfigBaseModel - { - /// - /// app中文名 - /// - public string AppChineseName { get; set; }//展示界面顶部的名称 - /// - /// app名称 - /// - public string AppName { get; set; }//用于区分不同用户的名称,或根据这个建立数据库名称 - - #region ConnectionStrings - - private List _connectStrings; - - /// - /// ConnectionStrings - /// - public List ConnectionStrings - { - get - { - if (_connectStrings == null) - { - _connectStrings = new List(); - } - return _connectStrings; - } - set - { - _connectStrings = value; - } - } - - #endregion - - #region Domains - - //private Dictionary _domains; - - ///// - ///// ConnectionStrings - ///// - //public Dictionary Domains - //{ - // get - // { - // if (_domains == null) - // { - // _domains = new Dictionary(); - // } - // return _domains; - // } - // set - // { - // _domains = value; - // foreach (var item in _domains) - // { - // if (item.Value != null) - // { - // item.Value.Name = item.Key; - // } - // } - // } - //} - - #endregion - - #region File attachment save mode - - private SaveFileModeEnum? _saveFileMode; - - /// - /// File attachment save mode - /// - [Obsolete("use Configs.FileUploadOptions instead")] - public SaveFileModeEnum? SaveFileMode - { - get - { - return _saveFileMode; - } - set - { - _saveFileMode = value; - } - } - - #endregion - - #region File attachment upload path - private string _uploadDir; - - /// - /// File attachment upload path - /// - [Obsolete("use Configs.FileUploadOptions instead")] - public string UploadDir - { - get - { - return _uploadDir; - } - set - { - _uploadDir = value; - } - } - - #endregion - - #region Auto sync db - - private bool? _syncdb; - - /// - /// Auto sync db(not supportted) - /// - public bool SyncDB - { - get - { - return _syncdb ?? false; - } - set - { - _syncdb = value; - } - } - - #endregion - - #region Database type - - private DBTypeEnum? _dbtype; - - /// - /// Database type - /// - public DBTypeEnum DbType - { - get - { - if (_dbtype == null) - { - _dbtype = DBTypeEnum.SqlServer; - } - return _dbtype.Value; - } - set - { - _dbtype = value; - } - } - - public bool IsOldSqlServer { get; set; } - - #endregion - - - - - - #region EncryptKey - - private string _encryptKey; - - /// - /// EncryptKey - /// - public string EncryptKey - { - get - { - if (string.IsNullOrEmpty(_encryptKey)) - { - _encryptKey = string.Empty; - } - return _encryptKey; - } - set - { - _encryptKey = value; - } - } - - #endregion - - #region Custom settings - - private Dictionary _appSettings; - - /// - /// Custom settings - /// - public Dictionary AppSettings - { - get - { - if (_appSettings == null) - { - _appSettings = new Dictionary(); - } - return _appSettings; - } - set - { - _appSettings = value; - } - } - - #endregion - - - - - - #region FileOptions - - private FileUploadOptions _fileUploadOptions; - - /// - /// FileOptions - /// - public FileUploadOptions FileUploadOptions - { - get - { - if (_fileUploadOptions == null) - { - _fileUploadOptions = new FileUploadOptions() - { - UploadLimit = DefaultConfigConsts.DEFAULT_UPLOAD_LIMIT, - SaveFileMode = SaveFileModeEnum.Database, - UploadDir = DefaultConfigConsts.DEFAULT_UPLOAD_DIR - }; - } - // TODO下个版本中删除 else里面的逻辑 - else - { - if (!string.IsNullOrEmpty(_uploadDir)) - { - _fileUploadOptions.UploadDir = _uploadDir; - } - if (_saveFileMode.HasValue) - { - _fileUploadOptions.SaveFileMode = _saveFileMode.Value; - } - } - return _fileUploadOptions; - } - set - { - _fileUploadOptions = value; - } - } - - #endregion - - - - #region Is FileAttachment public - - private bool? _isFilePublic; - - /// - /// Is FileAttachment public - /// - public bool IsFilePublic - { - get - { - return _isFilePublic ?? false; - } - set - { - _isFilePublic = value; - } - } - - #endregion - - - #region Cors configs - - //private Cors _cors; - - ///// - ///// Cors configs - ///// - //public Cors CorsOptions - //{ - // get - // { - // if (_cors == null) - // { - // _cors = new Cors(); - // _cors.Policy = new List(); - // } - // return _cors; - // } - // set - // { - // _cors = value; - // } - //} - - #endregion - - #region Support Languages - - private string _languages; - - /// - /// Support Languages - /// - public string Languages - { - get - { - if (string.IsNullOrEmpty((_languages))) - { - _languages = "zh"; - } - return _languages; - } - set - { - _languages = value; - } - } - - #endregion - } - - - - -} \ No newline at end of file diff --git a/Vampirewal.Core/AppConfig/DefaultConfigConsts.cs b/Vampirewal.Core/AppConfig/DefaultConfigConsts.cs index 1af9b4fe8ab1019490990cef456a17038c5c1472..13e7d92ab837d3397497f91e49903e22a8dcf721 100644 --- a/Vampirewal.Core/AppConfig/DefaultConfigConsts.cs +++ b/Vampirewal.Core/AppConfig/DefaultConfigConsts.cs @@ -11,47 +11,44 @@ //----------------------------------------------------------------*/ #endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Vampirewal.Core.AppConfig + + +namespace Vampirewal.Core.AppConfig; + +/// +/// DefaultConfigConsts +/// +[Obsolete("废弃",true)] +public static class DefaultConfigConsts { /// - /// DefaultConfigConsts + /// 默认上传路径 + /// + public const string DEFAULT_UPLOAD_DIR = "d:\\upload"; + + /// + /// 默认列表行数 + /// + public const int DEFAULT_RPP = 20; + + /// + /// 默认上传文件限制 + /// + public const int DEFAULT_UPLOAD_LIMIT = 20 * 1024 * 1024; + + /// + /// 默认允许ComboBox搜索 + /// + public const bool DEFAULT_COMBOBOX_DEFAULT_ENABLE_SEARCH = true; + + /// + /// 默认开启DateTime只读 + /// + public const bool DEFAULT_DATETIME_DEFAULT_READONLY = true; + + /// + /// 默认展开SearchPanel内容 /// - public static class DefaultConfigConsts - { - /// - /// 默认上传路径 - /// - public const string DEFAULT_UPLOAD_DIR = "d:\\upload"; - - /// - /// 默认列表行数 - /// - public const int DEFAULT_RPP = 20; - - /// - /// 默认上传文件限制 - /// - public const int DEFAULT_UPLOAD_LIMIT = 20 * 1024 * 1024; - - /// - /// 默认允许ComboBox搜索 - /// - public const bool DEFAULT_COMBOBOX_DEFAULT_ENABLE_SEARCH = true; - - /// - /// 默认开启DateTime只读 - /// - public const bool DEFAULT_DATETIME_DEFAULT_READONLY = true; - - /// - /// 默认展开SearchPanel内容 - /// - public const bool DEFAULT_SEARCHPANEL_DEFAULT_EXPAND = true; - } + public const bool DEFAULT_SEARCHPANEL_DEFAULT_EXPAND = true; } diff --git a/Vampirewal.Core/Support/ExtraClass.cs b/Vampirewal.Core/AppConfig/DomainSetting.cs similarity index 30% rename from Vampirewal.Core/Support/ExtraClass.cs rename to Vampirewal.Core/AppConfig/DomainSetting.cs index 5b7a8888fbc0f32da2a1d3cac5b44af101652097..f3f0c38ac49e8b19ac5151961169c61bd046a46b 100644 --- a/Vampirewal.Core/Support/ExtraClass.cs +++ b/Vampirewal.Core/AppConfig/DomainSetting.cs @@ -1,8 +1,8 @@ #region << 文 件 说 明 >> /*---------------------------------------------------------------- -// 文件名称:ExtraClass +// 文件名称:DomainSetting // 创 建 者:杨程 -// 创建时间:2021/9/16 10:53:23 +// 创建时间:2022/2/16 15:13:29 // 文件版本:V1.0.0 // =============================================================== // 功能描述: @@ -11,58 +11,57 @@ //----------------------------------------------------------------*/ #endregion -using System.Collections.Generic; -namespace Vampirewal.Core + + +namespace Vampirewal.Core.AppConfig; + +/// +/// 连接域设置 +/// +[Obsolete("废弃", true)] +public class DomainSetting { /// - /// 简单属性结构类 + /// 连接名 /// - public class SimpleTreeTextAndValue - { + public string Name { get; set; } - public object Id { get; set; } - public object Text { get; set; } - public object ParentId { get; set; } - } + /// + /// 地址 + /// + public string Address { get; set; } /// - /// 简单键值对类,用来存著生成下拉菜单的数据 + /// 端口号 /// - public class SimpleTextAndValue - { - public object Text { get; set; } - public object Value { get; set; } - } + public int? Port { get; set; } /// - /// 数据库排序类 + /// 输入网址 /// - public class SortInfo - { - public string Property { get; set; } - public SortDir Direction { get; set; } - } + public string EntryUrl { get; set; } - public class ErrorObj - { - public Dictionary Form { get; set; } - public List Message { get; set; } - } /// - /// 简单传值类 + /// 连接地址 /// - public class SimplePassData + [NotMapped] + [JsonIgnore] + public string Url { - /// - /// 名称 - /// - public string Key { get; set; } - - /// - /// 值 - /// - public object Value { get; set; } + get + { + var rv = Address; + if (rv.ToLower().StartsWith("http://") == false && rv.ToLower().StartsWith("https://") == false) + { + rv = "http://" + rv; + } + if (Port != null) + { + rv += ":" + Port; + } + return rv; + } } } diff --git a/Vampirewal.Core/AppConfig/FileUploadOptions.cs b/Vampirewal.Core/AppConfig/FileUploadOptions.cs index 236df65d0b49009273c24d8e5c176d62a7b62b00..f0843ab2a7130571cc8a35c0e7089d84a458b97a 100644 --- a/Vampirewal.Core/AppConfig/FileUploadOptions.cs +++ b/Vampirewal.Core/AppConfig/FileUploadOptions.cs @@ -11,32 +11,28 @@ //----------------------------------------------------------------*/ #endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Vampirewal.Core.AppConfig + + +namespace Vampirewal.Core.AppConfig; + +/// +/// FileOptions +/// +public class FileUploadOptions { /// - /// FileOptions + /// 文件保存位置 /// - public class FileUploadOptions - { - /// - /// 文件保存位置 - /// - public SaveFileModeEnum SaveFileMode { get; set; } + public SaveFileModeEnum SaveFileMode { get; set; } - /// - /// 上传目录 - /// - public string UploadDir { get; set; } + /// + /// 上传目录 + /// + public string UploadDir { get; set; } - /// - /// 上传文件限制 单位字节 默认 20 * 1024 * 1024 = 20971520 bytes - /// - public long UploadLimit { get; set; } - } + /// + /// 上传文件限制 单位字节 默认 20 * 1024 * 1024 = 20971520 bytes + /// + public long UploadLimit { get; set; } } diff --git a/Vampirewal.Core/AppConfig/PageSetting.cs b/Vampirewal.Core/AppConfig/PageSetting.cs new file mode 100644 index 0000000000000000000000000000000000000000..365a73ce6e28beb783d8b6169fe63c9be38c6492 --- /dev/null +++ b/Vampirewal.Core/AppConfig/PageSetting.cs @@ -0,0 +1,33 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:PageSetting +// 创 建 者:杨程 +// 创建时间:2022/2/11 15:15:59 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.AppConfig; + +/// +/// 分页配置 +/// +public class PageSetting +{ + + + private int _Limit = 20; + /// + /// 每页数 + /// + public int Limit { get => _Limit; set { _Limit = value; } } + + +} diff --git a/Vampirewal.Core/AppConfig/UpdateSetting.cs b/Vampirewal.Core/AppConfig/UpdateSetting.cs index be5a6ebb77aa09f215473f50d860faf23a7bfd68..54553fe374b48aa783d39f9eb62e7da40175ec90 100644 --- a/Vampirewal.Core/AppConfig/UpdateSetting.cs +++ b/Vampirewal.Core/AppConfig/UpdateSetting.cs @@ -11,37 +11,33 @@ //----------------------------------------------------------------*/ #endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Vampirewal.Core.AppConfig + + +namespace Vampirewal.Core.AppConfig; + +/// +/// 更新程序设置 +/// +public class UpdateSetting { /// - /// 更新程序设置 + /// 更新程序名称 + /// + public string UpdateName { get; set; } + + /// + /// 服务器IP + /// + public string ServerIp { get; set; } + + /// + /// 服务器端口号 + /// + public string ServerPort { get; set; } + + /// + /// AppToken /// - public class UpdateSetting - { - /// - /// 更新程序名称 - /// - public string UpdateName { get; set; } - - /// - /// 服务器IP - /// - public string ServerIp { get; set; } - - /// - /// 服务器端口号 - /// - public string ServerPort { get; set; } - - /// - /// AppToken - /// - public string AppToken { get; set; } - } + public string AppToken { get; set; } } diff --git a/Vampirewal.Core/AssemblyInfo.cs b/Vampirewal.Core/AssemblyInfo.cs index 6a3bf3fdbc4730349264d338c16f446cecef3214..2fdb3167795e17fe778e41761eaacd7de1e8f7ba 100644 --- a/Vampirewal.Core/AssemblyInfo.cs +++ b/Vampirewal.Core/AssemblyInfo.cs @@ -20,6 +20,8 @@ using System.Windows.Markup; [assembly: XmlnsDefinitionAttribute("Vampirewal.UcView", "Vampirewal.Core.WpfTheme.UcView")] [assembly: XmlnsDefinitionAttribute("Vampirewal.CustomControl", "Vampirewal.Core.WpfTheme.CustomControl")] [assembly: XmlnsDefinitionAttribute("Vampirewal.SimpleMVVM", "Vampirewal.Core.SimpleMVVM")] +[assembly: XmlnsDefinitionAttribute("Vampirewal.Behaviors", "Vampirewal.Core.WpfTheme.Behaviors")] +[assembly: XmlnsDefinitionAttribute("Vampirewal.Components", "Vampirewal.Core.Components")] // 将 ComVisible 设置为 false 会使此程序集中的类型对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型,请将该类型的 ComVisible // 属性设置为 true。 diff --git a/Vampirewal.Core/Attributes/ListenDetailChangeAttribute.cs b/Vampirewal.Core/Attributes/ListenDetailChangeAttribute.cs new file mode 100644 index 0000000000000000000000000000000000000000..bd8f46110645c456241b6e0097f56914a4f72b12 --- /dev/null +++ b/Vampirewal.Core/Attributes/ListenDetailChangeAttribute.cs @@ -0,0 +1,44 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: ListenDetailChangeAttribute +// 创建者: 杨程 +// 创建日期: 2022/10/31 18:23:24 + +//----------------------------------------------------------------*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; + +using System.Text; +using System.Threading.Tasks; + + + +namespace Vampirewal.Core.Attributes; + +/// +/// 监听明细项属性变更特性 +/// +[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] +public class ListenDetailChangeAttribute: Attribute +{ + /// + /// + /// + /// 属性名称 + public ListenDetailChangeAttribute([CallerMemberName] string propertyName="") + { + PropertyName = propertyName; + //构造函数 + } + + public string PropertyName { get; set; } +} diff --git a/Vampirewal.Core/SimpleMVVM/Attributes/PreferredConstructorAttribute.cs b/Vampirewal.Core/Attributes/PreferredConstructorAttribute.cs similarity index 58% rename from Vampirewal.Core/SimpleMVVM/Attributes/PreferredConstructorAttribute.cs rename to Vampirewal.Core/Attributes/PreferredConstructorAttribute.cs index b7e51bdc5ae4fc82550d3dbc9ab2ee67b9fda34f..f184ac4abd83b1d3de2090e19ad3b13cefddcee4 100644 --- a/Vampirewal.Core/SimpleMVVM/Attributes/PreferredConstructorAttribute.cs +++ b/Vampirewal.Core/Attributes/PreferredConstructorAttribute.cs @@ -11,16 +11,15 @@ //----------------------------------------------------------------*/ #endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Vampirewal.Core.SimpleMVVM.Attributes + + +namespace Vampirewal.Core.Attributes; + +/// +/// 多个构造函数标记一个作为选择 +/// +[AttributeUsage(AttributeTargets.Constructor)] +public sealed class PreferredConstructorAttribute : Attribute { - [AttributeUsage(AttributeTargets.Constructor)] - public sealed class PreferredConstructorAttribute : Attribute - { - } } diff --git a/Vampirewal.Core/SimpleMVVM/Attributes/RegistMethodAttribute.cs b/Vampirewal.Core/Attributes/RegistMethodAttribute.cs similarity index 44% rename from Vampirewal.Core/SimpleMVVM/Attributes/RegistMethodAttribute.cs rename to Vampirewal.Core/Attributes/RegistMethodAttribute.cs index 5be4c20c5d62a4ae3fccda60064907e94ef0332c..be7b601a79b10e169bcd426de3d6d2830ade44be 100644 --- a/Vampirewal.Core/SimpleMVVM/Attributes/RegistMethodAttribute.cs +++ b/Vampirewal.Core/Attributes/RegistMethodAttribute.cs @@ -11,35 +11,32 @@ * ****************************************************** */ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Vampirewal.Core.SimpleMVVM + + +namespace Vampirewal.Core.Attributes; + +/// +/// 注册为消息 +/// +[AttributeUsage(AttributeTargets.Method)] +public class RegistMethodAttribute : Attribute { + public RegistMethodAttribute() + { + //构造函数 + } + /// - /// 注册为消息 + /// /// - public class RegistMethodAttribute : Attribute + /// + public RegistMethodAttribute(string token) { - public RegistMethodAttribute() - { - //构造函数 - } - - /// - /// - /// - /// - public RegistMethodAttribute(string token) - { - this.Token = token; - } - /// - /// 标识 - /// - public string Token { get; set; } + Token = token; } + /// + /// 标识 + /// + public string Token { get; set; } } diff --git a/Vampirewal.Core/Attributes/SetClassificationAttribute.cs b/Vampirewal.Core/Attributes/SetClassificationAttribute.cs index d5c3e06c706b9aad3189d024b29f21535ae06c0c..eb90ec53765673023a20e111380b9fa095394657 100644 --- a/Vampirewal.Core/Attributes/SetClassificationAttribute.cs +++ b/Vampirewal.Core/Attributes/SetClassificationAttribute.cs @@ -11,30 +11,25 @@ //----------------------------------------------------------------*/ #endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Vampirewal.Core.Attributes + + +namespace Vampirewal.Core.Attributes; + +/// +/// 添加自定义属性 +/// 作用:过滤枚举类型 +/// +public class SetClassificationAttribute : Attribute { /// - /// 添加自定义属性 - - /// 作用:过滤枚举类型 + /// 分类 /// - public class SetClassificationAttribute : Attribute - { - /// - /// 分类 - /// - public int Type { get; set; } + public int Type { get; set; } - /// - /// - /// - public SetClassificationAttribute() { } + /// + /// + /// + public SetClassificationAttribute() { } - } } diff --git a/Vampirewal.Core/Attributes/VampirewalIoCRegisterAttribute.cs b/Vampirewal.Core/Attributes/VampirewalIoCRegisterAttribute.cs new file mode 100644 index 0000000000000000000000000000000000000000..198d2431d1ba11f2faff17a9818a9a900ddb55d2 --- /dev/null +++ b/Vampirewal.Core/Attributes/VampirewalIoCRegisterAttribute.cs @@ -0,0 +1,61 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: VampirewalIoCRegisterAttribute +// 创建者: 杨程 +// 创建日期: 2022/12/14 17:15:30 + +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.Attributes; + +/// +/// 标记了这个特性的将会被框架扫描并添加进IoC容器 +/// +public class VampirewalIoCRegisterAttribute: Attribute +{ + + /// + /// + /// + /// + /// + public VampirewalIoCRegisterAttribute(string token, RegisterType registerType= RegisterType.Transient) + { + Token = token; + this.registerType = registerType; + } + + public string Token { get;private set; } + + public RegisterType registerType { get; private set; } +} + +/// +/// 注册模式 +/// +public enum RegisterType +{ + /// + /// 单例生命周期注册 + /// + Singleton, + /// + /// 瞬时生命周期注册 + /// + Transient, + /// + /// 作用域生命周期注册 + /// + Scoped +} + diff --git a/Vampirewal.Core/Components/VampirewalApplication.cs b/Vampirewal.Core/Components/VampirewalApplication.cs new file mode 100644 index 0000000000000000000000000000000000000000..640158b9a6b68c4c4a88a2851cfa3317e471bcb0 --- /dev/null +++ b/Vampirewal.Core/Components/VampirewalApplication.cs @@ -0,0 +1,67 @@ +#region << 文 件 说 明 >> + +/*---------------------------------------------------------------- +// 文件名称:VampirewalApplication +// 创 建 者:杨程 +// 创建时间:2021/9/22 13:04:58 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ + +#endregion + +namespace Vampirewal.Core.Components; + +/// +/// Vampirewal版本的Application +/// +public abstract class VampirewalApplication : Application +{ + /// + /// 获取引导启动类型 + /// + /// + protected abstract Type BootStartUp(); + + /// + /// 全局异常捕获(需重写) + /// 错误信息:e.Exception.Message + /// 最后需要写e.Handled = true;证明异常已处理 + /// + /// + /// + protected virtual void GlobalExceptions(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) + { + //IDialogMessage dialog = new VampirewalDialog(); + //dialog.ShowPopupWindow($"错误信息:{e.Exception.Message}",) + //e.Handled = true; + } + + /// + /// 重写需保留base!!! + /// + /// + protected override void OnStartup(StartupEventArgs e) + { + if (BootStartUp() == null) + { + throw new Exception("未提供引导启动类!"); + } + else if (BootStartUp().BaseType != typeof(VampirewalBootStartUp)) + { + throw new Exception("提供引导启动类不是派生自 VampirewalBootStartUp !"); + } + + base.OnStartup(e); + + var bootStartup = (VampirewalBootStartUp)Activator.CreateInstance(BootStartUp()); + + bootStartup.BuildBootStartUp(); + + DispatcherUnhandledException += GlobalExceptions; + + } +} \ No newline at end of file diff --git a/Vampirewal.Core/Components/VampirewalBootStartUp.cs b/Vampirewal.Core/Components/VampirewalBootStartUp.cs new file mode 100644 index 0000000000000000000000000000000000000000..ca632e4bbd0d79cf823ccec878cfd536aeb456b9 --- /dev/null +++ b/Vampirewal.Core/Components/VampirewalBootStartUp.cs @@ -0,0 +1,113 @@ +#region 文件信息 + +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: VampirewalBootStartUp +// 创建者: 杨程 +// 创建日期: 2022/12/14 17:31:29 + +//----------------------------------------------------------------*/ + +#endregion + +namespace Vampirewal.Core.Components; + +/// +/// 引导启动基类 +/// +public abstract class VampirewalBootStartUp +{ + public VampirewalBootStartUp() + { + Collection = new ServiceCollection(); + } + + private IServiceProvider Services { get; set; } + private IServiceCollection Collection { get; set; } + + /// + /// 扫描并注册View和ViewModel + /// + /// + /// + private void RegisterAll(IServiceCollection services) + { + var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).Where(w => w.GetCustomAttribute() != null).ToArray(); + + foreach (var item in types) + { + var Attribute = item.GetCustomAttribute(); + + if (Attribute != null) + { + if (VampirewalCoreContext.GetInstance().AddViewAndVMDic(Attribute.Token, item)) + { + switch (Attribute.registerType) + { + case RegisterType.Singleton: + services.TryAddSingleton(item); + break; + + case RegisterType.Transient: + services.TryAddTransient(item); + break; + + case RegisterType.Scoped: + services.TryAddScoped(item); + break; + } + } + else + { + throw new BootStartUpException("重复Token"); + } + } + } + } + + /// + /// 注册服务 + /// + /// + protected abstract void RegisterService(IServiceCollection services); + + /// + /// 构建BootStartUp并启动 + /// + internal void BuildBootStartUp() + { + RegisterService(Collection); + RegisterAll(Collection); + + Services = Collection.BuildServiceProvider(); + + VampirewalCoreContext.GetInstance().SetService(Services); + + WindowsManager.GetInstance().OpenWindow(FirstViewKey, IsMainWindow: true); + } + + /// + /// 初始窗体的ViewKey + /// + /// + protected abstract string FirstViewKey { get; } +} + +/// +/// 引导启动异常 +/// +[Serializable] +internal class BootStartUpException : Exception +{ + /// + /// 引导启动异常 + /// + /// 错误消息 + public BootStartUpException(string mes) : base(mes) + { + } +} \ No newline at end of file diff --git a/Vampirewal.Core/Components/VampirewalConfig.cs b/Vampirewal.Core/Components/VampirewalConfig.cs index 4928665e7d5c84cf769e783172a537d25eb1c1ee..76fa1048457ce2e14895e6a28349ba2297b84c30 100644 --- a/Vampirewal.Core/Components/VampirewalConfig.cs +++ b/Vampirewal.Core/Components/VampirewalConfig.cs @@ -11,251 +11,325 @@ //----------------------------------------------------------------*/ #endregion -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Newtonsoft.Json; -using Vampirewal.Core.AppConfig; -using Vampirewal.Core.Interface; -using Vampirewal.Core.Models; -using static Org.BouncyCastle.Math.EC.ECCurve; - -namespace Vampirewal.Core.Components + + + +namespace Vampirewal.Core.Components; + +/// +/// Vampirewal使用的config +/// +[Obsolete("20230128切换使用新的配置文件方式",true)] +public sealed class VampirewalConfig : IAppConfig { /// - /// Vampirewal使用的config + /// 日志级别 + /// + public LoggerType LogLevel { get; set; } = LoggerType.Debug; + /// + /// app中文名 + /// + public string AppChineseName { get; set; }//展示界面顶部的名称 + + /// + /// 程序本地版本 + /// + public string AppVersion { get; set; } = "1.0.0.0"; + + #region 连接字符串集合 + private List _connectStrings; + + /// + /// 连接字符串集合 /// - public class VampirewalConfig : IAppConfig + public List ConnectionStrings { - /// - /// 日志级别 - /// - public LoggerType LogLevel { get; set; } = LoggerType.Debug; - /// - /// app中文名 - /// - public string AppChineseName { get; set; }//展示界面顶部的名称 - - /// - /// 程序本地版本 - /// - public string AppVersion { get; set; } = "1.0.0.0"; - - #region ConnectionStrings - private List _connectStrings; - - /// - /// ConnectionStrings - /// - public List ConnectionStrings + get { - get - { - if (_connectStrings == null) - { - _connectStrings = new List(); - } - return _connectStrings; - } - set + if (_connectStrings == null) { - _connectStrings = value; + _connectStrings = new List(); } + return _connectStrings; + } + set + { + _connectStrings = value; } - #endregion + } + #endregion - #region Database type + #region 数据库类型 - private DBTypeEnum? _dbtype; + private DBTypeEnum? _dbtype; - /// - /// Database type - /// - public DBTypeEnum DbType + /// + /// 数据库类型 + /// + public DBTypeEnum DbType + { + get { - get - { - if (_dbtype == null) - { - _dbtype = DBTypeEnum.SqlServer; - } - return _dbtype.Value; - } - set + if (_dbtype == null) { - _dbtype = value; + _dbtype = DBTypeEnum.SqlServer; } + return _dbtype.Value; + } + set + { + _dbtype = value; } - #endregion + } + #endregion - #region EncryptKey + #region 加密密钥 - private string _encryptKey; + private string _encryptKey; - /// - /// EncryptKey - /// - public string EncryptKey + /// + /// 加密密钥 + /// + public string EncryptKey + { + get { - get - { - if (string.IsNullOrEmpty(_encryptKey)) - { - _encryptKey = string.Empty; - } - return _encryptKey; - } - set + if (string.IsNullOrEmpty(_encryptKey)) { - _encryptKey = value; + _encryptKey = string.Empty; } + return _encryptKey; + } + set + { + _encryptKey = value; } + } - #endregion + #endregion - #region Custom settings + #region 自定义设置 - private Dictionary _appSettings; + private Dictionary _appSettings; - /// - /// 自定义设置 - /// - public Dictionary AppSettings + /// + /// 自定义设置 + /// + public Dictionary AppSettings + { + get { - get - { - if (_appSettings == null) - { - _appSettings = new Dictionary(); - } - return _appSettings; - } - set + if (_appSettings == null) { - _appSettings = value; + _appSettings = new Dictionary(); } + return _appSettings; } - #endregion - - #region UploadSetting - /// - /// 附件上传设置 - /// - public FileUploadOptions FileUploadOptions { get; set; } = new FileUploadOptions() - { - SaveFileMode= SaveFileModeEnum.Local, - UploadDir=DefaultConfigConsts.DEFAULT_UPLOAD_DIR, - UploadLimit=DefaultConfigConsts.DEFAULT_UPLOAD_LIMIT - }; - #endregion - - #region 操作 - - /// - /// 配置文件路径 - /// - [JsonIgnore] - public string ConfigPath { get; set; } = AppDomain.CurrentDomain.BaseDirectory; - - /// - /// 配置文件名称 - /// - [JsonIgnore] - public string ConfigName { get; set; } = "AppConfig.json"; - - /// - /// 更新程序设置 - /// - public UpdateSetting UpdateSetting { get; set; } = new UpdateSetting() - { - UpdateName ="XX", - ServerIp ="127.0.0.1", - ServerPort ="1234", - AppToken="aaaa" - }; - - /// - /// 读取配置文件 - /// - public void LoadAppConfig() + set { - //var configFile = $"{AppDomain.CurrentDomain.BaseDirectory}AppConfig.json"; - var configFile = $"{ConfigPath}\\{ConfigName}"; + _appSettings = value; + } + } + #endregion + + #region 附件上传设置 + /// + /// 附件上传设置 + /// + public FileUploadOptions FileUploadOptions { get; set; } = new FileUploadOptions() + { + SaveFileMode = SaveFileModeEnum.Local, + UploadDir = DefaultConfigConsts.DEFAULT_UPLOAD_DIR, + UploadLimit = DefaultConfigConsts.DEFAULT_UPLOAD_LIMIT + }; + #endregion - if (File.Exists(configFile)) + #region 视图View模块dll路径 + private List _ViewModulesPath; + /// + /// 视图View模块dll路径 + /// + public List ViewModulesPath + { + get + { + if (_ViewModulesPath == null) { - var Config = JsonConvert.DeserializeObject(JsonHelper.Readjson(configFile)); - SetValue(Config); + _ViewModulesPath = new List(); } - else + return _ViewModulesPath; + } + set + { + _ViewModulesPath = value; + } + } + #endregion + + #region 连接域设置 + private List _Domains; + /// + /// 连接域 + /// + public List Domains + { + get + { + if (_Domains == null) { - //T t = new T(); - //var json = JsonConvert.SerializeObject(t); - //var formatStr = JsonHelper.FormatJsonString(json); - //FileStream fs = File.Create(configFile); - //fs.Dispose(); - //File.AppendAllText(configFile, formatStr); - - //Config = t; - - Save(); - var Config = JsonConvert.DeserializeObject(JsonHelper.Readjson(configFile)); - SetValue(Config); + _Domains = new List(); } - + return _Domains; + } + set + { + _Domains = value; } + } + + #endregion + + #region 操作 + + /// + /// 配置文件路径 + /// + [JsonIgnore] + public string ConfigPath { get; set; } = AppDomain.CurrentDomain.BaseDirectory; + + /// + /// 配置文件名称 + /// + [JsonIgnore] + public string ConfigName { get; set; } = "AppConfig.json"; + + /// + /// 更新程序设置 + /// + public UpdateSetting UpdateSetting { get; set; } = new UpdateSetting() + { + UpdateName = "XX", + ServerIp = "127.0.0.1", + ServerPort = "1234", + AppToken = "aaaa" + }; + + /// + /// 分页设置 + /// + public PageSetting pageSetting { get; set; } = new PageSetting() + { + Limit = DefaultConfigConsts.DEFAULT_RPP + }; + + /// + /// 读取配置文件 + /// + public void LoadAppConfig() + { + //var configFile = $"{AppDomain.CurrentDomain.BaseDirectory}AppConfig.json"; + var configFile = $"{ConfigPath}\\{ConfigName}"; + + if (File.Exists(configFile)) + { + var Config = JsonConvert.DeserializeObject(JsonHelper.Readjson(configFile)); + SetValue(Config); - private void SetValue(VampirewalConfig self) + ExcuteLoadAssembly(isLoad); + } + else { - LogLevel = self.LogLevel; - AppChineseName = self.AppChineseName; - AppVersion = self.AppVersion; - ConnectionStrings = self.ConnectionStrings; - DbType = self.DbType; - AppSettings = self.AppSettings; - EncryptKey = self.EncryptKey; - FileUploadOptions = self.FileUploadOptions; - UpdateSetting = self.UpdateSetting; + //T t = new T(); + //var json = JsonConvert.SerializeObject(t); + //var formatStr = JsonHelper.FormatJsonString(json); + //FileStream fs = File.Create(configFile); + //fs.Dispose(); + //File.AppendAllText(configFile, formatStr); + + //Config = t; + + Save(); + var Config = JsonConvert.DeserializeObject(JsonHelper.Readjson(configFile)); + SetValue(Config); } - /// - /// 保存 - /// - public void Save() + } + + private void SetValue(VampirewalConfig self) + { + LogLevel = self.LogLevel; + AppChineseName = self.AppChineseName; + AppVersion = self.AppVersion; + ConnectionStrings = self.ConnectionStrings; + DbType = self.DbType; + AppSettings = self.AppSettings; + EncryptKey = self.EncryptKey; + FileUploadOptions = self.FileUploadOptions; + UpdateSetting = self.UpdateSetting; + pageSetting = self.pageSetting; + ViewModulesPath = self.ViewModulesPath; + Domains = self.Domains; + } + + /// + /// 保存 + /// + public void Save() + { + var jsonStr = JsonConvert.SerializeObject(this); + var formatStr = JsonHelper.FormatJsonString(jsonStr); + //var configFile = $"{AppDomain.CurrentDomain.BaseDirectory}AppConfig.json"; + var configFile = $"{ConfigPath}\\{ConfigName}"; + if (File.Exists(configFile)) { - var jsonStr = JsonConvert.SerializeObject(this); - var formatStr = JsonHelper.FormatJsonString(jsonStr); - //var configFile = $"{AppDomain.CurrentDomain.BaseDirectory}AppConfig.json"; - var configFile = $"{ConfigPath}\\{ConfigName}"; - if (File.Exists(configFile)) - { - File.Delete(configFile); - } - if (!Directory.Exists(ConfigPath)) - { - Directory.CreateDirectory(ConfigPath); - } - File.AppendAllText(configFile, formatStr); + File.Delete(configFile); + } + if (!Directory.Exists(ConfigPath)) + { + Directory.CreateDirectory(ConfigPath); } + File.AppendAllText(configFile, formatStr); + } - /// - /// 重置配置文件(慎用) - /// - public void Reset() + /// + /// 重置配置文件(慎用) + /// + public void Reset() + { + //var configFile = $"{AppDomain.CurrentDomain.BaseDirectory}AppConfig.json"; + var configFile = $"{ConfigPath}\\{ConfigName}"; + if (File.Exists(configFile)) + { + File.Delete(configFile); + + LoadAppConfig(); + } + } + + bool isLoad = false; + private void ExcuteLoadAssembly(bool _isLoaded) + { + if (!_isLoaded&&ViewModulesPath.Count > 0) { - //var configFile = $"{AppDomain.CurrentDomain.BaseDirectory}AppConfig.json"; - var configFile = $"{ConfigPath}\\{ConfigName}"; - if (File.Exists(configFile)) + ViewModulesPath.ForEach(f => { - File.Delete(configFile); + try + { + Assembly ass = Assembly.LoadFile(f); - LoadAppConfig(); - } + } + catch + { + //ErrorStr.Add($"无法加载该dll-{f}"); + throw new Exception($"无法加载该DLL:{f}"); + } + }); + + isLoad = true; } - #endregion + + } + #endregion } diff --git a/Vampirewal.Core/Components/VampirewalCoreActionService.cs b/Vampirewal.Core/Components/VampirewalCoreActionService.cs new file mode 100644 index 0000000000000000000000000000000000000000..07f0f99e18b3526190f20ef863befe77a7e2daf3 --- /dev/null +++ b/Vampirewal.Core/Components/VampirewalCoreActionService.cs @@ -0,0 +1,39 @@ +#region << 文 件 说 明 >> +/****************************************************************************************************** +*机器名称: DESKTOP-6RM95GA +*命名空间: Vampirewal.Core.Components +*文 件 名: VampirewalActionTimeSpanService +*创 建 人: 杨程 +*电子邮箱: 235160615@qq.com +*创建时间: 2022/4/12 11:32:07 + +*描述: +* +*******************************************************************************************************/ +#endregion + + + +namespace Vampirewal.Core.Components; + + +/// +/// 方法执行服务 +/// +public sealed class VampirewalCoreActionService: IVampirewalCoreActionService +{ + /// + /// 获取方法执行时间 + /// + /// + /// + public string GetMethodExcuteTime(Action action) + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + action.Invoke(); + sw.Stop(); + + return sw.ElapsedMilliseconds.ToString(); + } +} diff --git a/Vampirewal.Core/Components/VampirewalCoreConfig.cs b/Vampirewal.Core/Components/VampirewalCoreConfig.cs new file mode 100644 index 0000000000000000000000000000000000000000..093f96c9e8f399ee5173c2f067cffccdd74f4931 --- /dev/null +++ b/Vampirewal.Core/Components/VampirewalCoreConfig.cs @@ -0,0 +1,241 @@ +#region 文件信息 + +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: VampirewalCoreConfig +// 创建者: 杨程 +// 创建日期: 2023/1/28 12:17:34 + +//----------------------------------------------------------------*/ + +#endregion + +namespace Vampirewal.Core.Components; + +/// +/// 配置文件 +/// +public sealed class VampirewalCoreConfig +{ + private string JsonStr { get; set; } + private JObject JObject { get; set; } + + private string ConfigPath { get; set; } + + /// + /// + /// + internal VampirewalCoreConfig(string path) + { + //构造函数 + ConfigPath = path; + } + + /// + /// 获取配置 + /// + /// + /// + /// + internal T GetOptions() where T : IOptions + { + Type type = typeof(T); + + JToken jToken = JObject[type.Name]; + + string token = JsonConvert.SerializeObject(jToken); + + T t = JsonConvert.DeserializeObject(token); + + if (t == null) + { + throw new Exception("配置文件中无该节点数据!"); + } + + return t; + } + + /// + /// 根据A:B:C这样的来获取数据 + /// + /// + /// + internal T GetOptionsValue(string key) + { + var keyArray = key.Split(":".ToArray()); + var firstKey = keyArray.FirstOrDefault(); + var otherKey = keyArray.Skip(1); + JToken jToken = JObject[firstKey]; + foreach (var item in otherKey) + { + jToken = jToken[item]; + } + + string token = JsonConvert.SerializeObject(jToken); + + return JsonConvert.DeserializeObject(token); ; + } + + /// + /// 保存配置 + /// + /// + /// + internal void SaveOptions(T Options) where T : IOptions + { + Type type = typeof(T); + + JObject[type.Name] = JObject.Parse(JsonConvert.SerializeObject(Options)); + + SaveConfig(); + } + + /// + /// 完整保存配置文件 + /// + internal void SaveConfig() + { + var formatStr = JsonHelper.FormatJsonString(JsonConvert.SerializeObject(JObject)); + + File.Delete(ConfigPath); + + File.AppendAllText(ConfigPath, formatStr); + } + + /// + /// 在传入的目标路径下创建一个新的配置文件 + /// + private void CreateNewConfig() + { + string DevPath = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory).Parent.Parent.Parent.FullName; + + string _configPath = $"{DevPath}\\AppConfig.json"; + + JObject = new JObject(); + + foreach (var item in OptionsList) + { + Type type = item.GetType(); + object obj = Activator.CreateInstance(type); + string token = JsonConvert.SerializeObject(obj); + JObject.TryAdd(type.Name, JObject.Parse(token)); + } + + var formatStr = JsonHelper.FormatJsonString(JsonConvert.SerializeObject(JObject)); + + File.Delete(_configPath); + + File.AppendAllText(_configPath, formatStr); + } + + /// + /// 简单加载一下模块程序集,方便后续反射的时候,找到这些程序集 + /// + /// + private void LoadModules() + { + GetOptions().ModulesPath.ForEach(f => + { + try + { + Assembly ass = Assembly.LoadFile(f); + } + catch + { + throw new Exception($"无法加载该DLL:{f}"); + } + }); + } + + #region 新代码 + + internal List OptionsList { get; set; } = new List(); + + /// + /// 读取配置文件 + /// + /// + /// + internal void LoadConfig() + { + //1、先判断一下启动程序的路径下有没有这个配置文件,没有就按照添加进来的配置项创建对应的json配置文件 + +#if DEBUG + if (!File.Exists(ConfigPath)) + { + CreateNewConfig(); + throw new ArgumentException("Config路径不存在,已在VS中当前项目的根路径下创建了Config文件!请修改属性为内容和较新则复制!"); + } +#endif + + //2、已经读取到了配置文件 + JsonStr = JsonHelper.Readjson(ConfigPath); + + if (string.IsNullOrEmpty(JsonStr)) + { + throw new Exception("配置文件无内容"); + } + + //3、转成JObject + JObject = JObject.Parse(JsonStr); + bool IsSave = false; + + //4、将每一个传进来的配置项检查一下,读取到的json中有没有对应的键值 + foreach (var item in OptionsList) + { + Type type = item.GetType(); + + object obj = null; + try + { + JToken jToken = JObject[type.Name]; + + string token = JsonConvert.SerializeObject(jToken); + //直接将对应的token转成这个obj看是不是null + obj = JsonConvert.DeserializeObject(token); + + VampirewalCoreContext.GetInstance().AddContext(type.Name, token); + } + catch + { + //异常什么的直接吞掉吧 + } + finally + { + //如果obj为null说明配置文件中并没有这个配置项的对应键值,那么在这里添加进去,并把IsSave标记为true,方便后面生成对应的json文件 + if (obj == null) + { + JObject[type.Name] = JObject.Parse(JsonConvert.SerializeObject(Activator.CreateInstance(type))); + IsSave = true; + } + } + } + + if (IsSave) + { + string DevPath = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory).Parent.Parent.Parent.FullName; + + var formatStr = JsonHelper.FormatJsonString(JsonConvert.SerializeObject(JObject)); + + FileInfo info = new FileInfo(ConfigPath); + var filename = info.Name; + + string _configPath = $"{DevPath}\\{filename}"; + + File.Delete(_configPath); + + File.AppendAllText(_configPath, formatStr); + + //因为新增了对应的配置内容,这里按道理来说是不能进来的,能进来的话,就是新增了,所以直接抛个异常中断程序 + throw new Exception($"已重新添加了配置信息内容在{filename}中,请修改属性为内容和较新则复制!重新编译!"); + } + + LoadModules(); + } + + #endregion +} \ No newline at end of file diff --git a/Vampirewal.Core/Components/VampirewalCoreDataContext.cs b/Vampirewal.Core/Components/VampirewalCoreDataContext.cs new file mode 100644 index 0000000000000000000000000000000000000000..10028f59a0955c26a57ce2725f48e32ad3fb91ae --- /dev/null +++ b/Vampirewal.Core/Components/VampirewalCoreDataContext.cs @@ -0,0 +1,1217 @@ +#region << 文 件 说 明 >> + +/*---------------------------------------------------------------- +// 文件名称:VampirewalDbBase +// 创 建 者:杨程 +// 创建时间:2022/2/11 19:23:12 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ + +#endregion + +namespace Vampirewal.Core.Components; + +/// +/// 数据库连接操作基类 +/// +public abstract class VampirewalCoreDataContext : IVampirewalCoreDataContext +{ + /// + /// 构造函数 + /// + public VampirewalCoreDataContext() + { + DbBaseOptions DbOptions = VampirewalCoreContext.GetInstance().GetOptions(); + + var dbConnectConfigList = new List(); + + foreach (var item in DbOptions.ConnectionStrings ?? new List()) + { + string connStr = item.Value; + + if (item.DbType == DBTypeEnum.Sqlite) + { + var strs = connStr.Split('='); + + connStr = $"{strs[0]}={AppDomain.CurrentDomain.BaseDirectory}{strs[1]}"; + } + + dbConnectConfigList.Add(GetDbConnectionConfig(item.Key, connStr, item.DbType)); + } + + Client = new SqlSugarScope(dbConnectConfigList); + + //SQL执行完 + Client.Aop.OnLogExecuted = OnLogExecuted; + //SQL执行前 + Client.Aop.OnLogExecuting = OnLogExecuting; + + //SQL报错 + Client.Aop.OnError = OnError; + + //可以修改SQL和参数的值 + Client.Aop.OnExecutingChangeSql = OnExecutingChangeSql; + + Client.Aop.DataExecuting = DataExecuting; + Client.Aop.DataExecuted = DataExecuted; + + Client.DbMaintenance.CreateDatabase(); + CodeFirst(); + } + + /// + /// 数据库连接对象 + /// + public SqlSugarScope Client { get; set; } + + /// + /// 查询后数据替换 + /// + /// + /// + public virtual void DataExecuted(object value, DataAfterModel entity) + { } + + /// + /// 数据执行过滤 + /// 可用于新增或修改的时候,处理CreateName或UpdateName + /// + /// + /// + public virtual void DataExecuting(object OldValue, DataFilterModel entityInfo) + { + // 新增操作 + if (entityInfo.OperationType == DataFilterType.InsertByObject) + { + // 主键赋值 + if (entityInfo.EntityColumnInfo.IsPrimarykey && entityInfo.EntityColumnInfo.PropertyInfo.PropertyType == typeof(string)) + { + if (entityInfo.PropertyName == "BillId" && ((dynamic)entityInfo.EntityValue).BillId == null) + { + entityInfo.SetValue(Guid.NewGuid().ToString()); + } + + if (entityInfo.PropertyName == "DtlId" && ((dynamic)entityInfo.EntityValue).DtlId == null) + { + entityInfo.SetValue(Guid.NewGuid().ToString()); + } + } + + if (entityInfo.PropertyName == "CreateTime" && ((dynamic)entityInfo.EntityValue).CreateTime == null) + entityInfo.SetValue(DateTime.Now); + + if (VampirewalCoreContext.GetInstance().GetContext("UserId", out object UserId)) + { + if (entityInfo.PropertyName == "CreateUserId") + { + var createUserId = ((dynamic)entityInfo.EntityValue).CreateUserId; + if (createUserId == null || createUserId == 0) + entityInfo.SetValue(UserId.ToString()); + } + } + + if (VampirewalCoreContext.GetInstance().GetContext("UserName", out object UserName)) + { + if (entityInfo.PropertyName == "CreateBy" && ((dynamic)entityInfo.EntityValue).CreateBy == null) + entityInfo.SetValue(UserName.ToString()); + } + } + + // 更新操作 + if (entityInfo.OperationType == DataFilterType.UpdateByObject) + { + if (entityInfo.PropertyName == "UpdateTime") + entityInfo.SetValue(DateTime.Now); + + if (VampirewalCoreContext.GetInstance().GetContext("UserId", out object UserId)) + { + if (entityInfo.PropertyName == "UpdateUserId") + entityInfo.SetValue(UserId.ToString()); + } + + if (VampirewalCoreContext.GetInstance().GetContext("UserName", out object UserName)) + { + if (entityInfo.PropertyName == "UpdateBy") + entityInfo.SetValue(UserName.ToString()); + } + } + } + + /// + /// 配置Sqlsugar连接设置 + /// + /// + /// + /// + /// + public virtual ConnectionConfig GetDbConnectionConfig(string DbName, string ConnStr, DBTypeEnum? dbType) + { + return new ConnectionConfig() + { + ConfigId = DbName, + ConnectionString = ConnStr,//"Data Source=./demo.db", + DbType = (SqlSugar.DbType)(int)dbType, + IsAutoCloseConnection = true, + InitKeyType = InitKeyType.Attribute, + MoreSettings = new ConnMoreSettings() + { + IsWithNoLockQuery = true//看这里 + }, + }; + } + + /// + /// SQL报错 + /// + /// + public virtual void OnError(SqlSugarException exp) + { + } + + /// + /// 可以修改SQL和参数的值 + /// + /// sql=newsql + /// foreach(var p in pars) //修改 + /// + public virtual KeyValuePair OnExecutingChangeSql(string sql, SugarParameter[] pars) + { + return new KeyValuePair(sql, pars); + } + + /// + /// SQL执行完 + /// + /// + /// + public virtual void OnLogExecuted(string sql, SugarParameter[] para) + { + } + + /// + /// SQL执行前 + /// + /// + /// + public virtual void OnLogExecuting(string sql, SugarParameter[] para) + { + } + + /// + /// 创建表(需要建表的都需要重复写) + /// 使用方法:CreateTable(); + /// 这样一个表就能成功创建了 + /// + protected abstract void CodeFirst(); + + /// + /// 创建表,需写入CodeFirst中 + /// + /// + /// + protected void CreateTable(int length = 200) where T : TopModel + { + Client.CodeFirst.SetStringDefaultLength(length).InitTables(typeof(T)); + } + + /// + /// 获取代码执行超过1秒的代码,放在OnLogExecuted + /// + /// 超时sql所在信息 + protected string GetSqlExecuteTimeMoreOnceSecond() + { + double time = Client.Ado.SqlExecutionTime.TotalSeconds; + + if (time > 1) + { + //代码CS文件名 + var fileName = Client.Ado.SqlStackTrace.FirstFileName; + //代码行数 + var fileLine = Client.Ado.SqlStackTrace.FirstLine; + //方法名 + var FirstMethodName = Client.Ado.SqlStackTrace.FirstMethodName; + //db.Ado.SqlStackTrace.MyStackTraceList[1].xxx 获取上层方法的信息 + + return $"代码CS文件名:{fileName}-所在代码行数:{fileLine}-方法名:{FirstMethodName}(SQL执行时间:{time}秒)"; + } + return ""; + } + + private bool ClientCheck() + { + if (Client != null) + { + return true; + } + return false; + } +} + +/// +/// VampirewalCoreSqlSugar启动配置项 +/// +public abstract class VampirewalCoreSqlSugarSetup : IVampirewalCoreSqlSugar +{ + protected SqlSugarScope Client { get; private set; } + + /// + public virtual void CodeFirst() + { + } + + /// + public virtual void DataExecuted(object value, DataAfterModel entity) + { + } + + /// + public virtual void DataExecuting(object OldValue, DataFilterModel entityInfo) + { + // 新增操作 + if (entityInfo.OperationType == DataFilterType.InsertByObject) + { + // 主键赋值 + if (entityInfo.EntityColumnInfo.IsPrimarykey && entityInfo.EntityColumnInfo.PropertyInfo.PropertyType == typeof(string)) + { + if (entityInfo.PropertyName == "BillId" && ((dynamic)entityInfo.EntityValue).BillId == null) + { + entityInfo.SetValue(Guid.NewGuid().ToString()); + } + + if (entityInfo.PropertyName == "DtlId" && ((dynamic)entityInfo.EntityValue).DtlId == null) + { + entityInfo.SetValue(Guid.NewGuid().ToString()); + } + } + + if (entityInfo.PropertyName == "CreateTime" && ((dynamic)entityInfo.EntityValue).CreateTime == null) + entityInfo.SetValue(DateTime.Now); + + if (VampirewalCoreContext.GetInstance().GetContext("UserId", out object UserId)) + { + if (entityInfo.PropertyName == "CreateUserId") + { + var createUserId = ((dynamic)entityInfo.EntityValue).CreateUserId; + if (createUserId == null || createUserId == 0) + entityInfo.SetValue(UserId.ToString()); + } + } + + if (VampirewalCoreContext.GetInstance().GetContext("UserName", out object UserName)) + { + if (entityInfo.PropertyName == "CreateBy" && ((dynamic)entityInfo.EntityValue).CreateBy == null) + entityInfo.SetValue(UserName.ToString()); + } + } + + // 更新操作 + if (entityInfo.OperationType == DataFilterType.UpdateByObject) + { + if (entityInfo.PropertyName == "UpdateTime") + entityInfo.SetValue(DateTime.Now); + + if (VampirewalCoreContext.GetInstance().GetContext("UserId", out object UserId)) + { + if (entityInfo.PropertyName == "UpdateUserId") + entityInfo.SetValue(UserId.ToString()); + } + + if (VampirewalCoreContext.GetInstance().GetContext("UserName", out object UserName)) + { + if (entityInfo.PropertyName == "UpdateBy") + entityInfo.SetValue(UserName.ToString()); + } + } + } + + /// + + public virtual ConnectionConfig GetDbConnectionConfig(string DbName, string ConnStr, DBTypeEnum? dbType) + { + return new ConnectionConfig() + { + ConfigId = DbName, + ConnectionString = ConnStr,//"Data Source=./demo.db", + DbType = (SqlSugar.DbType)(int)dbType, + IsAutoCloseConnection = true, + InitKeyType = InitKeyType.Attribute, + MoreSettings = new ConnMoreSettings() + { + IsWithNoLockQuery = true//看这里 + }, + }; + } + + /// + + public virtual string GetSqlExecuteTimeMoreOnceSecond() + { + double time = Client.Ado.SqlExecutionTime.TotalSeconds; + + if (time > 1) + { + //代码CS文件名 + var fileName = Client.Ado.SqlStackTrace.FirstFileName; + //代码行数 + var fileLine = Client.Ado.SqlStackTrace.FirstLine; + //方法名 + var FirstMethodName = Client.Ado.SqlStackTrace.FirstMethodName; + //db.Ado.SqlStackTrace.MyStackTraceList[1].xxx 获取上层方法的信息 + + return $"代码CS文件名:{fileName}-所在代码行数:{fileLine}-方法名:{FirstMethodName}(SQL执行时间:{time}秒)"; + } + return ""; + } + + /// + + public virtual void InitData() + { + } + + /// + + public virtual void OnError(SqlSugarException exp) + { + } + + /// + + public virtual KeyValuePair OnExecutingChangeSql(string sql, SugarParameter[] pars) + { + return new KeyValuePair(sql, pars); + } + + /// + + public virtual void OnLogExecuted(string sql, SugarParameter[] para) + { + } + + /// + + public virtual void OnLogExecuting(string sql, SugarParameter[] para) + { + } + + /// + + public void SetClient(ISqlSugarClient client) + { + Client = (SqlSugarScope)client; + } + + /// + protected void CreateTable(int length = 200) where T : TopModel + { + Client.CodeFirst.SetStringDefaultLength(length).InitTables(typeof(T)); + } +} + +/// +/// SqlSugar 仓储实现类 +/// +/// +public partial class SqlSugarRepository +where TEntity : class, new() +{ + private readonly string[] UpdateIgnoreColumns = new string[] { "CreatedTime", "CreatedUserId", "CreatedUserName" }; + + #region 属性 + + /// + /// 初始化 SqlSugar 客户端 + /// + private readonly SqlSugarScope _db; + + /// + /// 构造函数 + /// + /// + public SqlSugarRepository(ISqlSugarClient db) + { + Context = _db = (SqlSugarScope)db; + EntityContext = _db.GetConnectionScopeWithAttr(); + Ado = EntityContext.Ado; + } + + /// + /// 原生 Ado 对象 + /// + public virtual IAdo Ado { get; } + + /// + /// 数据库上下文 + /// + public virtual SqlSugarScope Context { get; } + + /// + /// 实体集合 + /// + public virtual ISugarQueryable Entities => EntityContext.Queryable(); + + public virtual SqlSugarScopeProvider EntityContext { get; } + + #endregion + + #region 查询 + + /// + /// 检查是否存在 + /// + /// + /// + public bool Any(Expression> whereExpression) + { + return Entities.Any(whereExpression); + } + + /// + /// 检查是否存在 + /// + /// + /// + public async Task AnyAsync(Expression> whereExpression) + { + return await Entities.AnyAsync(whereExpression); + } + + /// + /// 获取总数 + /// + /// + /// + public int Count(Expression> whereExpression) + { + return Entities.Count(whereExpression); + } + + /// + /// 获取总数 + /// + /// + /// + public Task CountAsync(Expression> whereExpression) + { + return Entities.CountAsync(whereExpression); + } + + /// + /// 获取一个实体 + /// + /// + /// + public TEntity FirstOrDefault(Expression> whereExpression) + { + return Entities.First(whereExpression); + } + + /// + /// 获取一个实体 + /// + /// + /// + public async Task FirstOrDefaultAsync(Expression> whereExpression) + { + return await Entities.FirstAsync(whereExpression); + } + + /// + /// 分页查询 + /// + /// + /// + /// + /// + public (List, int) QueryableToPage(Expression> expression, int pageIndex = 0, int pageSize = 10) + { + int totalNumber = 0; + var list = Entities.Where(expression).ToPageList(pageIndex, pageSize, ref totalNumber); + return (list, totalNumber); + } + + /// + /// 分页查询 + /// + /// + /// + /// + /// + /// + public (List, int) QueryableToPage(Expression> expression, string order, int pageIndex = 0, int pageSize = 10) + { + int totalNumber = 0; + var list = Entities.Where(expression).OrderBy(order).ToPageList(pageIndex, pageSize, ref totalNumber); + return (list, totalNumber); + } + + /// + /// 分页查询 + /// + /// + /// + /// + /// + /// + /// + /// + /// + public List QueryableToPage(Expression> expression, Expression> order, OrderByType ordertype, int pageIndex, int pageSize, ref int totalNumber, ref int totalPage) + { + return Entities.Where(expression).OrderByIF(order != null, order, ordertype).ToPageList(pageIndex, pageSize, ref totalNumber, ref totalPage); + } + + /// + /// 分页查询 + /// + /// + /// + /// + /// + /// + /// + public (List, int) QueryableToPage(Expression> expression, Expression> orderFiled, string orderBy, int pageIndex = 0, int pageSize = 10) + { + int totalNumber = 0; + + if (orderBy.Equals("DESC", StringComparison.OrdinalIgnoreCase)) + { + var list = Entities.Where(expression).OrderBy(orderFiled, OrderByType.Desc).ToPageList(pageIndex, pageSize, ref totalNumber); + return (list, totalNumber); + } + else + { + var list = Entities.Where(expression).OrderBy(orderFiled, OrderByType.Asc).ToPageList(pageIndex, pageSize, ref totalNumber); + return (list, totalNumber); + } + } + + /// + /// 通过主键获取实体 + /// + /// + /// + public TEntity Single(dynamic Id) + { + return Entities.InSingle(Id); + } + + /// + /// 获取一个实体 + /// + /// + /// + public TEntity Single(Expression> whereExpression) + { + return Entities.Single(whereExpression); + } + + /// + /// 通过排序获取一个实体 + /// + /// + /// + /// + /// + public TEntity OrderSingle(Expression> whereExpression, Expression> OrderExpression, OrderByType orderType= OrderByType.Asc) + { + return Entities.OrderByIF(OrderExpression!=null, OrderExpression, orderType).Single(whereExpression); + } + + /// + /// 获取一个实体 + /// + /// + /// + public Task SingleAsync(Expression> whereExpression) + { + return Entities.SingleAsync(whereExpression); + } + + /// + /// 获取列表 + /// + /// + public List ToList() + { + return Entities.ToList(); + } + + /// + /// 获取列表 + /// + /// + /// + public List ToList(Expression> whereExpression) + { + return Entities.Where(whereExpression).ToList(); + } + + /// + /// 获取列表 + /// + /// + /// + /// + /// + public List ToList(Expression> whereExpression, Expression> orderByExpression = null, OrderByType orderByType = OrderByType.Asc) + { + return Entities.OrderByIF(orderByExpression != null, orderByExpression, orderByType).Where(whereExpression).ToList(); + } + + /// + /// 获取列表 + /// + /// + public Task> ToListAsync() + { + return Entities.ToListAsync(); + } + + /// + /// 获取列表 + /// + /// + /// + public Task> ToListAsync(Expression> whereExpression) + { + return Entities.Where(whereExpression).ToListAsync(); + } + + /// + /// 获取列表 + /// + /// + /// + /// + /// + public Task> ToListAsync(Expression> whereExpression, Expression> orderByExpression = null, OrderByType orderByType = OrderByType.Asc) + { + return Entities.OrderByIF(orderByExpression != null, orderByExpression, orderByType).Where(whereExpression).ToListAsync(); + } + + #endregion + + #region 新增 + + public virtual IInsertable AsInsertable(TEntity entity) + { + return EntityContext.Insertable(entity); + } + + public virtual IInsertable AsInsertable(params TEntity[] entities) + { + return EntityContext.Insertable(entities); + } + + /// + /// 新增一条记录 + /// + /// + /// + public virtual int Insert(TEntity entity) + { + return EntityContext.Insertable(entity).ExecuteCommand(); + } + + /// + /// 新增多条记录 + /// + /// + /// + public virtual int Insert(params TEntity[] entities) + { + return EntityContext.Insertable(entities).ExecuteCommand(); + } + + /// + /// 新增多条记录 + /// + /// + /// + public virtual int Insert(IEnumerable entities) + { + return EntityContext.Insertable(entities.ToArray()).ExecuteCommand(); + } + + /// + /// 新增一条记录 + /// + /// + /// + public virtual Task InsertAsync(TEntity entity) + { + return EntityContext.Insertable(entity).ExecuteCommandAsync(); + } + + /// + /// 新增多条记录 + /// + /// + /// + public virtual Task InsertAsync(params TEntity[] entities) + { + return EntityContext.Insertable(entities).ExecuteCommandAsync(); + } + + /// + /// 新增多条记录 + /// + /// + /// + public virtual Task InsertAsync(IEnumerable entities) + { + if (entities != null && entities.Any()) + { + return EntityContext.Insertable(entities.ToArray()).ExecuteCommandAsync(); + } + return Task.FromResult(0); + } + + /// + /// 新增一条记录返回实体 + /// + /// + /// + public virtual TEntity InsertReturnEntity(TEntity entity) + { + return EntityContext.Insertable(entity).ExecuteReturnEntity(); + } + + /// + /// 新增一条记录返回实体 + /// + /// + /// + public virtual async Task InsertReturnEntityAsync(TEntity entity) + { + return await EntityContext.Insertable(entity).ExecuteReturnEntityAsync(); + } + + /// + /// 新增一条记录返回自增Id + /// + /// + /// + public virtual int InsertReturnIdentity(TEntity insertObj) + { + return EntityContext.Insertable(insertObj).ExecuteReturnIdentity(); + } + + /// + /// 新增一条记录返回自增Id + /// + /// + /// + public virtual async Task InsertReturnIdentityAsync(TEntity entity) + { + return await EntityContext.Insertable(entity).ExecuteReturnBigIdentityAsync(); + } + + /// + /// 新增一条记录返回雪花Id + /// + /// + /// + public virtual long InsertReturnSnowflakeId(TEntity entity) + { + return EntityContext.Insertable(entity).ExecuteReturnSnowflakeId(); + } + + /// + /// 新增一条记录返回雪花Id + /// + /// + /// + public virtual async Task InsertReturnSnowflakeIdAsync(TEntity entity) + { + return await EntityContext.Insertable(entity).ExecuteReturnSnowflakeIdAsync(); + } + + #endregion + + #region 更新 + + public virtual IUpdateable AsUpdateable(TEntity entity) + { + return EntityContext.Updateable(entity).IgnoreColumns(UpdateIgnoreColumns); + } + + public virtual IUpdateable AsUpdateable(IEnumerable entities) + { + return EntityContext.Updateable(entities).IgnoreColumns(UpdateIgnoreColumns); + } + + /// + /// 更新一条记录 + /// + /// + /// + public virtual int Update(TEntity entity) + { + return EntityContext.Updateable(entity).IgnoreColumns(UpdateIgnoreColumns).ExecuteCommand(); + } + + /// + /// 更新多条记录 + /// + /// + /// + public virtual int Update(params TEntity[] entities) + { + return EntityContext.Updateable(entities).IgnoreColumns(UpdateIgnoreColumns).ExecuteCommand(); + } + + /// + /// 根据条件更新 + /// + /// + /// + /// + public virtual int Update(TEntity entity, Expression> UpdateColumns = null, params string[] WhereColumnNames) + { + return EntityContext.Updateable(entity).WhereColumns(WhereColumnNames).UpdateColumnsIF(UpdateColumns != null, UpdateColumns).IgnoreColumns(UpdateIgnoreColumns).ExecuteCommand(); + } + + /// + /// 更新多条记录 + /// + /// + /// + public virtual int Update(IEnumerable entities) + { + return EntityContext.Updateable(entities.ToArray()).IgnoreColumns(UpdateIgnoreColumns).ExecuteCommand(); + } + + /// + /// 更新记录 + /// + /// 更新的条件 + /// 更新的内容 + /// + public virtual int Update(Expression> predicate, Expression> content) + { + return EntityContext.Updateable(content).Where(predicate).IgnoreColumns(UpdateIgnoreColumns).ExecuteCommand(); + } + + /// + /// 更新一条记录 + /// + /// + /// + public virtual async Task UpdateAsync(TEntity entity) + { + return await EntityContext.Updateable(entity).IgnoreColumns(UpdateIgnoreColumns).ExecuteCommandAsync(); + } + + /// + /// 更新记录 + /// + /// 更新的条件 + /// 更新的内容 + /// + public virtual async Task UpdateAsync(Expression> predicate, Expression> content) + { + return await EntityContext.Updateable(content).Where(predicate).IgnoreColumns(UpdateIgnoreColumns).ExecuteCommandAsync(); + } + + /// + /// 更新多条记录 + /// + /// + /// + public virtual Task UpdateAsync(params TEntity[] entities) + { + return EntityContext.Updateable(entities).IgnoreColumns(UpdateIgnoreColumns).ExecuteCommandAsync(); + } + + /// + /// 更新多条记录 + /// + /// + /// + public virtual Task UpdateAsync(IEnumerable entities) + { + return EntityContext.Updateable(entities.ToArray()).IgnoreColumns(UpdateIgnoreColumns).ExecuteCommandAsync(); + } + + #endregion + + #region 删除 + + /// + /// 删除一条记录 + /// + /// + /// + public virtual int Delete(TEntity entity) + { + return EntityContext.Deleteable(entity).ExecuteCommand(); + } + + /// + /// 删除一条记录 + /// + /// + /// + public virtual int Delete(object key) + { + return EntityContext.Deleteable().In(key).ExecuteCommand(); + } + + /// + /// 删除多条记录 + /// + /// + /// + public virtual int Delete(params object[] keys) + { + return EntityContext.Deleteable().In(keys).ExecuteCommand(); + } + + /// + /// 自定义条件删除记录 + /// + /// + /// + public int Delete(Expression> whereExpression) + { + return EntityContext.Deleteable().Where(whereExpression).ExecuteCommand(); + } + + /// + /// 删除一条记录 + /// + /// + /// + public virtual Task DeleteAsync(TEntity entity) + { + return EntityContext.Deleteable(entity).ExecuteCommandAsync(); + } + + /// + /// 删除一条记录 + /// + /// + /// + public virtual Task DeleteAsync(object key) + { + return EntityContext.Deleteable().In(key).ExecuteCommandAsync(); + } + + /// + /// 删除多条记录 + /// + /// + /// + public virtual Task DeleteAsync(params object[] keys) + { + return EntityContext.Deleteable().In(keys).ExecuteCommandAsync(); + } + + /// + /// 自定义条件删除记录 + /// + /// + /// + public async Task DeleteAsync(Expression> whereExpression) + { + return await EntityContext.Deleteable().Where(whereExpression).ExecuteCommandAsync(); + } + + #endregion + + #region 其他 + + /// + /// 直接返回数据库结果 + /// + /// + public virtual Task> AsAsyncEnumerable() + { + return AsQueryable().ToListAsync(); + } + + /// + /// 直接返回数据库结果 + /// + /// + /// + public virtual Task> AsAsyncEnumerable(Expression> predicate) + { + return AsQueryable(predicate).ToListAsync(); + } + + /// + /// 直接返回数据库结果 + /// + /// + public virtual List AsEnumerable() + { + return AsQueryable().ToList(); + } + + /// + /// 直接返回数据库结果 + /// + /// + /// + public virtual List AsEnumerable(Expression> predicate) + { + return AsQueryable(predicate).ToList(); + } + + /// + /// 构建查询分析器 + /// + /// + public virtual ISugarQueryable AsQueryable() + { + return Entities; + } + + /// + /// 构建查询分析器 + /// + /// + /// + public virtual ISugarQueryable AsQueryable(Expression> predicate) + { + return Entities.Where(predicate); + } + + /// + /// 是否包含 + /// + /// + /// + public virtual bool IsExists(Expression> whereExpression) + { + return Entities.Any(whereExpression); + } + + /// + /// 是否包含(异步) + /// + /// + /// + public virtual Task IsExistsAsync(Expression> whereExpression) + { + return Entities.AnyAsync(whereExpression); + } + + /// + /// 根据表达式查询多条记录 + /// + /// + /// + public virtual ISugarQueryable Where(Expression> predicate) + { + return AsQueryable(predicate); + } + + /// + /// 根据表达式查询多条记录 + /// + /// + /// + /// + public virtual ISugarQueryable Where(bool condition, Expression> predicate) + { + return AsQueryable().WhereIF(condition, predicate); + } + + #endregion + + #region 仓储事务 + + /// + /// 所有db开启事务 + /// + public void BeginTran() + { + Context.BeginTran(); + } + + /// + /// 切换仓储(注意使用环境) + /// + /// 实体类型 + /// 仓储 + public virtual SqlSugarRepository Change() + where T : class, new() + { + return VampirewalCoreContext.GetInstance().GetService>(); + } + + /// + /// 当前Client执行事务 + /// + /// + /// + /// + public bool ClientUseTran(Action OperationAction, Action ErrorAction = null) + { + var result = Ado.UseTran(OperationAction, ErrorAction); + + return result.IsSuccess; + } + + /// + /// 所有db提交事务 + /// + public void CommitTran() + { + Context.CommitTran(); + } + + /// + /// 全局使用事务 + /// + /// + /// + /// + public bool ContextUseTran(Action OperationAction, Action ErrorAction = null) + { + var result = Context.Ado.UseTran(OperationAction, ErrorAction); + return result.IsSuccess; + } + + /// + /// 当前db开启事务 + /// + public void CurrentBeginTran() + { + Ado.BeginTran(); + } + + /// + /// 当前db提交事务 + /// + public void CurrentCommitTran() + { + Ado.CommitTran(); + } + + /// + /// 当前db回滚事务 + /// + public void CurrentRollbackTran() + { + Ado.RollbackTran(); + } + + /// + /// 所有db回滚事务 + /// + public void RollbackTran() + { + Context.RollbackTran(); + } + + #endregion +} \ No newline at end of file diff --git a/Vampirewal.Core/Components/VampirewalCoreDialogService.cs b/Vampirewal.Core/Components/VampirewalCoreDialogService.cs new file mode 100644 index 0000000000000000000000000000000000000000..565d39a005f72456add78b37618c7bf84b1894ed --- /dev/null +++ b/Vampirewal.Core/Components/VampirewalCoreDialogService.cs @@ -0,0 +1,86 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:VampirewalDialog +// 创 建 者:杨程 +// 创建时间:2021/10/18 10:51:10 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.Components; + +/// +/// Vampirewal自定义消息弹出框 +/// +public class VampirewalCoreDialogService:IVampirewalCoreDialogMessage +{ + + + /// + /// 弹出PopupWindow消息框 + /// + /// 消息内容 + /// 在哪个窗体内弹出 + /// 消息类型 + /// 是否自动关闭 + public void ShowPopupWindow(string Msg, Window window, MessageType messageType, bool iskeepOpen = false) + { + PopupWindow popup = new PopupWindow(Msg, window, messageType, iskeepOpen); + popup.Show(); + } + + /// + /// 弹出DialogWindow窗体 + /// + /// 窗体设置 + public object OpenDialogWindow(DialogWindowSetting setting) + { + ShowDialogWindow window = new ShowDialogWindow(setting); + WindowsManager.GetInstance().RegisterDialogWindow(window.ViewId, window); + window.ShowDialog(); + + var vm = window.DataContext as ViewModelBase; + + return vm.GetResult(); + } + + /// + /// 该方法暂时不提供使用 + /// + /// + [Obsolete("该方法暂时不提供使用!",true)] + public string OpenVampirewalFolderBrowserDialog() + { + VampirewalFolderBrowserDialog folderBrowserDialog = new VampirewalFolderBrowserDialog(); + + + if (folderBrowserDialog.ShowDialog()==true) + { + return folderBrowserDialog.FullPath; + } + else + { + return ""; + } + + } + + /// + /// 弹出Notify通知窗 + /// + public void OpenNotifyWindow(NotifyWindowSetting Setting) + { + NotifyWindow notify = new NotifyWindow(Setting); + notify.Topmost = true; + notify.ShowInTaskbar = false; + //notify.Owner = WindowsManager.GetInstance().MainWindow; + notify.ShowDialog(); + } +} diff --git a/Vampirewal.Core/Components/VampirewalCoreLogService.cs b/Vampirewal.Core/Components/VampirewalCoreLogService.cs new file mode 100644 index 0000000000000000000000000000000000000000..578eecbaef2c3871624dfc2adc44bec30a9d8640 --- /dev/null +++ b/Vampirewal.Core/Components/VampirewalCoreLogService.cs @@ -0,0 +1,169 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:VampirewalLog +// 创 建 者:杨程 +// 创建时间:2021/9/24 10:21:40 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.Components; + +/// +/// VampirewalLog日志 +/// +public class VampirewalCoreLogService : IVampirewalCoreLogService +{ + private int LogLevel { get; set; } + + private SqlSugarRepository rep { get; set; } + /// + /// 构造函数 + /// + public VampirewalCoreLogService(SqlSugarRepository _rep) + { + rep= _rep; + LogLevel = (int)VampirewalCoreContext.GetInstance().GetOptions().LogLevel; + } + + + /// + /// 写Debug日志 + /// + /// + /// + public virtual void DebugLog(string Msg, string SystemModuleName) + { + if (LogLevel>=0) + { + + Logger logger = new Logger() + { + LoggerContent = Msg, + loggerType = LoggerType.Debug, + SystemMoudleName = SystemModuleName, + CreateTime = DateTime.Now, + CreateBy = VampirewalCoreContext.GetInstance().GetContext("UserName",out object UserName)==true?UserName.ToString():"", + CreateUserId = VampirewalCoreContext.GetInstance().GetContext("UserId", out object UserId) == true ? UserId.ToString() : "", + }; + + try + { + rep.CurrentBeginTran(); + rep.Insert(logger); + rep.CurrentCommitTran(); + } + catch (Exception ex) + { + rep.CurrentRollbackTran(); + + } + + + } + } + + /// + /// 写错误日志 + /// + /// + /// + public virtual void ErrorLog(string Msg, string SystemModuleName) + { + if (LogLevel >= 2) + { + + Logger logger = new Logger() + { + LoggerContent = Msg, + loggerType = LoggerType.Error, + SystemMoudleName = SystemModuleName, + CreateTime = DateTime.Now, + CreateBy = VampirewalCoreContext.GetInstance().GetContext("UserName", out object UserName) == true ? UserName.ToString() : "", + CreateUserId = VampirewalCoreContext.GetInstance().GetContext("UserId", out object UserId) == true ? UserId.ToString() : "", + }; + rep.Insert(logger); + } + + + } + + /// + /// SQL出现问题 + /// + /// + /// + public virtual void SQLLog(string Msg, string SystemModuleName) + { + if (LogLevel >= 3) + { + + Logger logger = new Logger() + { + LoggerContent = Msg, + loggerType = LoggerType.SQL, + SystemMoudleName = SystemModuleName, + CreateTime = DateTime.Now, + CreateBy = VampirewalCoreContext.GetInstance().GetContext("UserName", out object UserName) == true ? UserName.ToString() : "", + CreateUserId = VampirewalCoreContext.GetInstance().GetContext("UserId", out object UserId) == true ? UserId.ToString() : "", + }; + rep.Insert(logger); + } + + } + + /// + /// 写警告日志 + /// + /// + /// + public virtual void WarningLog(string Msg, string SystemModuleName) + { + if (LogLevel >= 1) + { + + Logger logger = new Logger() + { + LoggerContent = Msg, + loggerType = LoggerType.Warning, + SystemMoudleName = SystemModuleName, + CreateTime = DateTime.Now, + CreateBy = VampirewalCoreContext.GetInstance().GetContext("UserName", out object UserName) == true ? UserName.ToString() : "", + CreateUserId = VampirewalCoreContext.GetInstance().GetContext("UserId", out object UserId) == true ? UserId.ToString() : "", + }; + + rep.Insert(logger); + } + + + } + + /// + /// 写自定义日志 + /// + /// + /// + /// + public virtual void WriteLog(string Msg, LoggerType loggerType, string SystemModuleName) + { + + Logger logger = new Logger() + { + LoggerContent = Msg, + loggerType = loggerType, + SystemMoudleName = SystemModuleName, + CreateTime = DateTime.Now, + CreateBy = VampirewalCoreContext.GetInstance().GetContext("UserName", out object UserName) == true ? UserName.ToString() : "", + CreateUserId = VampirewalCoreContext.GetInstance().GetContext("UserId", out object UserId) == true ? UserId.ToString() : "", + }; + + rep.Insert(logger); + } +} diff --git a/Vampirewal.Core/Components/VampirewalDialog.cs b/Vampirewal.Core/Components/VampirewalDialog.cs deleted file mode 100644 index 2ad8cfdeefd92007f1b6504c2dfea180ba831a56..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/Components/VampirewalDialog.cs +++ /dev/null @@ -1,81 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:VampirewalDialog -// 创 建 者:杨程 -// 创建时间:2021/10/18 10:51:10 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using Vampirewal.Core.Interface; -using Vampirewal.Core.SimpleMVVM; -using Vampirewal.Core.WpfTheme.WindowStyle; - -namespace Vampirewal.Core.Components -{ - /// - /// Vampirewal自定义消息弹出框 - /// - public class VampirewalDialog:IDialogMessage - { - - - /// - /// 弹出PopupWindow消息框 - /// - /// 消息内容 - /// 在哪个窗体内弹出 - /// 消息类型 - /// 是否自动关闭 - public void ShowPopupWindow(string Msg, Window window, MessageType messageType, bool iskeepOpen = false) - { - PopupWindow popup = new PopupWindow(Msg, window, messageType, iskeepOpen); - popup.Show(); - } - - /// - /// 弹出DialogWindow窗体 - /// - /// 窗体设置 - public object OpenDialogWindow(DialogWindowSetting setting) - { - ShowDialogWindow window = new ShowDialogWindow(setting); - window.ShowDialog(); - - var vm = window.DataContext as ViewModelBase; - - return vm.GetResult(); - } - - /// - /// 该方法暂时不提供使用 - /// - /// - [Obsolete("该方法暂时不提供使用!",true)] - public string OpenVampirewalFolderBrowserDialog() - { - VampirewalFolderBrowserDialog folderBrowserDialog = new VampirewalFolderBrowserDialog(); - - - if (folderBrowserDialog.ShowDialog()==true) - { - return folderBrowserDialog.FullPath; - } - else - { - return ""; - } - - } - } -} diff --git a/Vampirewal.Core/Components/VampirewalLog.cs b/Vampirewal.Core/Components/VampirewalLog.cs deleted file mode 100644 index 64350e0897ca1cdb151f50a2c0f9841dc3c08310..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/Components/VampirewalLog.cs +++ /dev/null @@ -1,167 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:VampirewalLog -// 创 建 者:杨程 -// 创建时间:2021/9/24 10:21:40 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Vampirewal.Core.Interface; -using Vampirewal.Core.Models; - -namespace Vampirewal.Core.Components -{ - /// - /// VampirewalLog日志 - /// !!!使用该接口需配合IDataContext!!! - /// !!!如果没有使用IDataContext将会报错!!! - /// - public class VampirewalLog : ILogger - { - private IDataContext DC; - private IAppConfig Config; - /// - /// 构造函数 - /// - /// - /// - public VampirewalLog(IDataContext dc, IAppConfig config) - { - //构造函数 - DC = dc; - Config = config; - - LogLevel = (int)Config.LogLevel; - } - - private int LogLevel = 0; - - /// - /// 写Debug日志 - /// - /// - /// - public void DebugLog(string Msg, string SystemModuleName) - { - if (LogLevel >= 0) - { - Logger logger = new Logger() - { - LoggerContent = Msg, - loggerType = LoggerType.Debug, - SystemMoudleName = SystemModuleName, - CreateTime = DateTime.Now, - CreateBy = SystemDataContext.GetInstance().loginUserInfo?.ITCode - }; - - DC.AddEntity(logger); - DC.SaveChanges(); - } - - } - - /// - /// 写错误日志 - /// - /// - /// - public void ErrorLog(string Msg, string SystemModuleName) - { - if (LogLevel >= 2) - { - Logger logger = new Logger() - { - LoggerContent = Msg, - loggerType = LoggerType.Error, - SystemMoudleName = SystemModuleName, - CreateTime = DateTime.Now, - CreateBy = SystemDataContext.GetInstance().loginUserInfo?.ITCode - }; - - DC.AddEntity(logger); - DC.SaveChanges(); - } - - - } - - /// - /// SQL出现问题 - /// - /// - /// - public void SQLLog(string Msg, string SystemModuleName) - { - if (LogLevel >= 3) - { - Logger logger = new Logger() - { - LoggerContent = Msg, - loggerType = LoggerType.SQL, - SystemMoudleName = SystemModuleName, - CreateTime = DateTime.Now, - CreateBy = SystemDataContext.GetInstance().loginUserInfo?.ITCode - }; - - DC.AddEntity(logger); - DC.SaveChanges(); - } - - } - - /// - /// 写警告日志 - /// - /// - /// - public void WarningLog(string Msg, string SystemModuleName) - { - if (LogLevel >= 1) - { - Logger logger = new Logger() - { - LoggerContent = Msg, - loggerType = LoggerType.Warning, - SystemMoudleName = SystemModuleName, - CreateTime = DateTime.Now, - CreateBy = SystemDataContext.GetInstance().loginUserInfo?.ITCode - }; - - DC.AddEntity(logger); - DC.SaveChanges(); - } - - } - - /// - /// 写自定义日志 - /// - /// - /// - /// - public void WriteLog(string Msg, LoggerType loggerType, string SystemModuleName) - { - Logger logger = new Logger() - { - LoggerContent = Msg, - loggerType = loggerType, - SystemMoudleName = SystemModuleName, - CreateTime = DateTime.Now, - CreateBy = SystemDataContext.GetInstance().loginUserInfo?.ITCode - }; - - DC.AddEntity(logger); - DC.SaveChanges(); - } - } -} diff --git a/Vampirewal.Core/Components/VampirewalMessenger.cs b/Vampirewal.Core/Components/VampirewalMessenger.cs new file mode 100644 index 0000000000000000000000000000000000000000..d0adae54207f240ec02caa9972fe37f46bda50c3 --- /dev/null +++ b/Vampirewal.Core/Components/VampirewalMessenger.cs @@ -0,0 +1,303 @@ +/* 项目名称: Messenger.cs + * 命名空间: Vampirewal.Core.SimpleMVVM + * 类 名 称: Messenger + * 作 者 : 杨程 + * 概 述 : + * 创建时间 : 2021/2/20 18:31:26 + * 更新时间 : 2021/2/20 18:31:26 + * CLR版本 : 4.0.30319.42000 + * ****************************************************** + * Copyright@Administrator 2021 .All rights reserved. + * ****************************************************** + */ + + + + +namespace Vampirewal.Core.Components; + +/// +/// 消息通知类 +/// 此处代码引用自 若汝棋茗 +/// CSDN博客:https://blog.csdn.net/qq_40374647/article/details/127651804?spm=1001.2014.3001.5501 +/// 哔哩哔哩视频:https://space.bilibili.com/94253567 +/// Gitee源代码仓库:https://gitee.com/RRQM_Home +/// Github源代码仓库:https://github.com/RRQM +/// API首页:https://www.yuque.com/rrqm/touchsocket/index +/// 交流QQ群:234762506 +/// +public class VampirewalMessenger : BaseSingleton +{ + /// + /// 注册消息 + /// + public void RegistAll() + { + //var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IMessageManager)))).ToArray(); + var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).Where(t => t.GetInterfaces().Contains(typeof(IVampirewalMessageManager))).ToArray(); + foreach (var v in types) + { + object obj = Activator.CreateInstance(v); + MethodInfo[] methods = obj.GetType().GetMethods().Where(w => w.GetCustomAttribute() != null).ToArray(); + foreach (var item in methods) + { + RegistMethodAttribute attribute = item.GetCustomAttribute(); + if (attribute != null) + { + if (attribute.Token == null) + { + GetInstance().Register(obj, item.Name, item); + } + else + { + GetInstance().Register(obj, attribute.Token, item); + } + } + } + } + } + + public void RegistObject(object obj) + { + MethodInfo[] methods = obj.GetType().GetMethods(); + foreach (var item in methods) + { + RegistMethodAttribute attribute = item.GetCustomAttribute(); + if (attribute != null) + { + if (attribute.Token == null) + { + GetInstance().Register(obj, item.Name, item); + } + else + { + GetInstance().Register(obj, attribute.Token, item); + } + } + } + } + + + Dictionary tokenAndInstance = new Dictionary(); + + /// + /// 获取已注册的Token + /// + /// + public List GetRegisterTokens() + { + List cur = new List(); + foreach (var item in tokenAndInstance) + { + cur.Add(item.Key); + } + + return cur; + } + + /// + /// 注册消息 + /// + /// + /// + /// + /// + public void Register(object register, string token, Action action) + { + TokenInstance tokenInstance = new TokenInstance(); + tokenInstance.Register = register; + tokenInstance.MethodInfo = action.Method; + try + { + tokenAndInstance.Add(token, tokenInstance); + } + catch (Exception) + { + + throw new MessageRegisteredException("该Token消息已注册"); + } + + } + + /// + /// 注册消息 + /// + /// + /// + /// + /// + public void Register(object register, string token, MethodInfo methodInfo) + { + TokenInstance tokenInstance = new TokenInstance(); + tokenInstance.Register = register; + tokenInstance.MethodInfo = methodInfo; + try + { + tokenAndInstance.Add(token, tokenInstance); + } + catch (Exception) + { + + throw new MessageRegisteredException("该Token消息已注册"); + } + + } + + /// + /// 注册消息 + /// + /// 参数类型 + /// + /// + /// + /// + public void Register(object register, string token, Action action) + { + TokenInstance tokenInstance = new TokenInstance(); + tokenInstance.Register = register; + tokenInstance.MethodInfo = action.Method; + try + { + tokenAndInstance.Add(token, tokenInstance); + } + catch (Exception) + { + + throw new MessageRegisteredException("该Token消息已注册"); + } + } + + /// + /// 注册 + /// + /// 参数类型 + /// 返回值类型 + /// + /// + /// + public void Register(object register, string token, Func action) + { + TokenInstance tokenInstance = new TokenInstance(); + tokenInstance.Register = register; + tokenInstance.MethodInfo = action.Method; + try + { + tokenAndInstance.Add(token, tokenInstance); + } + catch (Exception) + { + + throw new MessageRegisteredException("该Token消息已注册"); + } + } + + /// + /// 注册 + /// + /// 参数类型 + /// 传参类型 + /// 返回值类型 + /// + /// + /// + public void Register(object register, string token, Func action) + { + TokenInstance tokenInstance = new TokenInstance(); + tokenInstance.Register = register; + tokenInstance.MethodInfo = action.Method; + try + { + tokenAndInstance.Add(token, tokenInstance); + } + catch (Exception) + { + + throw new MessageRegisteredException("该Token消息已注册"); + } + } + + + /// + /// 注册 + /// + /// 返回值类型 + /// + /// + /// + public void Register(object register, string token, Func action) + { + TokenInstance tokenInstance = new TokenInstance(); + tokenInstance.Register = register; + tokenInstance.MethodInfo = action.Method; + try + { + tokenAndInstance.Add(token, tokenInstance); + } + catch (Exception) + { + + throw new MessageRegisteredException("该Token消息已注册"); + } + } + + /// + /// 卸载消息 + /// + /// + public void Unregister(object register) + { + List key = new List(); + + foreach (var item in tokenAndInstance.Keys) + { + if (register == tokenAndInstance[item].Register) + { + key.Add(item); + } + } + + foreach (var item in key) + { + tokenAndInstance.Remove(item); + } + } + + /// + /// 发送消息 + /// + /// + /// + /// + public void Send(string token, params object[] parameters) + { + try + { + tokenAndInstance[token].MethodInfo.Invoke(tokenAndInstance[token].Register, parameters); + } + catch (KeyNotFoundException) + { + throw new MessageNotFoundException("未找到该消息"); + } + + } + + /// + /// 发送消息 + /// + /// 返回值类型 + /// + /// + /// + /// + public T Send(string token, params object[] parameters) + { + try + { + return (T)tokenAndInstance[token].MethodInfo.Invoke(tokenAndInstance[token].Register, parameters); + } + catch (KeyNotFoundException) + { + throw new MessageNotFoundException("未找到该消息"); + } + } +} diff --git a/Vampirewal.Core/Components/VampirewalMessengerBase.cs b/Vampirewal.Core/Components/VampirewalMessengerBase.cs index df295599fc43adc4c2b7ac815ec9440b1cdd7a95..5c85673b416135dc6c757a0c84575640b47d10bc 100644 --- a/Vampirewal.Core/Components/VampirewalMessengerBase.cs +++ b/Vampirewal.Core/Components/VampirewalMessengerBase.cs @@ -11,28 +11,21 @@ //----------------------------------------------------------------*/ #endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using Vampirewal.Core.SimpleMVVM; -namespace Vampirewal.Core.Components + + +namespace Vampirewal.Core.Components; + +/// +/// 注册通用消息基类 +/// +public class VampirewalMessengerBase:IVampirewalMessageManager { - /// - /// 注册通用消息基类 - /// - public class VampirewalMessengerBase:IMessageManager + public VampirewalMessengerBase() { - public VampirewalMessengerBase() - { - //构造函数 - } + //构造函数 + } - + - } } diff --git a/Vampirewal.Core/Components/VampirewalServiceProviderFactory.cs b/Vampirewal.Core/Components/VampirewalServiceProviderFactory.cs new file mode 100644 index 0000000000000000000000000000000000000000..0fae14733f208b45d3d7d7b2e18792425c7adaba --- /dev/null +++ b/Vampirewal.Core/Components/VampirewalServiceProviderFactory.cs @@ -0,0 +1,116 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: VampirewalServiceProviderFactory +// 创建者: 杨程 +// 创建日期: 2022/12/29 12:49:43 + +//----------------------------------------------------------------*/ +#endregion + + + + + +namespace Vampirewal.Core.Components; + +/// +/// IoC工厂类 +/// +[Obsolete("未启用",true)] +public partial class VampirewalServiceProviderFactory:IServiceProviderFactory +{ + /// + /// + /// + public VampirewalServiceProviderFactory() + { + //构造函数 + } + + public IocContainer CreateBuilder(IServiceCollection services) + { + return new IocContainer(services); + } + + public IServiceProvider CreateServiceProvider(IocContainer containerBuilder) + { + return new Provider(containerBuilder); + } +} + +#region MyRegion +/// +/// 工厂容器 +/// +[Obsolete("未启用", true)] +public class IocContainer +{ + public IocContainer(IServiceCollection serviceDescriptors) + { + ServiceDescriptors = serviceDescriptors; + } + + public IServiceCollection ServiceDescriptors { get; } + +} + +[Obsolete("未启用", true)] +public class Provider : IServiceProvider +{ + private ServiceProvider? ServiceProvider { get; set; } + + public IocContainer ContainerBuilder { get; } + + + public Provider(IocContainer continerBuilder) + { + InitProvider(continerBuilder?.ServiceDescriptors); + ContainerBuilder = continerBuilder; + } + + public object GetService(Type serviceType) + { + var result = ServiceProvider?.GetService(serviceType); + + if (result == null) + { + //result = ContainerBuilder.ServiceDescriptors. + } + + return result; + } + + private void InitProvider(IServiceCollection? serviceDescriptors) + { + var constructorsMethod = typeof(ServiceProvider).GetConstructors(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic).FirstOrDefault(); + if (constructorsMethod != null && serviceDescriptors != null) + { + ServiceProvider = constructorsMethod.Invoke(new object[] { serviceDescriptors, new ServiceProviderOptions() }) as ServiceProvider; + } + } +} +#endregion + +[Obsolete("未启用", true)] +public class IocBuilder +{ + private class ServiceScope : IServiceScope + { + public ServiceScope(IServiceProvider serviceProvider) => ServiceProvider = serviceProvider; + public IServiceProvider ServiceProvider { get; } + public void Dispose() => (ServiceProvider as IDisposable)?.Dispose(); + } + + private class ServiceScopeFactory : IServiceScopeFactory + { + private readonly Provider _cat; + public ServiceScopeFactory(Provider cat) => _cat = cat; + public IServiceScope CreateScope() => new ServiceScope(_cat); + } +} diff --git a/Vampirewal.Core/Components/VampirewalValidationService.cs b/Vampirewal.Core/Components/VampirewalValidationService.cs new file mode 100644 index 0000000000000000000000000000000000000000..f6fc451bcf01297fa3173a9dffc320ffd1f54159 --- /dev/null +++ b/Vampirewal.Core/Components/VampirewalValidationService.cs @@ -0,0 +1,73 @@ +#region 文件信息 +/*=================================================== +* 类名称: VampirewalValidationService +* 类描述: +* 创建人: YangCheng +* 创建时间: 2022/5/21 13:56:19 +* 修改人: +* 修改时间: +* 版本: @version 1.0 +=====================================================*/ +#endregion + + + + + +namespace Vampirewal.Core.Components; + +/// +/// VampirewalCore错误属性验证服务 +/// 需要验证的类,属性上需要有 +/// +public class VampirewalCoreValidationService : IVampirewalCoreValidationService +{ + public VampirewalCoreValidationService () + { + ErrorList = new List(); + } + + /// + /// + /// + public List ErrorList { get; private set; } + + /// + /// 错误验证(传入需要验证的对象) + /// + /// + /// + /// + public bool IsValidation(T t) where T : class + { + ErrorList.Clear(); + + var type = typeof(T); + var properties = type.GetProperties(); + foreach (var property in properties) + { + var attrs = property.GetCustomAttributes(typeof(ValidationAttribute), true); + if (attrs.Length > 0) + { + foreach (var attr in attrs) + { + var validation = attr as ValidationAttribute; + if (!validation.IsValid(property.GetValue(t))) + { + ErrorList.Add(string.IsNullOrEmpty(validation.ErrorMessage)? $"{property.Name} 未填写错误信息!": validation.ErrorMessage); + } + } + } + } + + if (ErrorList.Count>0) + { + return false; + } + else + { + return true; + } + } + +} diff --git a/Vampirewal.Core/ConfigOptions/AppBaseOptions.cs b/Vampirewal.Core/ConfigOptions/AppBaseOptions.cs new file mode 100644 index 0000000000000000000000000000000000000000..8bfdd3e47abc94822c61e9ae7b70353e75d02b08 --- /dev/null +++ b/Vampirewal.Core/ConfigOptions/AppBaseOptions.cs @@ -0,0 +1,78 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: AppBaseOptions +// 创建者: 杨程 +// 创建日期: 2023/1/28 13:40:41 + +//----------------------------------------------------------------*/ +#endregion + + + +namespace Vampirewal.Core.ConfigOptions; + +/// +/// 程序基础信息配置 +/// +public class AppBaseOptions : IOptions +{ + /// + /// 应用程序名称 + /// + public string AppName { get; set; } = "Vampirewal.Core"; + + /// + /// 应用程序中文名称 + /// + public string AppChineseName { get; set; } = "Vampirewal.Core"; + + /// + /// 应用程序本地版本 + /// + public string AppVersion { get; set; } = "1.0.0.1"; + + /// + /// 日志级别 + /// + public LoggerType LogLevel { get; set; } = LoggerType.Debug; + + /// + /// 加密密钥 + /// + public string EncryptKey { get; set; } = ""; + + + + + private List _ModulesPath; + /// + /// 模块路径 + /// + public List ModulesPath + { + get + { + if (_ModulesPath == null) + { + _ModulesPath = new List() + { + //$"{AppDomain.CurrentDomain.BaseDirectory}测试.dll----例子,正式使用请注释掉或替换" + }; + } + return _ModulesPath; + } + + set + { + _ModulesPath = value; + } + } +} + + diff --git a/Vampirewal.Core/ConfigOptions/DbBaseOptions.cs b/Vampirewal.Core/ConfigOptions/DbBaseOptions.cs new file mode 100644 index 0000000000000000000000000000000000000000..672c599961bb13cc7227c345a07d1f64a9b10afd --- /dev/null +++ b/Vampirewal.Core/ConfigOptions/DbBaseOptions.cs @@ -0,0 +1,77 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: DbBaseOptions +// 创建者: 杨程 +// 创建日期: 2023/1/28 13:57:00 + +//----------------------------------------------------------------*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + + + +namespace Vampirewal.Core.ConfigOptions; + +/// +/// 数据库连接基础配置 +/// +public sealed class DbBaseOptions:IOptions +{ + /// + /// + /// + public DbBaseOptions() + { + //构造函数 + } + + private List _ConnectionStrings; + + public List ConnectionStrings + { + get + { + if (_ConnectionStrings==null) + { + _ConnectionStrings = new List() { }; + } + + return _ConnectionStrings; + } + + set + { + _ConnectionStrings = value; + } + } +} + +/// +/// 连接字符串设置 +/// +public class ConnectionString +{ + /// + /// 数据库名称 + /// + public string Key { get; set; } = "default"; + /// + /// 连接字符串 + /// + public string Value { get; set; } = "Data Source=VampirewalCore.db"; + /// + /// 数据库类型 + /// + public DBTypeEnum? DbType { get; set; }= DBTypeEnum.Sqlite; +} diff --git a/Vampirewal.Core/ConfigOptions/PagingOptions.cs b/Vampirewal.Core/ConfigOptions/PagingOptions.cs new file mode 100644 index 0000000000000000000000000000000000000000..4a48b4e4c6e0bdc6819bc8c5bbf6554160807786 --- /dev/null +++ b/Vampirewal.Core/ConfigOptions/PagingOptions.cs @@ -0,0 +1,36 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: PagingOptions +// 创建者: 杨程 +// 创建日期: 2023/1/28 17:40:04 + +//----------------------------------------------------------------*/ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + + + +namespace Vampirewal.Core.ConfigOptions; + +/// +/// 分页设置 +/// +public class PagingOptions:IOptions +{ + private int _Limit = 20; + /// + /// 每页数 + /// + public int Limit { get => _Limit; set { _Limit = value; } } +} diff --git a/Vampirewal.Core/DBContexts/DBContextBase.cs b/Vampirewal.Core/DBContexts/DBContextBase.cs deleted file mode 100644 index eb9d3ff817c400362a6dad196d193ae45cfb4287..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/DBContexts/DBContextBase.cs +++ /dev/null @@ -1,494 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:DBContextBase -// 创 建 者:杨程 -// 创建时间:2021/9/10 14:31:51 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using System.Linq.Expressions; -using System.Text; -using System.Threading.Tasks; -using Microsoft.Data.Sqlite; -using Microsoft.EntityFrameworkCore; -using Vampirewal.Core.AppConfig; -using Vampirewal.Core.Extensions; -using Vampirewal.Core.Helper; -using Vampirewal.Core.Interface; -using Vampirewal.Core.Models; - -namespace Vampirewal.Core.DBContexts -{ - /// - /// EF的DBContext基类(包含:日志库,用户数据库,角色数据库,用户角色关联表和域表) - /// - public class DBContextBase: EmptyContext, IDataContext - { - /// - /// - /// - public DBContextBase():base() - { - //构造函数 - InitData(); - } - - protected IAppConfig AppConfig; - /// - /// 包含配置文件的构造函数 - /// - /// - public DBContextBase(IAppConfig appConfig) - { - appConfig.LoadAppConfig(); - AppConfig = appConfig; - InitData(); - } - - public DBContextBase(string cs):base(cs) - { - //构造函数 - InitData(); - } - - public DBContextBase(string cs, DBTypeEnum dbtype, string version = null) : base(cs, dbtype, version) - { - //构造函数 - InitData(); - } - - public DBContextBase(CS cs) : base(cs) - { - //构造函数 - InitData(); - } - - public DBContextBase(DbContextOptions options) : base(options) - { - //构造函数 - InitData(); - } - - /// - /// 日志数据库 - /// - public DbSet Loggers { get; set; } - - /// - /// 用户数据库 - /// - public DbSet frameworkUsers { get; set; } - - /// - /// 角色数据库 - /// - public DbSet frameworkRoles { get; set; } - - /// - /// 用户角色关联表 - /// - public DbSet frameworkUserRoles { get; set; } - - /// - /// 域 - /// - public DbSet frameworkDomains { get; set; } - - /// - /// 初始化数据 - /// - protected virtual void InitData() - { - - } - - - } - - /// - /// 完全自定义的DBContext基类 - /// - public class CustomDbContextBase : EmptyContext, IDataContext - { - /// - /// - /// - public CustomDbContextBase() : base() - { - //构造函数 - InitData(); - } - - protected IAppConfig AppConfig; - /// - /// 包含配置文件的构造函数 - /// - /// - public CustomDbContextBase(IAppConfig appConfig) - { - appConfig.LoadAppConfig(); - AppConfig = appConfig; - InitData(); - } - - public CustomDbContextBase(string cs) : base(cs) - { - //构造函数 - InitData(); - } - - public CustomDbContextBase(string cs, DBTypeEnum dbtype, string version = null) : base(cs, dbtype, version) - { - //构造函数 - InitData(); - } - - public CustomDbContextBase(CS cs) : base(cs) - { - //构造函数 - InitData(); - } - - public CustomDbContextBase(DbContextOptions options) : base(options) - { - //构造函数 - InitData(); - } - - - /// - /// 初始化数据 - /// - protected virtual void InitData() - { - - } - - - } - - - public partial class EmptyContext : DbContext, IDataContext - { - /// - /// FrameworkContext - /// - public EmptyContext() - { - CSName = "default"; - DBType = DBTypeEnum.SQLite; - } - - /// - /// FrameworkContext - /// - /// - public EmptyContext(string cs) - { - CSName = cs; - } - - public EmptyContext(string cs, DBTypeEnum dbtype, string version = null) - { - CSName = cs; - DBType = dbtype; - Version = version; - } - - public EmptyContext(CS cs) - { - CSName = cs.Value; - DBType = cs.DbType.Value; - Version = cs.Version; - ConnectionString = cs; - } - - public EmptyContext(DbContextOptions options) : base(options) { } - - - - public bool IsFake { get ; set ; } - public DBTypeEnum DBType { get; set; } - public string CSName { get; set; } - - public string Version { get; set; } - - public CS ConnectionString { get; set; } - - public void AddEntity(T entity) where T : TopBaseModel - { - this.Entry(entity).State = EntityState.Added; - } - - public void CascadeDelete(T entity) where T : TopBaseModel, ITreeData - { - if (entity != null && entity.ID != Guid.Empty.ToString()) - { - var set = this.Set(); - var entities = set.Where(x => x.ParentId.ToString() == entity.ID).ToList(); - if (entities.Count > 0) - { - foreach (var item in entities) - { - CascadeDelete(item); - } - } - DeleteEntity(entity); - } - } - - public object CreateCommandParameter(string name, object value, ParameterDirection dir) - { - object rv = null; - switch (this.DBType) - { - case DBTypeEnum.SqlServer: - //rv = new SqlParameter(name, value) { Direction = dir }; - break; - case DBTypeEnum.MySql: - //rv = new MySqlParameter(name, value) { Direction = dir }; - break; - case DBTypeEnum.PgSql: - //rv = new NpgsqlParameter(name, value) { Direction = dir }; - break; - case DBTypeEnum.SQLite: - rv = new SqliteParameter(name, value) { Direction = dir }; - break; - case DBTypeEnum.Oracle: - //rv = new OracleParameter(name, value) { Direction = dir }; - break; - } - return rv; - } - - public IDataContext CreateNew() - { - if (ConnectionString != null) - { - return (IDataContext)this.GetType().GetConstructor(new Type[] { typeof(CS) }).Invoke(new object[] { ConnectionString }); ; - } - else - { - return (IDataContext)this.GetType().GetConstructor(new Type[] { typeof(string), typeof(DBTypeEnum), typeof(string) }).Invoke(new object[] { CSName, DBType, Version }); - } - } - - public async Task DataInit(object AllModel, bool IsSpa) - { - bool rv = await Database.EnsureCreatedAsync(); - return rv; - } - - /// - /// 删除 - /// - /// - /// - public void DeleteEntity(T entity) where T : TopBaseModel - { - var set = this.Set(); - var exist = set.Local.AsQueryable().CheckID(entity.GetID()).FirstOrDefault(); - if (exist == null) - { - set.Attach(entity); - set.Remove(entity); - } - else - { - set.Remove(exist); - - } - } - - public IDataContext ReCreate() - { - if (ConnectionString != null) - { - return (IDataContext)this.GetType().GetConstructor(new Type[] { typeof(CS) }).Invoke(new object[] { ConnectionString }); ; - } - else - { - return (IDataContext)this.GetType().GetConstructor(new Type[] { typeof(string), typeof(DBTypeEnum), typeof(string) }).Invoke(new object[] { CSName, DBType, Version }); - } - } - - public DataTable Run(string sql, CommandType commandType, params object[] paras) - { - DataTable table = new DataTable(); - switch (this.DBType) - { - case DBTypeEnum.SqlServer: - //SqlConnection con = this.Database.GetDbConnection() as SqlConnection; - //SqlDataAdapter adapter = new SqlDataAdapter(); - //using (SqlCommand cmd = new SqlCommand(sql, con)) - //{ - // adapter.SelectCommand = cmd; - // cmd.CommandTimeout = 2400; - // cmd.CommandType = commandType; - // if (paras != null) - // { - // foreach (var param in paras) - // cmd.Parameters.Add(param); - // } - // adapter.Fill(table); - // adapter.SelectCommand.Parameters.Clear(); - //} - break; - case DBTypeEnum.MySql: - //MySqlConnection mySqlCon = this.Database.GetDbConnection() as MySqlConnection; - //using (MySqlCommand cmd = new MySqlCommand(sql, mySqlCon)) - //{ - // if (mySqlCon.State == ConnectionState.Closed) - // { - // mySqlCon.Open(); - // } - // cmd.CommandTimeout = 2400; - // cmd.CommandType = commandType; - // if (paras != null) - // { - // foreach (var param in paras) - // cmd.Parameters.Add(param); - // } - // MySqlDataReader dr = cmd.ExecuteReader(); - // table.Load(dr); - // dr.Close(); - // mySqlCon.Close(); - //} - break; - case DBTypeEnum.PgSql: - //Npgsql.NpgsqlConnection npgCon = this.Database.GetDbConnection() as Npgsql.NpgsqlConnection; - //using (Npgsql.NpgsqlCommand cmd = new Npgsql.NpgsqlCommand(sql, npgCon)) - //{ - // if (npgCon.State == ConnectionState.Closed) - // { - // npgCon.Open(); - // } - // cmd.CommandTimeout = 2400; - // cmd.CommandType = commandType; - // if (paras != null) - // { - // foreach (var param in paras) - // cmd.Parameters.Add(param); - // } - // Npgsql.NpgsqlDataReader dr = cmd.ExecuteReader(); - // table.Load(dr); - // dr.Close(); - // npgCon.Close(); - //} - break; - case DBTypeEnum.SQLite: - case DBTypeEnum.Oracle: - //var connection = this.Database.GetDbConnection(); - //var isClosed = connection.State == ConnectionState.Closed; - //if (isClosed) - //{ - // connection.Open(); - //} - //using (var command = connection.CreateCommand()) - //{ - // command.CommandText = sql; - // command.CommandTimeout = 2400; - // command.CommandType = commandType; - // if (paras != null) - // { - // foreach (var param in paras) - // command.Parameters.Add(param); - // } - // using (var reader = command.ExecuteReader()) - // { - // table.Load(reader); - // } - //} - //if (isClosed) - //{ - // connection.Close(); - //} - break; - } - return table; - } - - public IEnumerable Run(string sql, CommandType commandType, params object[] paras) - { - IEnumerable entityList = new List(); - DataTable dt = Run(sql, commandType, paras); - entityList = EntityHelper.GetEntityList(dt); - return entityList; - } - - public DataTable RunSP(string command, params object[] paras) - { - return Run(command, CommandType.StoredProcedure, paras); - } - - public IEnumerable RunSP(string command, params object[] paras) - { - return Run(command, CommandType.StoredProcedure, paras); - } - - public DataTable RunSQL(string command, params object[] paras) - { - return Run(command, CommandType.Text, paras); - } - - public IEnumerable RunSQL(string sql, params object[] paras) - { - return Run(sql, CommandType.Text, paras); - } - - - - #region 更新 - /// - /// 更新entity - /// - /// - /// - public void UpdateEntity(T entity) where T : TopBaseModel - { - this.Entry(entity).State = EntityState.Modified; - } - - /// - /// 更新属性 - /// - /// 模型 - /// 实体类 - /// 属性 - public void UpdateProperty(T entity, Expression> fieldExp) where T : TopBaseModel - { - var set = this.Set(); - if (set.Local.AsQueryable().CheckID(entity.GetID()).FirstOrDefault() == null) - { - set.Attach(entity); - } - this.Entry(entity).Property(fieldExp).IsModified = true; - } - - /// - /// 更新属性 - /// - /// - /// - /// - public void UpdateProperty(T entity, string fieldName) where T : TopBaseModel - { - var set = this.Set(); - if (set.Local.AsQueryable().CheckID(entity.GetID()).FirstOrDefault() == null) - { - set.Attach(entity); - } - this.Entry(entity).Property(fieldName).IsModified = true; - } - #endregion - } -} diff --git a/Vampirewal.Core/Enums.cs b/Vampirewal.Core/Enums.cs deleted file mode 100644 index 28cbe8223c6b0965352e24618d87bb5301ea0b23..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/Enums.cs +++ /dev/null @@ -1,248 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:Enums -// 创 建 者:杨程 -// 创建时间:2021/9/15 14:26:53 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Vampirewal.Core -{ - /// - /// 列表操作列类型 - /// - public enum ColumnFormatTypeEnum - { - Dialog,//弹出窗口 - Button,//按钮 - Download,//下载 - ViewPic,//查看图片 - Script,//脚本 - Html - } - - /// - /// 上传图片存储方式 - /// - public enum SaveFileModeEnum - { - Local = 0,//本地 - Database = 1,//数据库 - DFS = 2 //DFS - }; - - /// - /// 数据库类型 - /// - public enum DBTypeEnum { SqlServer, MySql, PgSql, Memory, SQLite, Oracle } - - /// - /// 页面显示方式 - /// - public enum PageModeEnum { Single, Tab } - - /// - /// Tab页的显示方式 - /// - public enum TabModeEnum { Default, Simple } - - /// - /// Notification出现的位置 - /// - public enum ExtPosition - { - b = 0, //下 - bl = 1,//左下 - br = 2,//右下 - t = 3,//上 - tl = 4,//左上 - tr = 5,//右上 - l = 6,//左 - r = 7//右 - } - /// - /// Grid的选择模式 - /// - public enum SelectionModeEnum - { - SINGLE, - SIMPLE, - MULTI - }; - - public enum SortType - { - Local, - Remote, - Disable - } - /// - /// 按钮 - /// - public enum ButtonTypesEnum - { - Button, - Link - }; - - /// - /// 按钮 - /// - public enum RedirectTypesEnum - { - Layer, - Self, - NewWindow, - NewTab, - }; - - - /// - /// 按钮类型 - /// - public enum ButtonOperationEnum - { - Submit, - Button - }; - - ///// - ///// 上传类型 - ///// - //public enum UploadTypesEnum - //{ - // AllFiles, - // ImageFile, - // ZipFile, - // ExcelFile, - // WordFile, - // PDFFile, - // TextFile, - // Custom - //}; - - /// - /// 日期类型 - /// - public enum DateTimeTypeEnum - { - /// - /// 日期选择器 - /// 可选择:年、月、日 - /// - Date, - /// - /// 日期时间选择器 - /// 可选择:年、月、日、时、分、秒 - /// - DateTime, - /// - /// 年选择器 - /// 只提供年列表选择 - /// - Year, - /// - /// 年月选择器 - /// 只提供年、月选择 - /// - Month, - /// - /// 时间选择器 - /// 只提供时、分、秒选择 - /// - Time - }; - - /// - /// 图形枚举 - /// - public enum ChartEnum - { - line, - pie, - column, - bubble, - barcolumn - } - - /// - /// 图形统计值类型 - /// - public enum ChartValueType - { - sum, - count, - sumpct, - countpct - } - /// - /// 图形统计分区类型 - /// - public enum PartitionType - { - year, - month, - day, - hour, - minute, - second - } - - public enum UIEnum - { LayUI, React, VUE } - - public enum NoRightEnum - { - /// - /// 隐藏 - /// - Invisible, - /// - /// 禁用 - /// - Disable - } - - public enum VTypeEnum { url, email, Date, Time, IPaddress, Int, UInt, Double, UDouble, Color, Phone, Tel } - public enum HiddenModeEnum { Display, Visibility, Offsets } - public enum RegionEnum { North, South, West, East, Center } - public enum LayoutEnum { absolute, border, box, fit, center } - public enum LabelAlignEnum { left, right, top } - public enum DockDirEnum { top, left, right, bottom } - public enum BoxAlignEnum { Stretch, Begin, Middle, End, StretchMax } - public enum BoxPackEnum { Start, Middle, End } - public enum BoxDirectionEnum { H, V } - public enum MsgTargetEnum { qtip, title, under, side, none } - public enum FieldTypeEnum { String, Int, Bool, Date } - public enum IconAlignEnum { Left, Right, Bottom, Top } - public enum UploadTypeEnum { AllFiles, ImageFile, ZipFile, ExcelFile, WordFile, PDFFile, TextFile } - public enum ComponentRenderMode { Normal, Declare, Get, Reference } - - public enum BoolComboTypes { YesNo, ValidInvalid, MaleFemale, HaveNotHave, Custom } - - public enum SortDir { Asc, Desc } - - public enum BackgroudColorEnum - { - Grey, - Yellow, - Red - }; - - /// - /// HTTP Method - /// - public enum HttpMethodEnum { GET, POST, PUT, DELETE } - -} diff --git a/Vampirewal.Core/SimpleMVVM/Exception/MessageNotFoundException.cs b/Vampirewal.Core/Exception/MessageNotFoundException.cs similarity index 53% rename from Vampirewal.Core/SimpleMVVM/Exception/MessageNotFoundException.cs rename to Vampirewal.Core/Exception/MessageNotFoundException.cs index 8c21fd8eb951f6a8cab44a85186891b863b23303..6b88077cc713c83ce75850f8d6b376c272927a26 100644 --- a/Vampirewal.Core/SimpleMVVM/Exception/MessageNotFoundException.cs +++ b/Vampirewal.Core/Exception/MessageNotFoundException.cs @@ -11,27 +11,23 @@ * ****************************************************** */ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Vampirewal.Core.SimpleMVVM + + +namespace Vampirewal.Core.SimpleMVVM; + +/// +/// 未找到消息异常类 +/// +[Serializable] +public class MessageNotFoundException : Exception { /// - /// 未找到消息异常类 + /// /// - [Serializable] - public class MessageNotFoundException : Exception + /// + public MessageNotFoundException(string mes) : base(mes) { - /// - /// - /// - /// - public MessageNotFoundException(string mes) : base(mes) - { - } } } diff --git a/Vampirewal.Core/SimpleMVVM/Exception/MessageRegisteredException.cs b/Vampirewal.Core/Exception/MessageRegisteredException.cs similarity index 55% rename from Vampirewal.Core/SimpleMVVM/Exception/MessageRegisteredException.cs rename to Vampirewal.Core/Exception/MessageRegisteredException.cs index 1a23326e7f4336035488f7687cc0bedb81141642..98b9d755a4ccaa3acee919d37a35505a684dc851 100644 --- a/Vampirewal.Core/SimpleMVVM/Exception/MessageRegisteredException.cs +++ b/Vampirewal.Core/Exception/MessageRegisteredException.cs @@ -11,27 +11,23 @@ * ****************************************************** */ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Vampirewal.Core.SimpleMVVM + + +namespace Vampirewal.Core.SimpleMVVM; + +/// +/// +/// +[Serializable] +public class MessageRegisteredException : Exception { /// /// /// - [Serializable] - public class MessageRegisteredException : Exception + /// + public MessageRegisteredException(string mes) : base(mes) { - /// - /// - /// - /// - public MessageRegisteredException(string mes) : base(mes) - { - } } } diff --git a/Vampirewal.Core/Extensions/DCExtension.cs b/Vampirewal.Core/Extensions/DCExtension.cs deleted file mode 100644 index 8dbb16d67ac00c86aeae2235adeb8686cd81fc3f..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/Extensions/DCExtension.cs +++ /dev/null @@ -1,467 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:DCExtension -// 创 建 者:杨程 -// 创建时间:2021/9/15 11:39:50 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Data.Common; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Text; -using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; -using System.Transactions; -using Microsoft.EntityFrameworkCore; -using Vampirewal.Core.Helper; -using Vampirewal.Core.Interface; - -namespace Vampirewal.Core.Extensions -{ - /// - /// DataContext相关扩展方法 - /// - public static class DCExtension - { - public static IQueryable CheckID(this IQueryable baseQuery, object val, Expression> member = null) - { - ParameterExpression pe = Expression.Parameter(typeof(T)); - PropertyInfo idproperty = null; - if (member == null) - { - idproperty = typeof(T).GetSingleProperty("ID"); - } - else - { - idproperty = member.GetPropertyInfo(); - } - Expression peid = Expression.Property(pe, idproperty); - var convertid = PropertyHelper.ConvertValue(val, idproperty.PropertyType); - return baseQuery.Where(Expression.Lambda>(Expression.Equal(peid, Expression.Constant(convertid)), pe)); - } - - public static IQueryable CheckWhere(this IQueryable baseQuery, S val, Expression> where) - { - if (val == null) - { - return baseQuery; - } - else - { - if (typeof(IList).IsAssignableFrom(val.GetType())) - { - if (((IList)val).Count == 0) - { - return baseQuery; - } - } - return baseQuery.Where(where); - } - } - - public static IQueryable CheckEqual(this IQueryable baseQuery, string val, Expression> field) - { - if (val == null || val == "") - { - return baseQuery; - } - else - { - var equal = Expression.Equal(field.Body, Expression.Constant(val)); - var where = Expression.Lambda>(equal, field.Parameters[0]); - return baseQuery.Where(where); - } - } - - - public static IQueryable CheckEqual(this IQueryable baseQuery, S? val, Expression> field) - where S : struct - { - if (val == null) - { - return baseQuery; - } - else - { - var equal = Expression.Equal(Expression.PropertyOrField(field.Body, "Value"), Expression.Constant(val)); - var where = Expression.Lambda>(equal, field.Parameters[0]); - return baseQuery.Where(where); - } - } - - public static IQueryable CheckEqual(this IQueryable baseQuery, S val, Expression> field) where S : struct - { - S? a = val; - return baseQuery.CheckEqual(a, field); - } - - - public static IQueryable CheckBetween(this IQueryable baseQuery, S? valMin, S? valMax, Expression> field, bool includeMin = true, bool includeMax = true) where S : struct - { - if (valMin == null && valMax == null) - { - return baseQuery; - } - else - { - IQueryable rv = baseQuery; - if (valMin != null) - { - BinaryExpression exp1 = !includeMin ? Expression.GreaterThan(Expression.PropertyOrField(field.Body, "Value"), Expression.Constant(valMin)) : Expression.GreaterThanOrEqual(Expression.PropertyOrField(field.Body, "Value"), Expression.Constant(valMin)); - rv = rv.Where(Expression.Lambda>(exp1, field.Parameters[0])); - } - if (valMax != null) - { - BinaryExpression exp2 = !includeMax ? Expression.LessThan(Expression.PropertyOrField(field.Body, "Value"), Expression.Constant(valMax)) : Expression.LessThanOrEqual(Expression.PropertyOrField(field.Body, "Value"), Expression.Constant(valMax)); - rv = rv.Where(Expression.Lambda>(exp2, field.Parameters[0])); - } - return rv; - } - } - - public static IQueryable CheckBetween(this IQueryable baseQuery, S valMin, S valMax, Expression> field, bool includeMin = true, bool includeMax = true) where S : struct - { - S? a = valMin; - S? b = valMax; - return CheckBetween(baseQuery, a, b, field, includeMin, includeMax); - } - - public static IQueryable CheckBetween(this IQueryable baseQuery, S? valMin, S valMax, Expression> field, bool includeMin = true, bool includeMax = true) where S : struct - { - S? a = valMin; - S? b = valMax; - return CheckBetween(baseQuery, a, b, field, includeMin, includeMax); - } - - public static IQueryable CheckBetween(this IQueryable baseQuery, S valMin, S? valMax, Expression> field, bool includeMin = true, bool includeMax = true) where S : struct - { - S? a = valMin; - S? b = valMax; - return CheckBetween(baseQuery, a, b, field, includeMin, includeMax); - } - - public static IQueryable CheckContain(this IQueryable baseQuery, string val, Expression> field, bool ignoreCase = true) - { - if (string.IsNullOrEmpty(val)) - { - return baseQuery; - } - else - { - Expression exp = null; - if (ignoreCase == true) - { - var tolower = Expression.Call(field.Body, "ToLower", null); - exp = Expression.Call(tolower, "Contains", null, Expression.Constant(val.ToLower())); - } - else - { - exp = Expression.Call(field.Body, "Contains", null, Expression.Constant(val)); - - } - var where = Expression.Lambda>(exp, field.Parameters[0]); - return baseQuery.Where(where); - } - } - - public static IQueryable CheckContain(this IQueryable baseQuery, List val, Expression> field) - { - if (val == null || val.Count == 0 || (val.Count == 1 && val[0] == null)) - { - return baseQuery; - } - else - { - Expression exp = null; - exp = Expression.Call(Expression.Constant(val), "Contains", null, field.Body); - - var where = Expression.Lambda>(exp, field.Parameters[0]); - return baseQuery.Where(where); - } - } - - //public static string GetTableName(this IDataContext self) - //{ - // if (self.DBType == DBTypeEnum.PgSql) - // { - // return self.Model.FindEntityType(typeof(T)).Npgsql().TableName; - // } - // else - // { - // return self.Model.FindEntityType(typeof(T)).SqlServer().TableName; - // } - //} - /// - /// 通过模型和模型的某个List属性的名称来判断List的字表中关联到主表的主键名称 - /// - /// 主表Model - /// DataContext - /// 主表中的子表List属性名称 - /// 主键名称 - public static string GetFKName(this IDataContext self, string listFieldName) where T : class - { - return GetFKName(self, typeof(T), listFieldName); - } - - /// - /// 通过模型和模型的某个List属性的名称来判断List的字表中关联到主表的主键名称 - /// - /// DataContext - /// 主表model类型 - /// 主表中的子表List属性名称 - /// 主键名称 - public static string GetFKName(this IDataContext self, Type sourceType, string listFieldName) - { - try - { - var test = self.Model.FindEntityType(sourceType).GetReferencingForeignKeys().Where(x => x.PrincipalToDependent?.Name == listFieldName).FirstOrDefault(); - if (test != null && test.Properties.Count > 0) - { - return test.Properties[0].Name; - } - else - { - return ""; - } - } - catch - { - return ""; - } - } - - - /// - /// 通过子表模型和模型关联到主表的属性名称来判断该属性对应的主键名称 - /// - /// 子表Model - /// DataContext - /// 关联主表的属性名称 - /// 主键名称 - public static string GetFKName2(this IDataContext self, string FieldName) where T : class - { - return GetFKName2(self, typeof(T), FieldName); - } - - /// - /// 通过模型和模型关联到主表的属性名称来判断该属性对应的主键名称 - /// - /// DataContext - /// 子表model类型 - /// 关联主表的属性名称 - /// 主键名称 - public static string GetFKName2(this IDataContext self, Type sourceType, string FieldName) - { - try - { - var test = self.Model.FindEntityType(sourceType).GetForeignKeys().Where(x => x.DependentToPrincipal?.Name == FieldName).FirstOrDefault(); - if (test != null && test.Properties.Count > 0) - { - return test.Properties[0].Name; - } - else - { - return ""; - } - } - catch - { - return ""; - } - } - - //public static string GetFieldName(this IDataContext self, Expression> field) - //{ - // string pname = field.GetPropertyName(); - // return self.GetFieldName(pname); - //} - - - //public static string GetFieldName(this IDataContext self, string fieldname) - //{ - // var rv = self.Model.FindEntityType(typeof(T)).FindProperty(fieldname); - // if (rv == null) - // { - // return ""; - // } - // switch (self.DBType) - // { - // case DBTypeEnum.SqlServer: - // return rv.SqlServer().ColumnName; - // case DBTypeEnum.MySql: - // return rv.MySql().ColumnName; - // case DBTypeEnum.PgSql: - // return rv.Npgsql().ColumnName; - // case DBTypeEnum.Memory: - // return rv.SqlServer().ColumnName; - // case DBTypeEnum.SQLite: - // return rv.Sqlite().ColumnName; - // case DBTypeEnum.Oracle: - // return rv.Oracle().ColumnName; - // default: - // return rv.SqlServer().ColumnName; - // } - - //} - - //public static string GetPropertyNameByFk(this IDataContext self, Type sourceType, string fkname) - //{ - // try - // { - // var test = self.Model.FindEntityType(sourceType).GetForeignKeys().Where(x => x.DependentToPrincipal?.ForeignKey?.Properties[0]?.Name == fkname).FirstOrDefault(); - // if (test != null && test.Properties.Count > 0) - // { - // return test.DependentToPrincipal.Name; - // } - // else - // { - // return ""; - // } - // } - // catch - // { - // return ""; - // } - //} - - - public static Expression> GetContainIdExpression(this List Ids, Expression peid = null) - { - //if (Ids == null) - //{ - // Ids = new List(); - //} - - //ParameterExpression pe = Expression.Parameter(typeof(TModel)); - //if (peid == null) - //{ - // peid = Expression.Property(pe, typeof(TModel).GetProperties().Where(x => x.Name.ToLower() == "id").FirstOrDefault()); - //} - //List newids = new List(); - //foreach (var item in Ids) - //{ - // newids.Add(PropertyHelper.ConvertValue(item, peid.Type)); - //} - //Expression dpleft = Expression.Constant(newids, typeof(IEnumerable)); - //Expression dpleft2 = Expression.Call(typeof(Enumerable), "Cast", new Type[] { peid.Type }, dpleft); - //Expression dpleft3 = Expression.Call(typeof(Enumerable), "ToList", new Type[] { peid.Type }, dpleft2); - //Expression dpcondition = Expression.Call(typeof(Enumerable), "Contains", new Type[] { peid.Type }, dpleft3, peid); - ParameterExpression pe = Expression.Parameter(typeof(TModel)); - var rv = Ids.GetContainIdExpression(typeof(TModel), pe, peid) as Expression>; - return rv; - } - - public static LambdaExpression GetContainIdExpression(this List Ids, Type modeltype, ParameterExpression pe, Expression peid = null) - { - if (Ids == null) - { - Ids = new List(); - } - if (peid == null) - { - peid = Expression.Property(pe, modeltype.GetProperties().Where(x => x.Name.ToLower() == "id").FirstOrDefault()); - } - List newids = new List(); - foreach (var item in Ids) - { - newids.Add(PropertyHelper.ConvertValue(item, peid.Type)); - } - Expression dpleft = Expression.Constant(newids, typeof(IEnumerable)); - Expression dpleft2 = Expression.Call(typeof(Enumerable), "Cast", new Type[] { peid.Type }, dpleft); - Expression dpleft3 = Expression.Call(typeof(Enumerable), "ToList", new Type[] { peid.Type }, dpleft2); - Expression dpcondition = Expression.Call(typeof(Enumerable), "Contains", new Type[] { peid.Type }, dpleft3, peid); - var rv = Expression.Lambda(typeof(Func<,>).MakeGenericType(modeltype, typeof(bool)), dpcondition, pe); - return rv; - } - - - /// - /// 开始一个事务,当使用同一IDataContext时,嵌套的两个事务不会引起冲突,当嵌套的事务执行时引起的异常会通过回滚方法向上层抛出异常 - /// - /// DataContext - /// 可用的事务实例 - public static Microsoft.EntityFrameworkCore.Storage.IDbContextTransaction BeginTransaction(this IDataContext self) - { - if (self == null) - throw new ArgumentNullException(nameof(self)); - if (self.Database == null) - throw new ArgumentNullException(nameof(self.Database)); - if (@"Microsoft.EntityFrameworkCore.InMemory".Equals(self.Database.ProviderName, StringComparison.OrdinalIgnoreCase)) - return FakeNestedTransaction.DefaultTransaction; - return self.Database.CurrentTransaction == null ? self.Database.BeginTransaction() : FakeNestedTransaction.DefaultTransaction; - } - - /// - /// 开始一个事务,当使用同一IDataContext时,嵌套的两个事务不会引起冲突,当嵌套的事务执行时引起的异常会通过回滚方法向上层抛出异常 - /// - /// DataContext - /// - /// 可用的事务实例 - //public static Microsoft.EntityFrameworkCore.Storage.IDbContextTransaction BeginTransaction(this IDataContext self, System.Data.IsolationLevel isolationLevel) - //{ - // if (self == null) - // throw new ArgumentNullException(nameof(self)); - // if (self.Database == null) - // throw new ArgumentNullException(nameof(self.Database)); - // if (@"Microsoft.EntityFrameworkCore.InMemory".Equals(self.Database.ProviderName, StringComparison.OrdinalIgnoreCase)) - // return FakeNestedTransaction.DefaultTransaction; - // return self.Database.CurrentTransaction == null ? self.Database.BeginTransaction(isolationLevel) : FakeNestedTransaction.DefaultTransaction; - //} - } - - public static class DbCommandExtension - { - public static void AddParameter(this DbCommand command) - { - - } - } - - internal class FakeNestedTransaction : Microsoft.EntityFrameworkCore.Storage.IDbContextTransaction - { - internal static readonly FakeNestedTransaction DefaultTransaction = new FakeNestedTransaction(); - - private FakeNestedTransaction() { } - - public void Dispose() - { - } - - public void Commit() - { - } - - public void Rollback() - { - throw new TransactionInDoubtException("an exception occurs while executing the nested transaction or processing the results"); - } - - public Task CommitAsync(CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task RollbackAsync(CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public ValueTask DisposeAsync() - { - throw new NotImplementedException(); - } - - public Guid TransactionId => Guid.Empty; - } -} diff --git a/Vampirewal.Core/Extensions/DateTimeHelper.cs b/Vampirewal.Core/Extensions/DateTimeHelper.cs deleted file mode 100644 index 00d464b537ef74d5b64d0c5d2bd5d4c3009735d9..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/Extensions/DateTimeHelper.cs +++ /dev/null @@ -1,98 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:DateTimeHelper -// 创 建 者:杨程 -// 创建时间:2021/9/15 11:31:19 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Vampirewal.Core.Extensions -{ - /// - /// DateTime Helper - /// - public static class DateTimeHelper - { - #region DateTime Helper - - public static int WeekOfYear(this DateTime self) - { - var startDayOfYear = new DateTime(self.Year, 1, 1); - var weekOffset = 7 - (startDayOfYear.DayOfWeek == DayOfWeek.Sunday ? 7 : (int)startDayOfYear.DayOfWeek) + 1; - var weekOfYear = (int)Math.Ceiling((self.DayOfYear - weekOffset) / 7.0 + (weekOffset == 0 ? 0 : 1)); - - return weekOfYear; - } - - /// - /// 获取 指定的一周所在年份 的开始及结束时间 - /// - /// 所在年份 - /// 周数 - /// 指定周开始时间 - /// 指定周结束时间 - public static void WeekDays(int yearNum, int weekOfYear, out DateTime startDay, out DateTime endDay) - { - var startDayOfYear = new DateTime(yearNum, 1, 1, 0, 0, 0); - - var weekOffset = 7 - (startDayOfYear.DayOfWeek == DayOfWeek.Sunday ? 7 : (int)startDayOfYear.DayOfWeek) + 1; - startDay = startDayOfYear.AddDays(7 * (weekOfYear - (weekOffset == 0 ? 0 : 1)) + weekOffset - 7); - endDay = startDay.AddDays(7); - } - - #endregion - - #region DateTime Extensions - - private static readonly DateTime _jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); - - /// - /// UTC 1970/01/01 00:00:00 - /// - public static DateTime Jan1st1970 => _jan1st1970; - - /// - /// 时间戳 ms - /// - /// - /// 返回标准时间戳 单位 毫秒 注:从 1970/01/01 00:00:00 开始 - public static long ToMilliseconds(this DateTime self) - { - return (long)(self.ToUniversalTime() - Jan1st1970).TotalMilliseconds; - } - - /// - /// 时间戳 microsecond - /// - /// - /// 返回标准时间戳 单位 微秒 注:从 1970/01/01 00:00:00 开始 - public static long ToMicroseconds(this DateTime self) - { - return (long)((self.ToUniversalTime() - Jan1st1970).TotalMilliseconds * 1000); - } - - /// - /// 获取当前时间所在周的开始及结束时间 - /// - /// - /// 指定周开始时间 - /// 指定周结束时间 - public static void WeekDays(this DateTime self, out DateTime startDay, out DateTime endDay) - { - WeekDays(self.Year, self.WeekOfYear(), out startDay, out endDay); - } - - #endregion - } -} diff --git a/Vampirewal.Core/Extensions/DomainExtensions.cs b/Vampirewal.Core/Extensions/DomainExtensions.cs deleted file mode 100644 index 73828cbf10e7438ef7264438158d9ff6851d5394..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/Extensions/DomainExtensions.cs +++ /dev/null @@ -1,377 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:DomainExtensions -// 创 建 者:杨程 -// 创建时间:2021/9/16 17:02:37 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Http; -using System.Text; -using System.Threading.Tasks; -using Microsoft.Extensions.DependencyInjection; -using Newtonsoft.Json; -using Vampirewal.Core.Models; - -namespace Vampirewal.Core.Extensions -{ - public static class DomainExtensions - { - public static async Task CallAPI(this FrameworkDomain self, string url, HttpMethodEnum method, HttpContent content, ErrorObj error = null, string errormsg = null, int? timeout = null, string proxy = null) - { - var serviceProvider = new ServiceCollection().AddHttpClient().BuildServiceProvider(); - //IHttpClientFactory _httpClientFactory = - - - var factory = serviceProvider.GetService(); - try - { - if (string.IsNullOrEmpty(url)) - { - return default(T); - } - //新建http请求 - var client = factory.CreateClient(self.Name); - //如果配置了代理,则使用代理 - //设置超时 - if (timeout.HasValue) - { - client.Timeout = new TimeSpan(0, 0, 0, timeout.Value, 0); - } - //填充表单数据 - HttpResponseMessage res = null; - switch (method) - { - case HttpMethodEnum.GET: - res = await client.GetAsync(url); - break; - case HttpMethodEnum.POST: - res = await client.PostAsync(url, content); - break; - case HttpMethodEnum.PUT: - res = await client.PutAsync(url, content); - break; - case HttpMethodEnum.DELETE: - res = await client.DeleteAsync(url); - break; - default: - break; - } - T rv = default(T); - if (res == null) - { - return rv; - } - if (res.IsSuccessStatusCode == true) - { - rv = JsonConvert.DeserializeObject(await res.Content.ReadAsStringAsync()); - } - else - { - if (res.StatusCode == System.Net.HttpStatusCode.BadRequest) - { - error = JsonConvert.DeserializeObject(await res.Content.ReadAsStringAsync()); - } - else - { - errormsg = await res.Content.ReadAsStringAsync(); - } - } - - return rv; - } - catch (Exception ex) - { - errormsg = ex.ToString(); - return default(T); - } - } - - /// - /// 使用Get方法调用api - /// - /// - /// - /// 调用地址 - /// 如果是框架识别的错误格式,将返回ErrorObj - /// 如果框架不识别错误格式,返回错误文本 - /// 超时时间,单位秒 - /// 代理地址 - /// - public static async Task CallAPI(this FrameworkDomain self, string url, ErrorObj error = null, string errormsg = null, int? timeout = null, string proxy = null) - { - HttpContent content = null; - //填充表单数据 - return await CallAPI(self, url, HttpMethodEnum.GET, content, error, errormsg, timeout, proxy); - } - - - /// - /// - /// - /// - /// - /// 调用地址 - /// 调用方式 - /// 提交字段 - /// 如果是框架识别的错误格式,将返回ErrorObj - /// 如果框架不识别错误格式,返回错误文本 - /// 超时时间,单位秒 - /// 代理地址 - /// - public static async Task CallAPI(this FrameworkDomain self, string url, HttpMethodEnum method, IDictionary postdata, ErrorObj error = null, string errormsg = null, int? timeout = null, string proxy = null) - { - HttpContent content = null; - //填充表单数据 - if (!(postdata == null || postdata.Count == 0)) - { - List> paras = new List>(); - foreach (string key in postdata.Keys) - { - paras.Add(new KeyValuePair(key, postdata[key])); - } - content = new FormUrlEncodedContent(paras); - } - return await CallAPI(self, url, method, content, error, errormsg, timeout, proxy); - } - - /// - /// - /// - /// - /// - /// 调用地址 - /// 调用方式 - /// 提交的object,会被转成json提交 - /// 如果是框架识别的错误格式,将返回ErrorObj - /// 如果框架不识别错误格式,返回错误文本 - /// 超时时间,单位秒 - /// 代理地址 - /// - public static async Task CallAPI(this FrameworkDomain self, string url, HttpMethodEnum method, object postdata, ErrorObj error = null, string errormsg = null, int? timeout = null, string proxy = null) - { - HttpContent content = new StringContent(JsonConvert.SerializeObject(postdata), System.Text.Encoding.UTF8, "application/json"); - return await CallAPI(self, url, method, content, error, errormsg, timeout, proxy); - } - - - - - public static async Task CallAPI(this FrameworkDomain self, string url, HttpMethodEnum method, HttpContent content, ErrorObj error = null, string errormsg = null, int? timeout = null, string proxy = null) - { - var serviceProvider = new ServiceCollection().AddHttpClient().BuildServiceProvider(); - //IHttpClientFactory _httpClientFactory = - - - var factory = serviceProvider.GetService(); - try - { - if (string.IsNullOrEmpty(url)) - { - return ""; - } - //新建http请求 - var client = factory.CreateClient(self.Name); - //如果配置了代理,则使用代理 - //设置超时 - if (timeout.HasValue) - { - client.Timeout = new TimeSpan(0, 0, 0, timeout.Value, 0); - } - //填充表单数据 - HttpResponseMessage res = null; - switch (method) - { - case HttpMethodEnum.GET: - res = await client.GetAsync(url); - break; - case HttpMethodEnum.POST: - res = await client.PostAsync(url, content); - break; - case HttpMethodEnum.PUT: - res = await client.PutAsync(url, content); - break; - case HttpMethodEnum.DELETE: - res = await client.DeleteAsync(url); - break; - default: - break; - } - string rv = ""; - if (res == null) - { - return rv; - } - if (res.IsSuccessStatusCode == true) - { - rv = await res.Content.ReadAsStringAsync(); - } - else - { - if (res.StatusCode == System.Net.HttpStatusCode.BadRequest) - { - error = JsonConvert.DeserializeObject(await res.Content.ReadAsStringAsync()); - } - else - { - errormsg = await res.Content.ReadAsStringAsync(); - } - } - - return rv; - } - catch (Exception ex) - { - errormsg = ex.ToString(); - return ""; - } - } - - /// - /// 使用Get方法调用api - /// - /// - /// - /// 调用地址 - /// 如果是框架识别的错误格式,将返回ErrorObj - /// 如果框架不识别错误格式,返回错误文本 - /// 超时时间,单位秒 - /// 代理地址 - /// - public static async Task CallAPI(this FrameworkDomain self, string url, ErrorObj error = null, string errormsg = null, int? timeout = null, string proxy = null) - { - HttpContent content = null; - //填充表单数据 - return await CallAPI(self, url, HttpMethodEnum.GET, content, error, errormsg, timeout, proxy); - } - - - /// - /// - /// - /// - /// - /// 调用地址 - /// 调用方式 - /// 提交字段 - /// 如果是框架识别的错误格式,将返回ErrorObj - /// 如果框架不识别错误格式,返回错误文本 - /// 超时时间,单位秒 - /// 代理地址 - /// - public static async Task CallAPI(this FrameworkDomain self, string url, HttpMethodEnum method, IDictionary postdata, ErrorObj error = null, string errormsg = null, int? timeout = null, string proxy = null) - { - HttpContent content = null; - //填充表单数据 - if (!(postdata == null || postdata.Count == 0)) - { - List> paras = new List>(); - foreach (string key in postdata.Keys) - { - paras.Add(new KeyValuePair(key, postdata[key])); - } - content = new FormUrlEncodedContent(paras); - } - return await CallAPI(self, url, method, content, error, errormsg, timeout, proxy); - } - - /// - /// - /// - /// - /// - /// 调用地址 - /// 调用方式 - /// 提交的object,会被转成json提交 - /// 如果是框架识别的错误格式,将返回ErrorObj - /// 如果框架不识别错误格式,返回错误文本 - /// 超时时间,单位秒 - /// 代理地址 - /// - public static async Task CallAPI(this FrameworkDomain self, string url, HttpMethodEnum method, object postdata, ErrorObj error = null, string errormsg = null, int? timeout = null, string proxy = null) - { - HttpContent content = new StringContent(JsonConvert.SerializeObject(postdata), System.Text.Encoding.UTF8, "application/json"); - return await CallAPI(self, url, method, content, error, errormsg, timeout, proxy); - } - - public static async Task CallStreamAPI(this FrameworkDomain self, string url, HttpMethodEnum method, object postdata, ErrorObj error = null, string errormsg = null, int? timeout = null, string proxy = null) - { - HttpContent content = new StringContent(JsonConvert.SerializeObject(postdata), System.Text.Encoding.UTF8, "application/json"); - var serviceProvider = new ServiceCollection().AddHttpClient().BuildServiceProvider(); - //IHttpClientFactory _httpClientFactory = - - - var factory = serviceProvider.GetService(); - try - { - if (string.IsNullOrEmpty(url)) - { - return null; - } - //新建http请求 - var client = factory.CreateClient(self.Name); - //如果配置了代理,则使用代理 - //设置超时 - if (timeout.HasValue) - { - client.Timeout = new TimeSpan(0, 0, 0, timeout.Value, 0); - } - //填充表单数据 - HttpResponseMessage res = null; - switch (method) - { - case HttpMethodEnum.GET: - res = await client.GetAsync(url); - break; - case HttpMethodEnum.POST: - res = await client.PostAsync(url, content); - break; - case HttpMethodEnum.PUT: - res = await client.PutAsync(url, content); - break; - case HttpMethodEnum.DELETE: - res = await client.DeleteAsync(url); - break; - default: - break; - } - byte[] rv = null; - if (res == null) - { - return rv; - } - if (res.IsSuccessStatusCode == true) - { - rv = await res.Content.ReadAsByteArrayAsync(); - } - else - { - if (res.StatusCode == System.Net.HttpStatusCode.BadRequest) - { - error = JsonConvert.DeserializeObject(await res.Content.ReadAsStringAsync()); - } - else - { - errormsg = await res.Content.ReadAsStringAsync(); - } - } - - return rv; - } - catch (Exception ex) - { - errormsg = ex.ToString(); - return null; - } - - } - } -} diff --git a/Vampirewal.Core/Extensions/EntityExtension.cs b/Vampirewal.Core/Extensions/EntityExtension.cs index 1dfc1f07aaf681575dccfa978fc6baeae9c2af0b..642cfe13785bc7802412c64f9a5e15e5b34ac0f6 100644 --- a/Vampirewal.Core/Extensions/EntityExtension.cs +++ b/Vampirewal.Core/Extensions/EntityExtension.cs @@ -11,32 +11,58 @@ //----------------------------------------------------------------*/ #endregion -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using Newtonsoft.Json; -using Vampirewal.Core.Models; - -namespace Vampirewal.Core.Extensions + + + +namespace Vampirewal.Core.Extensions; + +/// +/// 实体类扩展 +/// +public static class EntityExtension { + + /// - /// 实体类扩展 + /// 简单映射 /// - public static class EntityExtension + /// 目标类型 + /// + /// + public static TTarget SimpleMap(this object source) { - public static void test(this T entity) where T:TopBaseModel - { - Type type = typeof(T); - - var CustomAttributes= type.GetCustomAttributes().ToList(); + var result = Activator.CreateInstance(typeof(TTarget)); + var SourceProps = source.GetType().GetProperties(); + var TargetProps = typeof(TTarget).GetProperties(); + foreach (var prop1 in SourceProps) + { + foreach (var prop2 in TargetProps) + { + if (prop2.PropertyType.IsValueType || prop2.PropertyType.Name.StartsWith("String")) + { + if (prop1.Name == prop2.Name) + { + try + { + object value = prop1.GetValue(source, null); + var prop = typeof(TTarget).GetProperty(prop1.Name); + if (prop != null && prop.CanWrite && !(value is DBNull)) + { + prop.SetValue(result, value, null); + } + } + catch (Exception ex) + { - type.GetAllProperties().ForEach(f => { f.GetCustomAttribute(typeof(RequiredAttribute)); }); + throw ex; + } + } + } + } } + + return (TTarget)result; } } diff --git a/Vampirewal.Core/Extensions/ITreeDataExtension.cs b/Vampirewal.Core/Extensions/ITreeDataExtension.cs deleted file mode 100644 index d435bfe95ee15e74d5d13d738f5bc030b6a90f62..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/Extensions/ITreeDataExtension.cs +++ /dev/null @@ -1,175 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:ITreeDataExtension -// 创 建 者:杨程 -// 创建时间:2021/9/16 17:11:10 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Vampirewal.Core.Interface; -using Vampirewal.Core.Models; - -namespace Vampirewal.Core.Extensions -{ - /// - /// 树形结构Model的扩展函数 - /// - public static class ITreeDataExtension - { - /// - /// 获取一个父节点下的所有子节点,包括子节点的子节点 - /// - /// 树形结构类 - /// 树形结构实例 - /// 排序字段,可为空 - /// 树形结构列表,包含所有子节点 - public static List GetAllChildren(this T self, Func order = null) where T : TopBaseModel, ITreeData - { - List rv = new List(); - var children = self.Children; - if (order != null && children != null) - { - children = children.OrderBy(order).ToList(); - } - if (children != null && children.Count() > 0) - { - var dictinct = children.Where(x => x.ID != self.ID).ToList(); - foreach (var item in dictinct) - { - rv.Add(item); - //递归添加子节点的子节点 - rv.AddRange(item.GetAllChildren(order)); - } - } - return rv; - } - - public static int GetLevel(this T self) - where T : TopBaseModel, ITreeData - { - int level = 0; - while (self.Parent != null) - { - level++; - self = self.Parent; - } - return level; - } - - /// - /// 查询数据库,根据某个节点ID递归获取其下所有级别的子节点ID - /// - /// 树形结构类 - /// 树形结构实例 - /// dc - /// 子节点ID列表 - /// 所有级别子节点ID - public static List GetAllChildrenIDs(this T self - , IDataContext dc - , List subids = null) - where T : TopBaseModel, ITreeData - { - List rv = new List(); - List ids = null; - if (subids == null) - { - ids = dc.Set().Where(x => x.ParentId.ToString() == self.ID).Select(x => new Guid(x.ID)).ToList(); - } - else - { - ids = dc.Set().Where(x => subids.Contains(x.ParentId.Value)).Select(x => new Guid(x.ID)).ToList(); - } - if (ids != null && ids.Count > 0) - { - rv.AddRange(ids); - rv.AddRange(self.GetAllChildrenIDs(dc, ids)); - } - return rv; - } - - /// - /// 将树形结构列表转变为标准列表 - /// - /// 树形结构类 - /// 树形结构实例 - /// 排序字段,可以为空 - /// 返回标准列表,所有节点都在同一级上 - public static List FlatTree(this List self, Func order = null) - where T : TopBaseModel, ITreeData - { - List rv = new List(); - if (order != null) - { - self = self.OrderBy(order).ToList(); - } - foreach (var item in self) - { - rv.Add(item); - rv.AddRange(item.GetAllChildren(order)); - } - return rv; - } - - /// - /// 将树形结构列表转变为标准列表 - /// - /// 树形结构实例 - /// 排序字段,可以为空 - /// 返回标准列表,所有节点都在同一级上 - //public static List FlatTreeSelectList(this List self, Func order = null) - //{ - // List rv = new List(); - // if (order != null) - // { - // self = self.OrderBy(order).ToList(); - // } - // foreach (var item in self) - // { - // rv.Add(item); - // if (item.Children != null) - // { - // rv.AddRange(item.GetTreeSelectChildren(order)); - // } - // } - // return rv; - //} - - /// - /// 获取TreeSelect节点下所有子节点 - /// - /// - /// - /// - //public static List GetTreeSelectChildren(this TreeSelectListItem self, Func order = null) - //{ - // List rv = new List(); - // var children = self.Children; - // if (order != null && children != null) - // { - // children = children.OrderBy(order).ToList(); - // } - // if (children != null && children.Count() > 0) - // { - // var dictinct = children.Where(x => x.Id != self.Id).ToList(); - // foreach (var item in dictinct) - // { - // rv.Add(item); - // //递归添加子节点的子节点 - // rv.AddRange(item.GetTreeSelectChildren(order)); - // } - // } - // return rv; - //} - - } -} diff --git a/Vampirewal.Core/Extensions/StringExtension.cs b/Vampirewal.Core/Extensions/StringExtension.cs index 7cfdda428f3a89ba5bb28a94a84be4caad93f511..76de171588227b3b71b1c68c0c0e45e6c5cb77c4 100644 --- a/Vampirewal.Core/Extensions/StringExtension.cs +++ b/Vampirewal.Core/Extensions/StringExtension.cs @@ -11,162 +11,166 @@ //----------------------------------------------------------------*/ #endregion -using System; -using System.Collections; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Linq; -using System.Linq.Expressions; -using System.Text; -using System.Threading.Tasks; -namespace Vampirewal.Core.Extensions + + +namespace Vampirewal.Core.Extensions; + +/// +/// 字符串辅助类 +/// +public static class StringExtension { /// - /// 字符串辅助类 + /// 根据名字获取Id形式 + /// + /// 名字 + /// 将[].转换成_形式的Id + public static string GetIdByName(this string fieldName) + { + return fieldName == null ? "" : fieldName.Replace(".", "_").Replace("[", "_").Replace("]", "_"); + } + + /// + /// 格式化URL /// - public static class StringExtension + /// 初始url + /// 格式化后的url + public static string CorrectUrl(this string url) { - /// - /// 根据名字获取Id形式 - /// - /// 名字 - /// 将[].转换成_形式的Id - public static string GetIdByName(this string fieldName) + if (string.IsNullOrWhiteSpace(url) == true) { - return fieldName == null ? "" : fieldName.Replace(".", "_").Replace("[", "_").Replace("]", "_"); + url = ""; } - - /// - /// 格式化URL - /// - /// 初始url - /// 格式化后的url - public static string CorrectUrl(this string url) + else { - if (string.IsNullOrWhiteSpace(url) == true) + url = url.ToLower(); + url = url.Trim('/', '\\'); + if (url.StartsWith("http://") == false && url.StartsWith("https://") == false) { - url = ""; + url = "http://" + url; } - else - { - url = url.ToLower(); - url = url.Trim('/', '\\'); - if (url.StartsWith("http://") == false && url.StartsWith("https://") == false) - { - url = "http://" + url; - } - } - return url; } - /// - /// 将数据列表转化为逗号分隔的字符串 - /// - /// 源数据类 - /// 文本字段 - /// 源数据List - /// 要拼接的文本字段 - /// 转化文本字段的表达式 - /// 分隔符,默认为逗号 - /// 转化后的字符串 - public static string ToSpratedString(this IEnumerable self, Expression> textField, Func Format = null, string seperator = ",") + return url; + } + /// + /// 将数据列表转化为逗号分隔的字符串 + /// + /// 源数据类 + /// 文本字段 + /// 源数据List + /// 要拼接的文本字段 + /// 转化文本字段的表达式 + /// 分隔符,默认为逗号 + /// 转化后的字符串 + public static string ToSpratedString(this IEnumerable self, Expression> textField, Func Format = null, string seperator = ",") + { + string rv = ""; + if (self == null) { - string rv = ""; - if (self == null) - { - return rv; - } - //循环所有数据 - for (int i = 0; i < self.Count(); i++) - { - //获取文本字段的值 - V text = textField.Compile().Invoke(self.ElementAt(i)); - string str = ""; - //如果有转换函数,则调用获取转换后的字符串 - if (Format == null) - { - if (text == null) - { - str = ""; - } - else - { - str = text.ToString(); - } - } - else - { - str = Format.Invoke(text); - } - rv += str; - //拼接分隔符 - if (i < self.Count() - 1) - { - rv += seperator; - } - } - //返回转化后的字符串 return rv; } - - public static string ToSpratedString(this IEnumerable self, Func Format = null, string seperator = ",") + //循环所有数据 + for (int i = 0; i < self.Count(); i++) { - string rv = ""; - if (self == null) + //获取文本字段的值 + V text = textField.Compile().Invoke(self.ElementAt(i)); + string str = ""; + //如果有转换函数,则调用获取转换后的字符串 + if (Format == null) { - return rv; - } - foreach (var item in self) - { - if (Format == null) + if (text == null) { - rv += item.ToString() + seperator; + str = ""; } else { - rv += Format.Invoke(item) + seperator; + str = text.ToString(); } } - if (rv.Length > 0) + else { - rv = rv.Substring(0, rv.Length - 1); + str = Format.Invoke(text); + } + rv += str; + //拼接分隔符 + if (i < self.Count() - 1) + { + rv += seperator; } - return rv; } + //返回转化后的字符串 + return rv; + } - public static string ToSpratedString(this NameValueCollection self, string seperator = ",") + public static string ToSpratedString(this IEnumerable self, Func Format = null, string seperator = ",") + { + string rv = ""; + if (self == null) { - string rv = ""; - if (self == null) - { - return rv; - } - foreach (var item in self) - { - rv += item.ToString() + "=" + self[item.ToString()] + seperator; - } - if (rv.Length > 0) - { - rv = rv.Substring(0, rv.Length - 1); - } return rv; } - - public static string AppendQuery(this string self, string query) + foreach (var item in self) { - if (self == null) - { - return null; - } - if (self.Contains("?")) + if (Format == null) { - self += "&" + query; + rv += item.ToString() + seperator; } else { - self += "?" + query; + rv += Format.Invoke(item) + seperator; } - return self; } + if (rv.Length > 0) + { + rv = rv.Substring(0, rv.Length - 1); + } + return rv; + } + + public static string ToSpratedString(this NameValueCollection self, string seperator = ",") + { + string rv = ""; + if (self == null) + { + return rv; + } + foreach (var item in self) + { + rv += item.ToString() + "=" + self[item.ToString()] + seperator; + } + if (rv.Length > 0) + { + rv = rv.Substring(0, rv.Length - 1); + } + return rv; + } + + public static string AppendQuery(this string self, string query) + { + if (self == null) + { + return null; + } + if (self.Contains("?")) + { + self += "&" + query; + } + else + { + self += "?" + query; + } + return self; + } + + /// + /// 直接Json转Entity + /// + /// + /// + /// + public static T JsonToEntity(this string self) + { + return JsonConvert.DeserializeObject(self); } } diff --git a/Vampirewal.Core/Extensions/TypeExtension.cs b/Vampirewal.Core/Extensions/TypeExtension.cs deleted file mode 100644 index 3a98b1c5f136466e731ea8b4ff45eeabfa616a09..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/Extensions/TypeExtension.cs +++ /dev/null @@ -1,368 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:TypeExtension -// 创 建 者:杨程 -// 创建时间:2021/9/15 10:59:48 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.ComponentModel.DataAnnotations.Schema; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using Vampirewal.Core.Models; - -namespace Vampirewal.Core.Extensions -{ - /// - /// Type的扩展函数 - /// - public static class TypeExtension - { - public static ImmutableDictionary> _propertyCache { get; set; } = new Dictionary>().ToImmutableDictionary(); - /// - /// 判断是否是泛型 - /// - /// Type类 - /// 泛型类型 - /// 判断结果 - public static bool IsGeneric(this Type self, Type innerType) - { - if (self.GetTypeInfo().IsGenericType && self.GetGenericTypeDefinition() == innerType) - { - return true; - } - else - { - return false; - } - } - - /// - /// 判断是否为Nullable<>类型 - /// - /// Type类 - /// 判断结果 - public static bool IsNullable(this Type self) - { - return self.IsGeneric(typeof(Nullable<>)); - } - - /// - /// 判断是否为List<>类型 - /// - /// Type类 - /// 判断结果 - public static bool IsList(this Type self) - { - return self.IsGeneric(typeof(List<>)) || self.IsGeneric(typeof(IEnumerable<>)); - } - - /// - /// 判断是否为List<>类型 - /// - /// Type类 - /// 判断结果 - public static bool IsListOf(this Type self) - { - if (self.IsGeneric(typeof(List<>)) && typeof(T).IsAssignableFrom(self.GenericTypeArguments[0])) - { - return true; - } - else - { - return false; - } - } - - - #region 判断是否为枚举 - - /// - /// 判断是否为枚举 - /// - /// Type类 - /// 判断结果 - public static bool IsEnum(this Type self) - { - return self.GetTypeInfo().IsEnum; - } - - /// - /// 判断是否为枚举或者可空枚举 - /// - /// - /// - public static bool IsEnumOrNullableEnum(this Type self) - { - if (self == null) - { - return false; - } - if (self.IsEnum) - { - return true; - } - else - { - if (self.IsGenericType && self.GetGenericTypeDefinition() == typeof(Nullable<>) && self.GetGenericArguments()[0].IsEnum) - { - return true; - } - else - { - return false; - } - } - } - - #endregion - - /// - /// 判断是否为值类型 - /// - /// Type类 - /// 判断结果 - public static bool IsPrimitive(this Type self) - { - return self.GetTypeInfo().IsPrimitive || self == typeof(decimal); - } - - public static bool IsNumber(this Type self) - { - Type checktype = self; - if (self.IsNullable()) - { - checktype = self.GetGenericArguments()[0]; - } - if (checktype == typeof(int) || checktype == typeof(short) || checktype == typeof(long) || checktype == typeof(float) || checktype == typeof(decimal) || checktype == typeof(double)) - { - return true; - } - else - { - return false; - } - } - - - #region 判断是否是Bool - - public static bool IsBool(this Type self) - { - return self == typeof(bool); - } - - /// - /// 判断是否是 bool or bool?类型 - /// - /// - /// - public static bool IsBoolOrNullableBool(this Type self) - { - if (self == null) - { - return false; - } - if (self == typeof(bool) || self == typeof(bool?)) - { - return true; - } - else - { - return false; - } - } - - #endregion - - public static Dictionary GetRandomValues(this Type self) - { - Dictionary rv = new Dictionary(); - string pat = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"; - var pros = self.GetAllProperties(); - List skipFields = new List() - { - - }; - if (typeof(IBaseModel).IsAssignableFrom(self)) - { - skipFields.AddRange( - new string[]{ - //nameof(IBaseModel.CreateBy), - //nameof(IBaseModel.CreateTime), - nameof(IBaseModel.UpdateBy), - nameof(IBaseModel.UpdateTime) } - ); - } - - foreach (var pro in pros) - { - string key = pro.Name; - string val = ""; - var notmapped = pro.GetCustomAttribute(); - if (notmapped == null && - pro.PropertyType.IsList() == false && - pro.PropertyType.IsSubclassOf(typeof(TopBaseModel)) == false && - skipFields.Contains(key) == false - ) - { - if (pro.PropertyType.IsNumber()) - { - var range = pro.GetCustomAttribute(); - int start = 0; - int end = 100; - if (range != null) - { - try - { - start = (int)Math.Truncate(double.Parse(range.Minimum.ToString())); - end = (int)Math.Truncate(double.Parse(range.Maximum.ToString())); - } - catch { } - } - Random r = new Random(); - val = r.Next(start, end).ToString(); - } - else if (pro.PropertyType.IsBoolOrNullableBool()) - { - List boolvalues = new List { "true", "false" }; - if (pro.PropertyType.IsNullable()) - { - boolvalues.Add("null"); - } - Random r = new Random(); - var index = r.Next(0, boolvalues.Count); - val = boolvalues[index]; - } - else if (pro.PropertyType.IsEnumOrNullableEnum()) - { - List enumvalues = new List(); - Type enumtype = null; - if (pro.PropertyType.IsNullable()) - { - enumtype = pro.PropertyType.GenericTypeArguments[0]; - enumvalues.Add("null"); - } - else - { - enumtype = pro.PropertyType; - } - var vs = Enum.GetValues(enumtype); - Random r = new Random(); - var index = r.Next(0, vs.Length); - val = enumtype.FullName + "." + vs.GetValue(index).ToString(); - } - else if (pro.PropertyType == typeof(string)) - { - var length = pro.GetCustomAttribute(); - var min = 1; - var max = 20; - var l = 0; - if (length != null) - { - if (length.MaximumLength > 0) - { - max = length.MaximumLength; - } - if (length.MinimumLength > 0) - { - min = length.MinimumLength; - } - } - if (min == max) - { - l = max; - } - else if (min < max) - { - l = new Random().Next(min, max); - } - Random r = new Random(); - for (int i = 0; i < l; i++) - { - int index = r.Next(pat.Length); - val += pat[index]; - } - val = "\"" + val + "\""; - } - else if (pro.PropertyType == typeof(DateTime) || pro.PropertyType == typeof(DateTime?)) - { - Random r = new Random(); - val = DateTime.Now.AddDays(r.Next(-500, 500)).ToString("yyyy-MM-dd HH:mm:ss"); - val = $"DateTime.Parse(\"{val}\")"; - } - if (pros.Where(x => x.Name.ToLower() + "id" == key.ToLower()).Any()) - { - val = "$fk$"; - } - if (val != "") - { - if (rv.ContainsKey(key) == false) - { - rv.Add(key, val); - } - } - } - } - return rv; - } - - - - - public static PropertyInfo GetSingleProperty(this Type self, string name) - { - if (_propertyCache.ContainsKey(self.FullName) == false) - { - var properties = self.GetProperties().ToList(); - _propertyCache = _propertyCache.Add(self.FullName, properties); - return properties.Where(x => x.Name == name).FirstOrDefault(); - } - else - { - return _propertyCache[self.FullName].Where(x => x.Name == name).FirstOrDefault(); - } - } - - public static PropertyInfo GetSingleProperty(this Type self, Func where) - { - if (_propertyCache.ContainsKey(self.FullName) == false) - { - var properties = self.GetProperties().ToList(); - _propertyCache = _propertyCache.Add(self.FullName, properties); - return properties.Where(where).FirstOrDefault(); - } - else - { - return _propertyCache[self.FullName].Where(where).FirstOrDefault(); - } - } - - public static List GetAllProperties(this Type self) - { - if (_propertyCache.ContainsKey(self.FullName) == false) - { - var properties = self.GetProperties().ToList(); - _propertyCache = _propertyCache.Add(self.FullName, properties); - return properties; - } - else - { - return _propertyCache[self.FullName]; - } - } - - } -} diff --git a/Vampirewal.Core/Extensions/VampirewalCoreConfigExtension.cs b/Vampirewal.Core/Extensions/VampirewalCoreConfigExtension.cs new file mode 100644 index 0000000000000000000000000000000000000000..6cc85ac6c67edd44c41f76ec7756f576fc338cd1 --- /dev/null +++ b/Vampirewal.Core/Extensions/VampirewalCoreConfigExtension.cs @@ -0,0 +1,66 @@ +#region 文件信息 + +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: VampirewalCoreConfigExtension +// 创建者: 杨程 +// 创建日期: 2023/1/29 9:57:26 + +//----------------------------------------------------------------*/ + +#endregion + +namespace Vampirewal.Core.Extensions; + +/// +/// VampirewalCoreConfig扩展 +/// +public static class VampirewalCoreConfigExtension +{ + /// + /// 将VampirewalCoreConfig添加到IOC容器(务必添加到最前面) + /// 已内置基础配置项,请添加自定义的内容即可 + /// 使用options.RegisterOptions + /// + /// + /// 配置文件路径 + /// 配置项 + public static void AddVampirewalCoreConfig(this IServiceCollection Service, string ConfigPath, Action> Options) + { + VampirewalCoreConfig config = new VampirewalCoreConfig(ConfigPath); + + #region 添加内置配置项 + + config.OptionsList.Add(new AppBaseOptions()); + config.OptionsList.Add(new DbBaseOptions()); + config.OptionsList.Add(new PagingOptions()); + + #endregion + + Options?.Invoke(config.OptionsList); + + config.LoadConfig(); + + Service.AddSingleton(config); + } + + /// + /// 将配置项注册进VampirewalCoreConfig中 + /// + /// + /// + /// + public static void RegisterOptions(this List Source) where T : IOptions, new() + { + T t = new T(); + + if (!Source.Any(a => a.GetType() == t.GetType())) + Source.Add(t); + else + throw new Exception("集合中已经注册了该类型的配置项!"); + } +} \ No newline at end of file diff --git a/Vampirewal.Core/Extensions/VampirewalCoreDataContextExtension.cs b/Vampirewal.Core/Extensions/VampirewalCoreDataContextExtension.cs new file mode 100644 index 0000000000000000000000000000000000000000..79b1b5d55d88932c9547859e60bf378bab0c15d7 --- /dev/null +++ b/Vampirewal.Core/Extensions/VampirewalCoreDataContextExtension.cs @@ -0,0 +1,141 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: VampirewalCoreDataContextExtension +// 创建者: 杨程 +// 创建日期: 2023/2/20 19:07:10 + +//----------------------------------------------------------------*/ +#endregion + + + +namespace Vampirewal.Core.Extensions; + +/// +/// VampirewalCoreDataContext扩展项 +/// +public static class VampirewalCoreDataContextExtension +{ + /// + /// 使用SqlSugar作为数据源 + /// + /// + /// + public static void UseVampirewalCoreSqlSugar(this IServiceCollection services, IVampirewalCoreSqlSugar SqlSugarSetup) + { + var DbOptions = VampirewalCoreContext.GetInstance().GetContext("DbBaseOptions").JsonToEntity(); + + var dbConnectConfigList = new List(); + + foreach (var item in DbOptions.ConnectionStrings ?? new List()) + { + string connStr = item.Value; + + if (item.DbType == DBTypeEnum.Sqlite) + { + var strs = connStr.Split('='); + + connStr = $"{strs[0]}={AppDomain.CurrentDomain.BaseDirectory}{strs[1]}"; + } + + dbConnectConfigList.Add(SqlSugarSetup.GetDbConnectionConfig(item.Key, connStr, item.DbType)); + + } + + SqlSugarScope client = new SqlSugarScope(dbConnectConfigList, db => + { + foreach (var item in DbOptions.ConnectionStrings) + { + //SQL执行完 + db.GetConnection(item.Key).Aop.OnLogExecuted = SqlSugarSetup.OnLogExecuted; + //SQL执行前 + db.GetConnection(item.Key).Aop.OnLogExecuting = SqlSugarSetup.OnLogExecuting; + + //SQL报错 + db.GetConnection(item.Key).Aop.OnError = SqlSugarSetup.OnError; + + //可以修改SQL和参数的值 + db.GetConnection(item.Key).Aop.OnExecutingChangeSql = SqlSugarSetup.OnExecutingChangeSql; + + db.GetConnection(item.Key).Aop.DataExecuting = SqlSugarSetup.DataExecuting; + db.GetConnection(item.Key).Aop.DataExecuted = SqlSugarSetup.DataExecuted; + } + + }); + SqlSugarSetup.SetClient(client); + + client.DbMaintenance.CreateDatabase(); + SqlSugarSetup.CodeFirst(); + SqlSugarSetup.InitData(); + + services.AddSingleton(client); + + } + + /// + /// 使用SqlSugar作为数据源 + /// + /// + /// + public static void UseVampirewalCoreSqlSugar(this IServiceCollection services) where SqlSugarSetup: IVampirewalCoreSqlSugar + { + Type SetupType = typeof(SqlSugarSetup); + + var Setup= (IVampirewalCoreSqlSugar)Activator.CreateInstance(SetupType); + + var DbOptions = VampirewalCoreContext.GetInstance().GetContext("DbBaseOptions").JsonToEntity(); + + var dbConnectConfigList = new List(); + + foreach (var item in DbOptions.ConnectionStrings ?? new List()) + { + string connStr = item.Value; + + if (item.DbType == DBTypeEnum.Sqlite) + { + var strs = connStr.Split('='); + + connStr = $"{strs[0]}={AppDomain.CurrentDomain.BaseDirectory}{strs[1]}"; + } + + dbConnectConfigList.Add(Setup.GetDbConnectionConfig(item.Key, connStr, item.DbType)); + + } + + SqlSugarScope client = new SqlSugarScope(dbConnectConfigList, db => + { + foreach (var item in DbOptions.ConnectionStrings) + { + //SQL执行完 + db.GetConnection(item.Key).Aop.OnLogExecuted = Setup.OnLogExecuted; + //SQL执行前 + db.GetConnection(item.Key).Aop.OnLogExecuting = Setup.OnLogExecuting; + + //SQL报错 + db.GetConnection(item.Key).Aop.OnError = Setup.OnError; + + //可以修改SQL和参数的值 + db.GetConnection(item.Key).Aop.OnExecutingChangeSql = Setup.OnExecutingChangeSql; + + db.GetConnection(item.Key).Aop.DataExecuting = Setup.DataExecuting; + db.GetConnection(item.Key).Aop.DataExecuted = Setup.DataExecuted; + } + + }); + Setup.SetClient(client); + + + client.DbMaintenance.CreateDatabase(); + Setup.CodeFirst(); + Setup.InitData(); + + services.AddSingleton(client); + + } +} diff --git a/Vampirewal.Core/Helper/EntityHelper.cs b/Vampirewal.Core/Helper/EntityHelper.cs deleted file mode 100644 index b5707611aba13c5ab533876cef52cc59269e3d32..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/Helper/EntityHelper.cs +++ /dev/null @@ -1,180 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:EntityHelper -// 创 建 者:杨程 -// 创建时间:2021/9/15 11:44:08 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using System.Reflection; -using Vampirewal.Core.Extensions; -using Vampirewal.Core.Support; - -namespace Vampirewal.Core.Helper -{ - /// - /// DataTable和Entity之间转换的辅助类 - /// - public static class EntityHelper - { - /// - /// 根据DataTable获取Entity列表 - /// - /// Entity类型 - /// DataTable - /// Entity列表 - public static IList GetEntityList(DataTable table) - { - IList entityList = new List(); - - if (typeof(T) == typeof(DynamicData)) - { - foreach (DataRow row in table.Rows) - { - //新建Entity - T entity = (T)Activator.CreateInstance(typeof(T)); - foreach (DataColumn col in table.Columns) - { - (entity as DynamicData).Add(col.ColumnName, row[col] == DBNull.Value ? null : row[col]); - } - entityList.Add(entity); - } - } - else - { - var properties = typeof(T).GetAllProperties().ToLookup(property => property.Name, property => property).ToDictionary(i => i.Key, i => i.First()).Values; - - //循环Datable中的每一行 - foreach (DataRow row in table.Rows) - { - //新建Entity - T entity = (T)Activator.CreateInstance(typeof(T)); - //循环Entity的每一个属性 - foreach (var item in properties) - { - //如果DataTable中有列名和属性名一致,则把单元格内容赋值给Entity的该属性 - if (row.Table.Columns.Contains(item.Name)) - { - //判断null值 - if (string.IsNullOrEmpty(row[item.Name].ToString())) - { - item.SetValue(entity, null); - } - else - { - var ptype = item.PropertyType; - if (ptype.IsNullable()) - { - ptype = ptype.GenericTypeArguments[0]; - } - //如果是Guid或Guid?类型 - if (ptype == typeof(Guid)) - { - item.SetValue(entity, Guid.Parse(row[item.Name].ToString())); - } - //如果是enum或enum?类型 - else if (ptype.IsEnum) - { - item.SetValue(entity, Enum.ToObject(ptype, row[item.Name])); - } - else - { - item.SetValue(entity, Convert.ChangeType(row[item.Name], ptype)); - } - - } - } - } - entityList.Add(entity); - } - } - return entityList; - } - - #region 实体类转换成DataTable - - /// - /// 实体类转换成DataSet - /// - /// 实体类列表 - /// DataSet - public static DataSet ToDataSet(List modelList) where T : new() - { - if (modelList == null || modelList.Count == 0) - { - return null; - } - else - { - DataSet ds = new DataSet(); - ds.Tables.Add(ToDataTable(modelList)); - return ds; - } - } - - /// - /// 实体类转换成DataTable - /// - /// 实体类列表 - /// DataTable - public static DataTable ToDataTable(List modelList) where T : new() - { - if (modelList == null || modelList.Count == 0) - { - return null; - } - DataTable dt = CreateData(modelList[0]); - - foreach (T model in modelList) - { - DataRow dataRow = dt.NewRow(); - //循环实体类所有属性,给对应的DataTable字段赋值 - foreach (PropertyInfo propertyInfo in typeof(T).GetAllProperties()) - { - var res = propertyInfo.GetValue(model); - dataRow[propertyInfo.Name] = res ?? DBNull.Value; - } - dt.Rows.Add(dataRow); - } - return dt; - } - - /// - /// 根据实体类得到表结构 - /// - /// 实体类 - /// DataTable - private static DataTable CreateData(T model) where T : new() - { - DataTable dataTable = new DataTable(typeof(T).Name); - foreach (PropertyInfo propertyInfo in typeof(T).GetAllProperties()) - { - if (propertyInfo.PropertyType.IsGenericType) - { - if (propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>) && propertyInfo.PropertyType.GenericTypeArguments.Length > 0) - { - dataTable.Columns.Add(propertyInfo.Name, propertyInfo.PropertyType.GenericTypeArguments[0]); - continue; - } - else - { - continue; - } - } - dataTable.Columns.Add(propertyInfo.Name, propertyInfo.PropertyType); - } - return dataTable; - } - - #endregion - } -} diff --git a/Vampirewal.Core/Helper/PropertyHelper.cs b/Vampirewal.Core/Helper/PropertyHelper.cs deleted file mode 100644 index ac5305ca22b57e7ed7e1d49ecae8faee37bc541e..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/Helper/PropertyHelper.cs +++ /dev/null @@ -1,761 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:PropertyHelper -// 创 建 者:杨程 -// 创建时间:2021/9/15 11:42:34 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using Microsoft.Extensions.Primitives; -using System.Windows.Controls; -using Vampirewal.Core.Extensions; -using Microsoft.Extensions.Localization; - -namespace Vampirewal.Core.Helper -{ - /// - /// 属性辅助类 - /// - public static class PropertyHelper - { - - public static Func GetPropertyExpression(Type objtype, string property) - { - property = Regex.Replace(property, @"\[[^\]]*\]", string.Empty); - List level = new List(); - if (property.Contains('.')) - { - level.AddRange(property.Split('.')); - } - else - { - level.Add(property); - } - - var pe = Expression.Parameter(objtype); - var member = Expression.Property(pe, objtype.GetSingleProperty(level[0])); - for (int i = 1; i < level.Count; i++) - { - member = Expression.Property(member, member.Type.GetSingleProperty(level[i])); - } - return Expression.Lambda>(member, pe).Compile(); - } - - /// - /// 获取属性名 - /// - /// 属性表达式 - /// 是否获取全部级别名称,比如a.b.c - /// 属性名 - public static string GetPropertyName(this Expression expression, bool getAll = true) - { - if (expression == null) - { - return ""; - } - MemberExpression me = null; - LambdaExpression le = null; - if (expression is MemberExpression) - { - me = expression as MemberExpression; - } - if (expression is LambdaExpression) - { - le = expression as LambdaExpression; - if (le.Body is MemberExpression) - { - me = le.Body as MemberExpression; - } - if (le.Body is UnaryExpression) - { - me = (le.Body as UnaryExpression).Operand as MemberExpression; - } - } - string rv = ""; - if (me != null) - { - rv = me.Member.Name; - } - while (me != null && getAll && me.NodeType == ExpressionType.MemberAccess) - { - Expression exp = me.Expression; - if (exp is MemberExpression) - { - rv = (exp as MemberExpression).Member.Name + "." + rv; - me = exp as MemberExpression; - } - else if (exp is MethodCallExpression) - { - var mexp = exp as MethodCallExpression; - if (mexp.Method.Name == "get_Item") - { - object index = 0; - if (mexp.Arguments[0] is MemberExpression) - { - var obj = ((mexp.Arguments[0] as MemberExpression).Expression as ConstantExpression).Value; - index = obj.GetType().GetField((mexp.Arguments[0] as MemberExpression).Member.Name).GetValue(obj); - } - else - { - index = (mexp.Arguments[0] as ConstantExpression).Value; - } - rv = (mexp.Object as MemberExpression).Member.Name + "[" + index + "]." + rv; - me = mexp.Object as MemberExpression; - } - } - else - { - break; - } - } - return rv; - } - - public static Expression GetMemberExp(this ParameterExpression self, Expression member) - { - return self.GetMemberExp(member.GetPropertyName()); - } - - public static Expression GetMemberExp(this ParameterExpression self, string memberName) - { - var names = memberName.Split(','); - Expression rv = Expression.PropertyOrField(self, names[0]); ; - for (int i = 1; i < names.Length; i++) - { - rv = Expression.PropertyOrField(rv, names[i]); - } - return rv; - } - - - /// - /// 获取属性名的Id形式,将属性名中的.转换为_,适合作为HTML中的Id使用 - /// - /// 属性表达式 - /// 是否获取全部级别名称,比如a.b.c - /// 属性Id - public static string GetPropertyId(this Expression expression, bool getAll = true) - { - return GetPropertyName(expression, getAll).GetIdByName(); - } - - /// - /// 获取正则表达式错误 - /// - /// 属性信息 - /// 错误文本 - public static string GetRegexErrorMessage(this MemberInfo pi) - { - string rv = ""; - - if (pi.GetCustomAttributes(typeof(RegularExpressionAttribute), false).FirstOrDefault() is RegularExpressionAttribute dis && !string.IsNullOrEmpty(dis.ErrorMessage)) - { - rv = dis.ErrorMessage; - - } - else - { - rv = ""; - } - return rv; - } - - /// - /// 获取属性显示名称 - /// - /// 属性信息 - /// - /// 属性名称 - public static string GetPropertyDisplayName(this MemberInfo pi, IStringLocalizer local = null) - { - string rv = ""; - if (pi.GetCustomAttributes(typeof(DisplayAttribute), false).FirstOrDefault() is DisplayAttribute dis && !string.IsNullOrEmpty(dis.Name)) - { - rv = dis.Name; - if (local == null) - { - //if (CoreProgram._localizer != null) - //{ - // rv = CoreProgram._localizer[rv]; - //} - } - else - { - rv = local[rv]; - } - } - else - { - rv = pi.Name; - } - return rv; - } - - /// - /// 获取属性显示名称 - /// - /// 属性表达式 - /// - /// 属性显示名称 - public static string GetPropertyDisplayName(this Expression expression, IStringLocalizer local = null) - { - return GetPropertyDisplayName(expression.GetPropertyInfo(), local); - } - - - /// - /// 获取枚举显示名称 - /// - /// 枚举值 - /// 枚举显示名称 - public static string GetEnumDisplayName(this Enum value) - { - return GetEnumDisplayName(value.GetType(), value.ToString()); - } - - /// - /// 获取属性信息 - /// - /// 属性表达式 - /// 属性信息 - public static PropertyInfo GetPropertyInfo(this Expression expression) - { - MemberExpression me = null; - LambdaExpression le = null; - if (expression is MemberExpression) - { - me = expression as MemberExpression; - } - if (expression is LambdaExpression) - { - le = expression as LambdaExpression; - if (le.Body is MemberExpression) - { - me = le.Body as MemberExpression; - } - if (le.Body is UnaryExpression) - { - me = (le.Body as UnaryExpression).Operand as MemberExpression; - } - } - PropertyInfo rv = null; - if (me != null) - { - rv = me.Member.DeclaringType.GetSingleProperty(me.Member.Name); - } - return rv; - } - - /// - /// 获取属性值 - /// - /// 属性表达式 - /// 属性所在实例 - /// 属性值 - public static object GetPropertyValue(this object obj, LambdaExpression exp) - { - //获取表达式的值,并过滤单引号 - try - { - var expValue = exp.Compile().DynamicInvoke(obj); - object val = expValue; - return val; - } - catch - { - return ""; - } - } - - public static object GetPropertyValue(this object obj, string property) - { - //获取表达式的值,并过滤单引号 - try - { - return obj.GetType().GetSingleProperty(property).GetValue(obj); ; - } - catch - { - return ""; - } - } - - - public static List GetPropertySiblingValues(this object obj, string propertyName) - { - if (obj == null) - { - return new List(); - } - Regex reg = new Regex("(.*?)\\[\\-?\\d?\\]\\.(.*?)$"); - var match = reg.Match(propertyName); - if (match.Success) - { - var name1 = match.Groups[1].Value; - var name2 = match.Groups[2].Value; - - var levels = name1.Split('.'); - var objtype = obj.GetType(); - var pe = Expression.Parameter(objtype); - var member = Expression.Property(pe, objtype.GetSingleProperty(levels[0])); - for (int i = 1; i < levels.Length; i++) - { - member = Expression.Property(member, member.Type.GetSingleProperty(levels[i])); - } - var pe2 = Expression.Parameter(member.Type.GetGenericArguments()[0]); - var cast = Expression.Call(typeof(Enumerable), "Cast", new Type[] { pe2.Type }, member); - - var name2exp = Expression.Property(pe2, pe2.Type.GetSingleProperty(name2)); - var selectexp = Expression.Call(name2exp, "ToString", Type.EmptyTypes); - - Expression select = Expression.Call( - typeof(Enumerable), - "Select", - new Type[] { pe2.Type, typeof(string) }, - cast, - Expression.Lambda(selectexp, pe2)); - - - var lambda = Expression.Lambda(select, pe); - var rv = new List(); - try - { - rv = (lambda.Compile().DynamicInvoke(obj) as IEnumerable)?.ToList(); - } - catch { } - return rv; - } - else - { - return new List(); - } - } - - /// - /// 判断属性是否必填 - /// - /// 属性信息 - /// 是否必填 - public static bool IsPropertyRequired(this MemberInfo pi) - { - bool isRequired = false; - if (pi != null) - { - ////如果需要显示星号,则判断是否是必填项,如果是必填则在内容后面加上星号 - ////所有int,float。。。这种Primitive类型的,肯定都是必填 - //Type t = pi.GetMemberType(); - //if (t != null && (t.IsPrimitive() || t.IsEnum() || t == typeof(decimal) || t == typeof(Guid))) - //{ - // isRequired = true; - //} - //else - //{ - // //对于其他类,检查是否有RequiredAttribute,如果有就是必填 - // if (pi.GetCustomAttributes(typeof(RequiredAttribute), false).FirstOrDefault() is RequiredAttribute required && required.AllowEmptyStrings == false) - // { - // isRequired = true; - // } - // else if (pi.GetCustomAttributes(typeof(KeyAttribute), false).FirstOrDefault() != null) - // { - // isRequired = true; - // } - //} - } - return isRequired; - } - - /// - /// 设置属性值 - /// - /// 属性所在实例 - /// 属性名 - /// 要赋的值 - /// 属性前缀 - /// 是否为字符串格式的值 - public static void SetPropertyValue(this object source, string property, object value, string prefix = null, bool stringBasedValue = false) - { - try - { - property = Regex.Replace(property, @"\[[^\]]*\]", string.Empty); - List level = new List(); - if (property.Contains('.')) - { - level.AddRange(property.Split('.')); - } - else - { - level.Add(property); - } - - if (!string.IsNullOrWhiteSpace(prefix)) - { - level.Insert(0, prefix); - } - object temp = source; - Type tempType = source.GetType(); - for (int i = 0; i < level.Count - 1; i++) - { - var member = tempType.GetMember(level[i])[0]; - if (member != null) - { - var va = member.GetMemberValue(temp); - if (va != null) - { - temp = va; - } - else - { - var newInstance = member.GetMemberType().GetConstructor(Type.EmptyTypes).Invoke(null); - member.SetMemberValue(temp, newInstance, null); - temp = newInstance; - } - tempType = member.GetMemberType(); - - } - } - - var memberInfos = tempType.GetMember(level.Last()); - if (!memberInfos.Any()) - { - return; - } - var fproperty = memberInfos[0]; - if (value == null || ((value is StringValues s) && StringValues.IsNullOrEmpty(s))) - { - fproperty.SetMemberValue(temp, null, null); - return; - } - - bool isArray = false; - if (value != null && value.GetType().IsArray == true) - { - isArray = true; - } - - if (stringBasedValue == true) - { - Type propertyType = fproperty.GetMemberType(); - if (propertyType.IsGeneric(typeof(List<>)) == true) - { - var list = propertyType.GetConstructor(Type.EmptyTypes).Invoke(null) as IList; - - var gs = propertyType.GenericTypeArguments; - try - { - if (value.GetType() == typeof(StringValues)) - { - var strVals = (StringValues)value; - var a = strVals.ToArray(); - for (int i = 0; i < a.Length; i++) - { - list.Add(a[i].ConvertValue(gs[0])); - } - } - else if (isArray) - { - var a = (value as object[]); - for (int i = 0; i < a.Length; i++) - { - list.Add(a[i].ConvertValue(gs[0])); - } - } - else - { - list = value.ConvertValue(propertyType) as IList; - } - } - catch { } - fproperty.SetMemberValue(temp, list, null); - } - else if (propertyType.IsArray) - { - try - { - var strVals = (StringValues)value; - var eletype = propertyType.GetElementType(); - var arr = Array.CreateInstance(eletype, strVals.Count); - for (int i = 0; i < arr.Length; i++) - { - arr.SetValue(strVals[i].ConvertValue(eletype), i); - } - fproperty.SetMemberValue(temp, arr, null); - } - catch { } - } - else - { - if (isArray) - { - var a = (value as object[]); - if (a.Length == 1) - { - value = a[0]; - } - } - - if (value is string) - { - value = value.ToString().Replace("\\", "/"); - } - fproperty.SetMemberValue(temp, value, null); - } - } - else - { - if (value is string) - { - value = value.ToString().Replace("\\", "/"); - } - fproperty.SetMemberValue(temp, value, null); - } - } - catch - { - } - } - - /// - /// 根据MemberInfo获取值 - /// - /// MemberInfo - /// 所在实例 - /// 如果是数组,指定数组下标。默认为null - /// MemberInfo的值 - public static object GetMemberValue(this MemberInfo mi, object obj, object[] index = null) - { - object rv = null; - if (mi.MemberType == MemberTypes.Property) - { - rv = ((PropertyInfo)mi).GetValue(obj, index); - } - else if (mi.MemberType == MemberTypes.Field) - { - rv = ((FieldInfo)mi).GetValue(obj); - } - return rv; - } - - /// - /// 设定MemberInfo的值 - /// - /// MemberInfo - /// 所在实例 - /// 要赋的值 - /// 如果是数组,指定数组下标。默认为null - public static void SetMemberValue(this MemberInfo mi, object obj, object val, object[] index = null) - { - object newval = val; - if (val is string s) - { - if (string.IsNullOrEmpty(s)) - { - val = null; - } - } - if (val != null && val.GetType() != mi.GetMemberType()) - { - newval = val.ConvertValue(mi.GetMemberType()); - } - if (mi.MemberType == MemberTypes.Property) - { - ((PropertyInfo)mi).SetValue(obj, newval, index); - } - else if (mi.MemberType == MemberTypes.Field) - { - ((FieldInfo)mi).SetValue(obj, newval); - } - } - - /// - /// 获取某个MemberInfo的类型 - /// - /// MemberInfo - /// 类型 - public static Type GetMemberType(this MemberInfo mi) - { - Type rv = null; - if (mi != null) - { - if (mi.MemberType == MemberTypes.Property) - { - rv = ((PropertyInfo)mi).PropertyType; - } - else if (mi.MemberType == MemberTypes.Field) - { - rv = ((FieldInfo)mi).FieldType; - } - } - return rv; - } - - /// - /// 获取枚举显示名称 - /// - /// 枚举类型 - /// 枚举值 - /// 枚举显示名称 - public static string GetEnumDisplayName(Type enumType, string value) - { - string rv = ""; - FieldInfo field = null; - - if (enumType.IsEnum()) - { - field = enumType.GetField(value); - } - //如果是nullable的枚举 - if (enumType.IsGeneric(typeof(Nullable<>)) && enumType.GetGenericArguments()[0].IsEnum()) - { - field = enumType.GenericTypeArguments[0].GetField(value); - } - - if (field != null) - { - - var attribs = field.GetCustomAttributes(typeof(DisplayAttribute), true).ToList(); - if (attribs.Count > 0) - { - rv = ((DisplayAttribute)attribs[0]).GetName(); - - } - else - { - rv = value; - } - } - return rv; - } - - public static string GetEnumDisplayName(Type enumType, int value) - { - string rv = ""; - FieldInfo field = null; - string ename = ""; - if (enumType.IsEnum()) - { - ename = enumType.GetEnumName(value); - field = enumType.GetField(ename); - } - //如果是nullable的枚举 - if (enumType.IsGeneric(typeof(Nullable<>)) && enumType.GetGenericArguments()[0].IsEnum()) - { - ename = enumType.GenericTypeArguments[0].GetEnumName(value); - field = enumType.GenericTypeArguments[0].GetField(ename); - } - - if (field != null) - { - - var attribs = field.GetCustomAttributes(typeof(DisplayAttribute), true).ToList(); - if (attribs.Count > 0) - { - rv = ((DisplayAttribute)attribs[0]).GetName(); - - } - else - { - rv = ename; - } - } - return rv; - } - - /// - /// 转化值 - /// - /// 要转换的值 - /// 转换后的类型 - /// 转换后的值 - public static object ConvertValue(this object value, Type propertyType) - { - object val = null; - if (propertyType.IsGeneric(typeof(Nullable<>)) == true) - { - var gs = propertyType.GenericTypeArguments; - try - { - val = ConvertValue(value, gs[0]); - } - catch { } - } - else if (propertyType.IsEnum()) - { - val = Enum.Parse(propertyType, value.ToString()); - } - else if (propertyType == typeof(string)) - { - val = value?.ToString().Trim(); - } - else if (propertyType == typeof(Guid)) - { - bool suc = Guid.TryParse(value?.ToString(), out Guid g); - if (suc) - { - val = g; - } - else - { - val = Guid.Empty; - } - } - - else - { - try - { - if (value.ToString().StartsWith("`") && value.ToString().EndsWith("`")) - { - string inner = value.ToString().Trim('`').TrimEnd(','); - if (!string.IsNullOrWhiteSpace(inner)) - { - val = propertyType.GetConstructor(Type.EmptyTypes).Invoke(null); - string[] pair = inner.Split(','); - var gs = propertyType.GetGenericArguments(); - foreach (var p in pair) - { - (val as IList).Add(Convert.ChangeType(p, gs[0])); - } - } - } - else - { - val = Convert.ChangeType(value.ToString(), propertyType); - } - } - catch - { - } - } - return val; - } - - public static object MakeList(Type innerType, string propertyName, object[] values) - { - object rv = typeof(List<>).MakeGenericType(innerType).GetConstructor(Type.EmptyTypes).Invoke(null); - var mi = rv.GetType().GetMethod("Add"); - var con = innerType.GetConstructor(Type.EmptyTypes); - foreach (var item in values) - { - var newobj = con.Invoke(null); - newobj.SetPropertyValue(propertyName, item); - mi.Invoke(rv, new object[] { newobj }); - } - return rv; - } - } -} diff --git a/Vampirewal.Core/Interface/IAppConfig.cs b/Vampirewal.Core/Interface/IAppConfig.cs index 7959d3f60a0d3cb9c5c755f1448be6e64f2d8ee1..da4e9897b2e238ae1f6a50ba1137fa25f17a748d 100644 --- a/Vampirewal.Core/Interface/IAppConfig.cs +++ b/Vampirewal.Core/Interface/IAppConfig.cs @@ -11,116 +11,102 @@ //----------------------------------------------------------------*/ #endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Vampirewal.Core.AppConfig; -using Vampirewal.Core.Models; - -namespace Vampirewal.Core.Interface + + + +using Vampirewal.Core.ConfigOptions; + +namespace Vampirewal.Core.Interface; + + + +/// +/// 系统配置接口 +/// +[Obsolete("20230128 已废弃,请使用新的配置文件方式",true)] +public interface IAppConfig { - ///// - ///// 系统配置接口 - ///// - ///// - //public interface IAppConfig where T : AppConfigBaseModel, new() - //{ - // /// - // /// 配置model - // /// - // T Config { get; set; } - - // /// - // /// 读取配置文件 - // /// - // void LoadAppConfig(); - // /// - // /// 保存 - // /// - // void Save(); - - // /// - // /// 重置配置文件(慎用) - // /// - // void Delete(); - //} - - - /// - /// 系统配置接口 - /// - public interface IAppConfig - { - - - /// - /// 日志级别 - /// - LoggerType LogLevel { get; set; } - - /// - /// app中文名 - /// - string AppChineseName { get; set; }//展示界面顶部的名称 - - /// - /// 程序本地版本 - /// - string AppVersion { get; set; } - - /// - /// ConnectionStrings - /// - List ConnectionStrings { get; set; } - - /// - /// Database type - /// - DBTypeEnum DbType { get; set; } - - /// - /// 自定义设置 - /// - Dictionary AppSettings { get; set; } - - /// - /// 密钥Key - /// - string EncryptKey { get; set; } - - /// - /// 附件上传设置 - /// - FileUploadOptions FileUploadOptions { get; set; } - - /// - /// 更新程序设置 - /// - UpdateSetting UpdateSetting { get; set; } - /// - /// 配置文件路径 - /// - string ConfigPath { get; set; } - - /// - /// 配置文件名称 - /// - string ConfigName{get;set;} - /// - /// 读取配置文件 - /// - void LoadAppConfig(); - - /// - /// 保存配置文件 - /// - void Save(); - - /// - /// 重置配置文件(慎用) - /// - void Reset(); - } + + + /// + /// 日志级别 + /// + LoggerType LogLevel { get; set; } + + /// + /// app中文名 + /// + string AppChineseName { get; set; }//展示界面顶部的名称 + + /// + /// 程序本地版本 + /// + string AppVersion { get; set; } + + /// + /// ConnectionStrings + /// + List ConnectionStrings { get; set; } + + /// + /// Database type + /// + DBTypeEnum DbType { get; set; } + + /// + /// 列表分页设置 + /// + PageSetting pageSetting { get; set; } + /// + /// 自定义设置 + /// + Dictionary AppSettings { get; set; } + + /// + /// 密钥Key + /// + string EncryptKey { get; set; } + + /// + /// 附件上传设置 + /// + FileUploadOptions FileUploadOptions { get; set; } + + /// + /// 更新程序设置 + /// + UpdateSetting UpdateSetting { get; set; } + + /// + /// 视图View模块dll路径 + /// + List ViewModulesPath { get; set; } + + /// + /// 连接域设置 + /// + List Domains { get; set; } + /// + /// 配置文件路径 + /// + string ConfigPath { get; set; } + + /// + /// 配置文件名称 + /// + string ConfigName{get;set;} + /// + /// 读取配置文件 + /// + void LoadAppConfig(); + + /// + /// 保存配置文件 + /// + void Save(); + + /// + /// 重置配置文件(慎用) + /// + void Reset(); } diff --git a/Vampirewal.Core/Interface/IBaseListVM.cs b/Vampirewal.Core/Interface/IBaseListVM.cs deleted file mode 100644 index 52b3f7be541fa0c2b11af1cfd56ab827c79e6607..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/Interface/IBaseListVM.cs +++ /dev/null @@ -1,198 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:IBaseListVM -// 创 建 者:杨程 -// 创建时间:2021/9/16 13:27:58 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Text; -using System.Threading.Tasks; -using Vampirewal.Core.Models; -using Vampirewal.Core.SimpleMVVM; - -namespace Vampirewal.Core.Interface -{ - - /// - /// ListVM接口 - /// - public interface IBaseListVM - where T : TopBaseModel - where S : ISearcher - { - - - /// - /// 查询并生成Excel - /// - /// Excel文件 - byte[] GenerateExcel(); - - - string TotalText { get; set; } - #region Old - - event Action> OnAfterInitList; - /// - ///记录批量操作时列表中选择的Id - /// - List Ids { get; set; } - - /// - /// 获取Model集合 - /// - /// Model集合 - IEnumerable GetEntityList(); - - /// - /// 清空list - /// - void ClearEntityList(); - /// - /// 获取Searcher - /// - S Searcher { get; } - /// - /// 获取被选择的项 - /// - /// - /// - bool GetIsSelected(object item); - - /// - /// 每页行数 - /// - [Obsolete("弃用,改用 DataTableHelper上的Limit")] - int RecordsPerPage { get; set; } - - /// - /// 是否已经搜索过 - /// - bool IsSearched { get; set; } - - /// - /// PassSearch - /// - bool PassSearch { get; set; } - - /// - /// 搜索模式 - /// - ListVMSearchModeEnum SearcherMode { get; set; } - - /// - /// 是否需要分页 - /// - bool NeedPage { get; set; } - - /// - /// 允许导出Excel的最大行数,超过行数会分成多个文件,最多不能超过100万 - /// - int ExportMaxCount { get; set; } - - /// - /// 根据允许导出的Excel最大行数,算出最终导出的Excel个数 - /// - int ExportExcelCount { get; set; } - - /// - /// 移除操作列 - /// - void RemoveActionColumn(object root = null); - - /// - /// 移除动作 - /// - void RemoveAction(); - - ///// - ///// 填加错误信息列,用于批量操作的列表 - ///// - //void AddErrorColumn(); - - /// - /// 搜索条件Panel的Id - /// - string SearcherDivId { get; } - - /// - /// GetSearchQuery - /// - /// - IOrderedQueryable GetSearchQuery(); - /// - /// DoSearch - /// - void DoSearch(); - /// - /// CopyContext - /// - /// - void CopyContext(IBaseVM vm); - - /// - /// ReplaceWhere - /// - Expression> ReplaceWhere { get; set; } - - /// - /// SetFullRowColor - /// - /// - /// - string SetFullRowColor(object entity); - /// - /// SetFullRowBgColor - /// - /// - /// - string SetFullRowBgColor(object entity); - - /// - /// 创建1个空entity - /// - /// - T CreateEmptyEntity(); - - /// - /// 用于为子表生成可编辑Grid时,内部控件名称前缀 - /// - string DetailGridPrix { get; set; } - - /// - /// 初始化ListVM - /// - void DoInitListVM(); - - /// - /// 批量删除操作 - /// - void DoBatchDelete(); - - #endregion - } - - /// - /// ListVM的搜索模式枚举 - /// - public enum ListVMSearchModeEnum - { - Search, //搜索 - Export, //导出 - Batch, //批量 - Selector,//选择器 - MasterDetail, // - CheckExport, - Custom1, Custom2, Custom3, Custom4, Custom5 - }; -} diff --git a/Vampirewal.Core/Interface/IBaseVM.cs b/Vampirewal.Core/Interface/IBaseVM.cs deleted file mode 100644 index 26565991afd78bda0ed60774233c520f7449ed28..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/Interface/IBaseVM.cs +++ /dev/null @@ -1,90 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:IBaseVM -// 创 建 者:杨程 -// 创建时间:2021/9/16 13:51:08 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using Vampirewal.Core.Models; -using Vampirewal.Core.SimpleMVVM; - -namespace Vampirewal.Core.Interface -{ - /// - /// ViewModel基类接口 - /// - public interface IBaseVM - { - /// - /// - /// - string VMId { get; } - - /// - /// 标题 - /// - string Title { get; set; } - - /// - /// 绑定前端的UI - /// - FrameworkElement View { get; set; } - - /// - /// UI线程调用 - /// - /// - void UIInvoke(Action action); - - /// - /// 数据库操作使用,初始化必须在构造函数中,使用依赖注入 - /// - IDataContext DC { get; set; } - - /// - /// 当前登陆用户 - /// - LoginUserInfo loginUserInfo { get; set; } - - - /// - /// 当窗体是DialogShow的方式打开的时候,可以通过重写这个方法,将值传回主窗体 - /// - /// - object GetResult(); - - /// - /// 初始化页面数据,由ViewModelBase的构造函数调用,重写后不用再调用 - /// - void InitData(); - - /// - /// 初始化页面数据,由创建时传递参数 - /// - /// 传入参数 - void PassData(object obj); - - /// - /// 通用消息注册 - /// - void MessengerRegister(); - - /// - /// 拷贝VM内的信息 - /// - /// IBaseVM - void CopyVM(IBaseVM self); - } -} diff --git a/Vampirewal.Core/Interface/IDataContext.cs b/Vampirewal.Core/Interface/IDataContext.cs deleted file mode 100644 index 9bf262c04ecaf3787bc819edd0e3b567548ba575..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/Interface/IDataContext.cs +++ /dev/null @@ -1,141 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using System.Linq.Expressions; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore; -using Vampirewal.Core.Models; - -namespace Vampirewal.Core.Interface -{ - /// - /// IDataContext - /// - public interface IDataContext : IDisposable - { - /// - /// IsFake - /// - bool IsFake { get; set; } - - DBTypeEnum DBType { get; set; } - /// - /// AddEntity - /// - /// - /// - void AddEntity(T entity) where T : TopBaseModel; - - /// - /// UpdateEntity - /// - void UpdateEntity(T entity) where T : TopBaseModel; - - /// - /// UpdateProperty - /// - void UpdateProperty(T entity, Expression> fieldExp) where T : TopBaseModel; - - /// - /// UpdateProperty - /// - void UpdateProperty(T entity, string fieldName) where T : TopBaseModel; - - /// - /// DeleteEntity - /// - void DeleteEntity(T entity) where T : TopBaseModel; - - /// - /// CascadeDelete - /// - void CascadeDelete(T entity) where T : TopBaseModel, ITreeData; - - /// - /// Set - /// - /// - /// - DbSet Set() where T : class; - - /// - /// Model - /// - IModel Model { get; } - - /// - /// Database - /// - DatabaseFacade Database { get; } - - /// - /// CSName - /// - string CSName { get; set; } - - #region SaveChange - - /// - /// SaveChanges - /// - /// - int SaveChanges(); - - /// - /// SaveChanges - /// - /// - int SaveChanges(bool acceptAllChangesOnSuccess); - - /// - /// SaveChangesAsync - /// - /// - Task SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default(CancellationToken)); - - /// - /// SaveChangesAsync - /// - /// - Task SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken)); - - #endregion - - /// - /// 初始化 - /// - /// - /// - /// 返回true即数据新建完成,进入初始化操作,返回false即数据库已经存在 - Task DataInit(object AllModel, bool IsSpa); - - IDataContext CreateNew(); - IDataContext ReCreate(); - - /// - /// 执行存储过程,返回datatable - /// - /// 存储过程名称 - /// 参数 - /// - DataTable RunSP(string command, params object[] paras); - IEnumerable RunSP(string command, params object[] paras); - - /// - /// 执行sql语句,返回datatable - /// - /// 查询sql语句 - /// 参数 - /// - DataTable RunSQL(string command, params object[] paras); - IEnumerable RunSQL(string sql, params object[] paras); - DataTable Run(string sql, CommandType commandType, params object[] paras); - IEnumerable Run(string sql, CommandType commandType, params object[] paras); - object CreateCommandParameter(string name, object value, ParameterDirection dir); - } -} diff --git a/Vampirewal.Core/Interface/IDialogMessage.cs b/Vampirewal.Core/Interface/IDialogMessage.cs deleted file mode 100644 index 3fd3c738f9ab9934bb126cf02a6276feb4210f47..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/Interface/IDialogMessage.cs +++ /dev/null @@ -1,50 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:IDialogMessage -// 创 建 者:杨程 -// 创建时间:2021/10/18 10:51:43 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using Vampirewal.Core.WpfTheme.WindowStyle; - -namespace Vampirewal.Core.Interface -{ - /// - /// 弹窗通知服务接口 - /// - public interface IDialogMessage - { - /// - /// 弹出PopupWindow消息框 - /// - /// 消息内容 - /// 在哪个窗体内弹出 - /// 消息类型 - /// 是否自动关闭 - void ShowPopupWindow(string Msg, Window window, MessageType messageType, bool iskeepOpen = false); - - /// - /// 弹出DialogWindow窗体 - /// - /// 窗体设置 - object OpenDialogWindow(DialogWindowSetting setting); - - /// - /// - /// - [Obsolete("该方法暂时不提供使用!", true)] - string OpenVampirewalFolderBrowserDialog(); - } -} diff --git a/Vampirewal.Core/Interface/IEFRepository.cs b/Vampirewal.Core/Interface/IEFRepository.cs deleted file mode 100644 index a7f34c72513c96635447c76d8e9312b90b714d83..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/Interface/IEFRepository.cs +++ /dev/null @@ -1,41 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:IEFRepository -// 创 建 者:杨程 -// 创建时间:2021/9/10 13:30:27 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Text; -using System.Threading.Tasks; - -namespace Vampirewal.Core.Interface -{ - /// - /// EF帮助类接口 - /// - /// - public interface IEFRepository - { - - bool AddEntity(TEntity entity) where TEntity : class; - bool UpdateEntity(TEntity entity) where TEntity : class; - bool UpdateEntityList(IEnumerable entities) where TEntity : class; - bool DeleteEntity(object ID) where TEntity : class; - bool DeleteEntity(TEntity entity) where TEntity : class; - bool DeleteEntity(Expression> predicate) where TEntity : class; - bool DeleteEntityList(IEnumerable entities) where TEntity : class; - IEnumerable LoadEntities(Func whereLambda) where TEntity : class; - IEnumerable LoadEntities(int pageIndex = 1, int pageSize = 30, Func whereLambda = null) where TEntity : class; - TEntity GetByID(object ID) where TEntity : class; - } -} diff --git a/Vampirewal.Core/Interface/IIoC.cs b/Vampirewal.Core/Interface/IIoC.cs deleted file mode 100644 index b7c94e09f93f13376654e0c2ac407f207af4d8ff..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/Interface/IIoC.cs +++ /dev/null @@ -1,89 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:IIoC -// 创 建 者:杨程 -// 创建时间:2021/9/7 10:05:55 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Vampirewal.Core.Interface -{ - /// - /// IoC接口(来自Mvvmlight) - /// - public interface IIoC - { - - bool ContainsCreated(string key); - - - bool IsRegistered(); - - - bool IsRegistered(string key); - - - void Register() - where TInterface : class - where TClass : class, TInterface; - - - void Register(bool createInstanceImmediately) - where TInterface : class - where TClass : class, TInterface; - - - void Register() - where TClass : class; - - - void Register(bool createInstanceImmediately) - where TClass : class; - - - void Register(Func factory) - where TClass : class; - - - void Register(Func factory, bool createInstanceImmediately) - where TClass : class; - - - void Register(Func factory, string key) - where TClass : class; - - - void Register( - Func factory, - string key, - bool createInstanceImmediately) - where TClass : class; - - - void Reset(); - - - void Unregister() - where TClass : class; - - - void Unregister(TClass instance) - where TClass : class; - - - void Unregister(string key) - where TClass : class; - } -} diff --git a/Vampirewal.Core/Interface/ILogger.cs b/Vampirewal.Core/Interface/ILogger.cs deleted file mode 100644 index 3923e0b2c36065ab4a915316286f55aa3df8581f..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/Interface/ILogger.cs +++ /dev/null @@ -1,66 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:ILogger -// 创 建 者:杨程 -// 创建时间:2021/9/10 14:46:26 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Vampirewal.Core.Models; - -namespace Vampirewal.Core.Interface -{ - /// - /// 日志接口 - /// !!!使用该接口需配合IDataContext!!! - /// !!!如果没有使用IDataContext将会报错!!! - /// - public interface ILogger - { - /// - /// 写日志 - /// - /// 内容 - /// 日志类型 - /// 系统模块 - void WriteLog(string Msg,LoggerType loggerType, string SystemModuleName); - - /// - /// 写Debug日志 - /// - /// - /// - void DebugLog(string Msg, string SystemModuleName); - - /// - /// 写警告日志 - /// - /// - /// - void WarningLog(string Msg, string SystemModuleName); - - /// - /// 写错误日志 - /// - /// - /// - void ErrorLog(string Msg, string SystemModuleName); - - /// - /// SQL出现问题 - /// - /// - /// - void SQLLog(string Msg, string SystemModuleName); - } -} diff --git a/Vampirewal.Core/Interface/IOptions.cs b/Vampirewal.Core/Interface/IOptions.cs new file mode 100644 index 0000000000000000000000000000000000000000..fd55fcda55ad5f61d98db0b94bd59abb8ba33abd --- /dev/null +++ b/Vampirewal.Core/Interface/IOptions.cs @@ -0,0 +1,26 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: IOptions +// 创建者: 杨程 +// 创建日期: 2023/1/28 19:15:03 + +//----------------------------------------------------------------*/ +#endregion + + + +namespace Vampirewal.Core.Interface; + +/// +/// 自定义配置文件接口 +/// +public interface IOptions +{ + +} diff --git a/Vampirewal.Core/Interface/IPersistModel.cs b/Vampirewal.Core/Interface/IPersistModel.cs new file mode 100644 index 0000000000000000000000000000000000000000..9031e70be07f1169ac96a8e0a7003d6e48b27e63 --- /dev/null +++ b/Vampirewal.Core/Interface/IPersistModel.cs @@ -0,0 +1,28 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:IPersistModel +// 创 建 者:杨程 +// 创建时间:2022/1/29 16:49:35 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.Interface; + +/// +/// 是否假删除接口 +/// +public interface IPersistModel +{ + /// + /// + /// + bool IsDelete { get; set; } +} diff --git a/Vampirewal.Core/Interface/IVampirewalCoreActionService.cs b/Vampirewal.Core/Interface/IVampirewalCoreActionService.cs new file mode 100644 index 0000000000000000000000000000000000000000..0dd739e617290e751c18c1a95f54a96be06b4704 --- /dev/null +++ b/Vampirewal.Core/Interface/IVampirewalCoreActionService.cs @@ -0,0 +1,30 @@ +#region 文件信息 +/*=================================================== +* 类名称: IVampirewalActionService +* 类描述: +* 创建人: YangCheng +* 创建时间: 2022/5/18 10:50:39 +* 修改人: +* 修改时间: +* 版本: @version 1.0 +=====================================================*/ +#endregion + + + + + +namespace Vampirewal.Core.Interface; + +/// +/// 方法执行服务接口 +/// +public interface IVampirewalCoreActionService +{ + /// + /// 获取方法执行时间 + /// + /// + /// + string GetMethodExcuteTime(Action action); +} diff --git a/Vampirewal.Core/Interface/IVampirewalCoreDataContext.cs b/Vampirewal.Core/Interface/IVampirewalCoreDataContext.cs new file mode 100644 index 0000000000000000000000000000000000000000..2af0ea5ef4e84222b328d5ea81c800a8e835d18a --- /dev/null +++ b/Vampirewal.Core/Interface/IVampirewalCoreDataContext.cs @@ -0,0 +1,100 @@ + + + +namespace Vampirewal.Core.Interface; + +/// +/// VampireCore数据上下文 +/// +public interface IVampirewalCoreDataContext +{ + /// + /// 连接客户端 + /// + SqlSugarScope Client { get; set; } + +} + +/// +/// VampirewalCore的SqlSugar配置 +/// +public interface IVampirewalCoreSqlSugar +{ + /// + /// 初始化数据(在CodeFirst后执行) + /// + void InitData(); + /// + /// 设置客户端 + /// + /// + void SetClient(ISqlSugarClient client); + + /// + /// 配置Sqlsugar连接设置 + /// + /// + /// + /// + /// + ConnectionConfig GetDbConnectionConfig(string DbName, string ConnStr, DBTypeEnum? dbType); + + /// + /// 获取代码执行超过1秒的代码,放在OnLogExecuted + /// + /// 超时sql所在信息 + string GetSqlExecuteTimeMoreOnceSecond(); + + /// + /// SQL执行完 + /// + /// + /// + void OnLogExecuted(string sql, SugarParameter[] para); + + /// + /// SQL执行前 + /// + /// + /// + void OnLogExecuting(string sql, SugarParameter[] para); + + /// + /// SQL报错 + /// + /// + void OnError(SqlSugarException exp); + + /// + /// 数据执行过滤 + /// 可用于新增或修改的时候,处理CreateName或UpdateName + /// + /// + /// + void DataExecuting(object OldValue, DataFilterModel entityInfo); + + /// + /// 查询后数据替换 + /// + /// + /// + void DataExecuted(object value, DataAfterModel entity); + + /// + /// 可以修改SQL和参数的值 + /// + /// sql=newsql + /// foreach(var p in pars) //修改 + /// + KeyValuePair OnExecutingChangeSql(string sql, SugarParameter[] pars); + + /// + /// 创建表(需要建表的都需要重复写) + /// 使用方法:CreateTable(); + /// 这样一个表就能成功创建了 + /// + void CodeFirst(); + + +} + diff --git a/Vampirewal.Core/Interface/IVampirewalCoreDialogMessage.cs b/Vampirewal.Core/Interface/IVampirewalCoreDialogMessage.cs new file mode 100644 index 0000000000000000000000000000000000000000..b6972ae695fe6e96ce4bfb901937bd11b74ac4a6 --- /dev/null +++ b/Vampirewal.Core/Interface/IVampirewalCoreDialogMessage.cs @@ -0,0 +1,49 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:IDialogMessage +// 创 建 者:杨程 +// 创建时间:2021/10/18 10:51:43 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.Interface; + +/// +/// 弹窗通知服务接口 +/// +public interface IVampirewalCoreDialogMessage +{ + /// + /// 弹出PopupWindow消息框 + /// + /// 消息内容 + /// 在哪个窗体内弹出 + /// 消息类型 + /// 是否自动关闭 + void ShowPopupWindow(string Msg, Window window, MessageType messageType, bool iskeepOpen = false); + + /// + /// 弹出DialogWindow窗体 + /// + /// 窗体设置 + object OpenDialogWindow(DialogWindowSetting setting); + + /// + /// + /// + [Obsolete("该方法暂时不提供使用!", true)] + string OpenVampirewalFolderBrowserDialog(); + + /// + /// 弹出Notify通知窗 + /// + public void OpenNotifyWindow(NotifyWindowSetting Setting); +} diff --git a/Vampirewal.Core/Interface/IVampirewalCoreLogService.cs b/Vampirewal.Core/Interface/IVampirewalCoreLogService.cs new file mode 100644 index 0000000000000000000000000000000000000000..64875a8d6a08a4136ac8f4aa15bc24958194cc8a --- /dev/null +++ b/Vampirewal.Core/Interface/IVampirewalCoreLogService.cs @@ -0,0 +1,59 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:ILogger +// 创 建 者:杨程 +// 创建时间:2021/9/10 14:46:26 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.Interface; + +/// +/// VampireCore日志服务 +/// +public interface IVampirewalCoreLogService +{ + /// + /// 写日志 + /// + /// 内容 + /// 日志类型 + /// 系统模块 + void WriteLog(string Msg,LoggerType loggerType, string SystemModuleName); + + /// + /// 写Debug日志 + /// + /// + /// + void DebugLog(string Msg, string SystemModuleName); + + /// + /// 写警告日志 + /// + /// + /// + void WarningLog(string Msg, string SystemModuleName); + + /// + /// 写错误日志 + /// + /// + /// + void ErrorLog(string Msg, string SystemModuleName); + + /// + /// SQL出现问题 + /// + /// + /// + void SQLLog(string Msg, string SystemModuleName); +} diff --git a/Vampirewal.Core/Interface/IVampirewalCoreValidationService.cs b/Vampirewal.Core/Interface/IVampirewalCoreValidationService.cs new file mode 100644 index 0000000000000000000000000000000000000000..bd51adaae8e85ae15e75ed50a141889e67e69927 --- /dev/null +++ b/Vampirewal.Core/Interface/IVampirewalCoreValidationService.cs @@ -0,0 +1,37 @@ +#region 文件信息 +/*=================================================== +* 类名称: IValidationService +* 类描述: +* 创建人: YangCheng +* 创建时间: 2022/5/21 13:57:06 +* 修改人: +* 修改时间: +* 版本: @version 1.0 +=====================================================*/ +#endregion + + + + + +namespace Vampirewal.Core.Interface; + +/// +/// VampirewalCore错误属性验证服务 +/// 需要验证的类,属性上需要有 +/// +public interface IVampirewalCoreValidationService +{ + /// + /// 错误信息集合 + /// + public List ErrorList { get; } + + /// + /// 错误验证 + /// + /// + /// + /// + bool IsValidation(T t) where T : class; +} diff --git a/Vampirewal.Core/Interface/IVampirewalMessageManager.cs b/Vampirewal.Core/Interface/IVampirewalMessageManager.cs new file mode 100644 index 0000000000000000000000000000000000000000..38dcaac30569c6e364e4931e12359c0a450b4c2e --- /dev/null +++ b/Vampirewal.Core/Interface/IVampirewalMessageManager.cs @@ -0,0 +1,9 @@ + + + +namespace Vampirewal.Core.Interface; + +public interface IVampirewalMessageManager +{ + +} diff --git a/Vampirewal.Core/LICENSE b/Vampirewal.Core/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..ddbd00b437e877e43b09521e47a65ad43f04aa8a --- /dev/null +++ b/Vampirewal.Core/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 vampirewal + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Vampirewal.Core/Models/BaseModel.cs b/Vampirewal.Core/Models/BaseModel.cs index 17bedff152704c9d02b433c7754f72d5164e6243..21f408b194e6bdcbf1965a28f6074d0e27608053 100644 --- a/Vampirewal.Core/Models/BaseModel.cs +++ b/Vampirewal.Core/Models/BaseModel.cs @@ -1,69 +1,38 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:BaseModel -// 创 建 者:杨程 -// 创建时间:2021/9/15 10:54:24 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion +//#region << 文 件 说 明 >> +///*---------------------------------------------------------------- +//// 文件名称:BaseModel +//// 创 建 者:杨程 +//// 创建时间:2021/9/15 10:54:24 +//// 文件版本:V1.0.0 +//// =============================================================== +//// 功能描述: +//// +//// +////----------------------------------------------------------------*/ +//#endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Vampirewal.Core.Models + + +namespace Vampirewal.Core.Models; + + +/// +/// 需要继承 +/// +public abstract partial class BaseModel : TopModel { + /// - /// BaseModel接口 + /// 更新时间 /// - public interface IBaseModel - { + [ObservableProperty] + public DateTime? updateTime; - /// - /// 更新时间 - /// - DateTime? UpdateTime { get; set; } - /// - /// 更新人 - /// - string UpdateBy { get; set; } - } /// - /// 需要继承 + /// 更新人 /// - public abstract class BaseModel : TopBaseModel, IBaseModel - { - private DateTime? _UpdateTime; - /// - /// 更新时间 - /// - public DateTime? UpdateTime - { - get => _UpdateTime; set - { - _UpdateTime = value; - DoNotify(); - } - } - - private string _UpdateBy; - /// - /// 更新人 - /// - public string UpdateBy - { - get => _UpdateBy; set - { - _UpdateBy = value; - DoNotify(); - } - } - } + [ObservableProperty] + public string updateBy; } diff --git a/Vampirewal.Core/Models/BillBaseModel.cs b/Vampirewal.Core/Models/BillBaseModel.cs new file mode 100644 index 0000000000000000000000000000000000000000..a0f1b42cfc6dc4eccaf6c325e8d513a672c60796 --- /dev/null +++ b/Vampirewal.Core/Models/BillBaseModel.cs @@ -0,0 +1,135 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:BillBaseModel +// 创 建 者:杨程 +// 创建时间:2022/1/29 16:17:48 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.Models; + +/// +/// 单据模型基类 +/// + +public class BillBaseModel : TopModel +{ + #region 属性 + private string _BillId; + + /// + /// Id + /// + [SugarColumn(IsPrimaryKey = true,IsNullable =false, ColumnDescription = "主键")] + //[ExportExcel(propertyChineseName: "单据ID", propertyName: "BillId",IsCanExport =true)] + public string BillId + { + get + { + + return _BillId; + } + set + { + _BillId = value; + OnPropertyChanged(); + } + } + + private DateTime? _CreateTime; + /// + /// 创建时间 + /// + [SugarColumn(IsNullable =true,IsOnlyIgnoreUpdate =true)] + public DateTime? CreateTime + { + get + { + + return _CreateTime; + } + set + { + _CreateTime = value; + OnPropertyChanged(); + } + } + + private string _CreateBy; + /// + /// 创建人 + /// + [SugarColumn(IsNullable = true, IsOnlyIgnoreUpdate = true)] + public string CreateBy + { + get { return _CreateBy; } + set { _CreateBy = value; OnPropertyChanged(); } + } + + private string _CreateUserId; + /// + /// 创建人ID + /// + [SugarColumn(IsNullable = true, IsOnlyIgnoreUpdate = true)] + public string CreateUserId + { + get { return _CreateUserId; } + set { _CreateUserId = value; OnPropertyChanged(); } + } + + + + private DateTime? _UpdateTime; + /// + /// 更新时间 + /// + [SugarColumn(IsNullable = true, IsOnlyIgnoreInsert = true)] + public DateTime? UpdateTime + { + get + { + + return _UpdateTime; + } + set + { + _UpdateTime = value; + OnPropertyChanged(); + } + } + + private string _UpdateBy; + /// + /// 更新人 + /// + [SugarColumn(IsNullable = true, IsOnlyIgnoreInsert = true)] + public string UpdateBy + { + get => _UpdateBy; set + { + _UpdateBy = value; + OnPropertyChanged(); + } + } + + private string _UpdateUserId; + /// + /// 更新人ID + /// + [SugarColumn(IsNullable = true, IsOnlyIgnoreInsert = true)] + public string UpdateUserId + { + get { return _UpdateUserId; } + set { _UpdateUserId = value; OnPropertyChanged(); } + } + + #endregion +} diff --git a/Vampirewal.Core/Models/DetailBaseModel.cs b/Vampirewal.Core/Models/DetailBaseModel.cs new file mode 100644 index 0000000000000000000000000000000000000000..4b1152114da97d705274182512a76aa65be3f634 --- /dev/null +++ b/Vampirewal.Core/Models/DetailBaseModel.cs @@ -0,0 +1,72 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:DetailBaseModel +// 创 建 者:杨程 +// 创建时间:2022/1/29 16:21:05 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.Models; + +/// +/// 明细数据基类 +/// +public class DetailBaseModel:TopModel +{ + public DetailBaseModel() + { + //构造函数 + } + + private string _DtlId; + /// + /// 明细ID + /// + [SugarColumn(IsPrimaryKey =true,IsNullable =false, ColumnDescription = "主键")] + //[ExportExcel(propertyChineseName: "明细ID", propertyName: "DtlId", IsCanExport = true)] + public string DtlId + { + get + { + return _DtlId; + } + set + { + _DtlId = value; + OnPropertyChanged(); + } + } + + private string _BillId; + + /// + /// 关联单据Id + /// + [SugarColumn( IsNullable = false)] + //[ExportExcel(propertyChineseName: "单据ID", propertyName: "BillId", IsCanExport = true)] + public string BillId + { + get + { + return _BillId; + } + set + { + _BillId = value; + OnPropertyChanged(); + } + } + + + +} + + diff --git a/Vampirewal.Core/Models/DetailItemChangeBaseModel.cs b/Vampirewal.Core/Models/DetailItemChangeBaseModel.cs new file mode 100644 index 0000000000000000000000000000000000000000..a1f2968be98106215d0b04f6954c063557fd7085 --- /dev/null +++ b/Vampirewal.Core/Models/DetailItemChangeBaseModel.cs @@ -0,0 +1,200 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: DetailItemChangeBaseModel +// 创建者: 杨程 +// 创建日期: 2022/11/1 17:21:18 + +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.Models; + +/// +/// 明细项变更基类 +/// +/// +public abstract class DetailItemChangeBaseModel : TopModel +{ + + /// + /// 当前项的变更状态 + /// + public ChangeType InnerItemChangeType { get; private set; } + + public DetailItemChangeBaseModel(TDto dto) + { + if (dto == null) + { + InnerItemChangeType = ChangeType.Add; + } + else + { + LoadDTO(dto); + RefreshSourceValue(); + } + } + + + + #region 基础属性 + private string _DtlId; + /// + /// 明细ID + /// + [SugarColumn(IsPrimaryKey = true, IsNullable = false, ColumnDescription = "主键")] + + public string DtlId + { + get + { + + return _DtlId; + } + set + { + _DtlId = value; + OnPropertyChanged(); + } + } + + private string _BillId; + + /// + /// 关联单据Id + /// + [SugarColumn(IsNullable = false)] + //[ExportExcel(propertyChineseName: "单据ID", propertyName: "BillId", IsCanExport = true)] + public string BillId + { + get + { + return _BillId; + } + set + { + _BillId = value; + OnPropertyChanged(); + } + } + #endregion + + + /// + /// 记录原始值,并刷新变更状态为NoChanged + /// + public void RefreshSourceValue() + { + InnerItemChangeType = ChangeType.NoChanged; + //_sourceValueMD5 = CreateCurrentValueToken(); + GetOldValueByAttribute(); + } + + /// + /// 设置当前项为删除状态 + /// + public void SetDeleteState() + { + InnerItemChangeType = ChangeType.Deleted; + } + /// + /// 加载DTO,如果这里使用到该DTO,需要在该方法里面实例化 + /// + /// 原始的DTO,可以为null + public abstract void LoadDTO(TDto dto); + + + + + + private Dictionary OldDic = new Dictionary(); + + /// + /// 通过特性获取初始值 + /// + private void GetOldValueByAttribute() + { + var Props = this.GetType().GetProperties().Where(w => w.GetCustomAttribute() != null); + + foreach (PropertyInfo prop in Props) + { + var att = prop.GetCustomAttribute(); + + if (att != null) + { + var OldVaule = prop.GetValue(this, null); + + OldDic.Add(att.PropertyName, OldVaule); + } + } + } + + /// + /// 比较原始值 + /// + /// + public bool CompareSourceValue() + { + var Props = this.GetType().GetProperties().Where(w => w.GetCustomAttribute() != null); + + bool IsChange = false; + + foreach (PropertyInfo prop in Props) + { + if (IsChange) + { + continue; + } + + var Newatt = prop.GetCustomAttribute(); + + if (Newatt != null && OldDic.TryGetValue(Newatt.PropertyName, out object OldVaule)) + { + var NewVaule = prop.GetValue(this, null); + + if (InnerItemChangeType != ChangeType.Deleted && InnerItemChangeType != ChangeType.Add) + { + InnerItemChangeType = NewVaule != OldVaule ? ChangeType.Changed : ChangeType.NoChanged; + } + } + + if (InnerItemChangeType != ChangeType.NoChanged) + { + IsChange = true; + } + } + + return IsChange; + } +} + +/// +/// 细目变更状态 +/// +public enum ChangeType +{ + /// + /// 删除 + /// + Deleted = -1, + /// + /// 未变更 + /// + NoChanged = 0, + /// + /// 新增 + /// + Add = 1, + /// + /// 编辑 + /// + Changed = 2 +} diff --git a/Vampirewal.Core/Models/EnumberCreditType.cs b/Vampirewal.Core/Models/EnumberCreditType.cs index d059bb8b2b50825e8e539b369e1d4f75c46bafae..689b8b06abab38efdd035bd6f98c830a187d31ea 100644 --- a/Vampirewal.Core/Models/EnumberCreditType.cs +++ b/Vampirewal.Core/Models/EnumberCreditType.cs @@ -11,43 +11,39 @@ //----------------------------------------------------------------*/ #endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Vampirewal.Core.Models + + +namespace Vampirewal.Core.Models; + +/// +/// 自定义返回值类型(适用于从枚举获取display值) +/// +public class EnumberCreditType { + /// + /// 枚举的描述 + /// + public string Desction { set; get; } + + /// + /// 枚举名称 + /// + public string Key { set; get; } + + /// + /// 枚举对象的值 + /// + public int Value { set; get; } + + /// + /// 描述 + /// + public string Name { get; set; } + + /// - /// 自定义返回值类型 + /// 分类 /// - public class EnumberCreditType - { - /// - /// 枚举的描述 - /// - public string Desction { set; get; } - - /// - /// 枚举名称 - /// - public string Key { set; get; } - - /// - /// 枚举对象的值 - /// - public int Value { set; get; } - - /// - /// 描述 - /// - public string Name { get; set; } - - - /// - /// 分类 - /// - public int Classification { set; get; } - } + public int Classification { set; get; } } diff --git a/Vampirewal.Core/Models/Enums.cs b/Vampirewal.Core/Models/Enums.cs new file mode 100644 index 0000000000000000000000000000000000000000..69f52aa84c3a5b67b038c2aa080da1b8ec3ff344 --- /dev/null +++ b/Vampirewal.Core/Models/Enums.cs @@ -0,0 +1,289 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:Enums +// 创 建 者:杨程 +// 创建时间:2021/9/15 14:26:53 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core; + +/// +/// 列表操作列类型 +/// +public enum ColumnFormatTypeEnum +{ + Dialog,//弹出窗口 + Button,//按钮 + Download,//下载 + ViewPic,//查看图片 + Script,//脚本 + Html +} + +/// +/// 上传图片存储方式 +/// +public enum SaveFileModeEnum +{ + Local = 0,//本地 + Database = 1,//数据库 + DFS = 2 //DFS +}; + +/// +/// 数据库类型 +/// +public enum DBTypeEnum { + MySql, + SqlServer, + Sqlite, + Oracle, + PostgreSQL, + Dm, + Kdbndp, + Oscar +} + +/// +/// 页面显示方式 +/// +public enum PageModeEnum { Single, Tab } + +/// +/// Tab页的显示方式 +/// +public enum TabModeEnum { Default, Simple } + +/// +/// Notification出现的位置 +/// +public enum ExtPosition +{ + b = 0, //下 + bl = 1,//左下 + br = 2,//右下 + t = 3,//上 + tl = 4,//左上 + tr = 5,//右上 + l = 6,//左 + r = 7//右 +} +/// +/// Grid的选择模式 +/// +public enum SelectionModeEnum +{ + SINGLE, + SIMPLE, + MULTI +}; + +public enum SortType +{ + Local, + Remote, + Disable +} +/// +/// 按钮 +/// +public enum ButtonTypesEnum +{ + Button, + Link +}; + +/// +/// 按钮 +/// +public enum RedirectTypesEnum +{ + Layer, + Self, + NewWindow, + NewTab, +}; + + +/// +/// 按钮类型 +/// +public enum ButtonOperationEnum +{ + Submit, + Button +}; + +///// +///// 上传类型 +///// +//public enum UploadTypesEnum +//{ +// AllFiles, +// ImageFile, +// ZipFile, +// ExcelFile, +// WordFile, +// PDFFile, +// TextFile, +// Custom +//}; + +/// +/// 日期类型 +/// +public enum DateTimeTypeEnum +{ + /// + /// 日期选择器 + /// 可选择:年、月、日 + /// + Date, + /// + /// 日期时间选择器 + /// 可选择:年、月、日、时、分、秒 + /// + DateTime, + /// + /// 年选择器 + /// 只提供年列表选择 + /// + Year, + /// + /// 年月选择器 + /// 只提供年、月选择 + /// + Month, + /// + /// 时间选择器 + /// 只提供时、分、秒选择 + /// + Time +}; + +/// +/// 图形枚举 +/// +public enum ChartEnum +{ + line, + pie, + column, + bubble, + barcolumn +} + +/// +/// 图形统计值类型 +/// +public enum ChartValueType +{ + sum, + count, + sumpct, + countpct +} +/// +/// 图形统计分区类型 +/// +public enum PartitionType +{ + year, + month, + day, + hour, + minute, + second +} + +public enum UIEnum +{ LayUI, React, VUE } + +public enum NoRightEnum +{ + /// + /// 隐藏 + /// + Invisible, + /// + /// 禁用 + /// + Disable +} + +public enum VTypeEnum { url, email, Date, Time, IPaddress, Int, UInt, Double, UDouble, Color, Phone, Tel } +public enum HiddenModeEnum { Display, Visibility, Offsets } +public enum RegionEnum { North, South, West, East, Center } +public enum LayoutEnum { absolute, border, box, fit, center } +public enum LabelAlignEnum { left, right, top } +public enum DockDirEnum { top, left, right, bottom } +public enum BoxAlignEnum { Stretch, Begin, Middle, End, StretchMax } +public enum BoxPackEnum { Start, Middle, End } +public enum BoxDirectionEnum { H, V } +public enum MsgTargetEnum { qtip, title, under, side, none } +public enum FieldTypeEnum { String, Int, Bool, Date } +public enum IconAlignEnum { Left, Right, Bottom, Top } +public enum UploadTypeEnum { AllFiles, ImageFile, ZipFile, ExcelFile, WordFile, PDFFile, TextFile } +public enum ComponentRenderMode { Normal, Declare, Get, Reference } + +public enum BoolComboTypes { YesNo, ValidInvalid, MaleFemale, HaveNotHave, Custom } + +public enum SortDir { Asc, Desc } + +public enum BackgroudColorEnum +{ + Grey, + Yellow, + Red +}; + +/// +/// HTTP Method +/// +public enum HttpMethodEnum { GET, POST, PUT, DELETE } + +/// +/// Excel类型 +/// +public enum ExcelType +{ + + xlsx = 0, + xls = 1 +} + +/// +/// GeneralListView界面上的按钮 +/// +public enum ListViewButton +{ + /// + /// 新增 + /// + Add=0, + /// + /// 编辑 + /// + Edit=1, + /// + /// 删除 + /// + Delete=2, + /// + /// 导出 + /// + Export=3, + /// + /// 导入 + /// + Import=4 +} diff --git a/Vampirewal.Core/Models/FileAttachment.cs b/Vampirewal.Core/Models/FileAttachment.cs deleted file mode 100644 index cd25267e7fedea303100ff2a85ab6af661c711d6..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/Models/FileAttachment.cs +++ /dev/null @@ -1,55 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:FileAttachment -// 创 建 者:杨程 -// 创建时间:2021/9/16 10:54:59 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Xml.Linq; - -namespace Vampirewal.Core.Models -{ - /// - /// FileAttachment - /// - [Table("FileAttachments")] - public class FileAttachment : BaseModel - { - - [Display(Name = "FileName")] - [Required(ErrorMessage = "{0}required")] - public string FileName { get; set; } - [Display(Name = "FileExt")] - [Required(ErrorMessage = "{0}required")] - [StringLength(10)] - public string FileExt { get; set; } - [Display(Name = "Path")] - public string Path { get; set; } - [Display(Name = "Length")] - public long Length { get; set; } - public DateTime UploadTime { get; set; } - public bool IsTemprory { get; set; } - - #region 组名,FastDFS服务器用 - [Display(Name = "SaveFileMode")] - public SaveFileModeEnum? SaveFileMode { get; set; } - [Display(Name = "GroupName")] - [StringLength(50, ErrorMessage = "最大长度为50!")] - public string GroupName { get; set; } - #endregion - public byte[] FileData { get; set; } - } -} diff --git a/Vampirewal.Core/Models/FrameworkDomain.cs b/Vampirewal.Core/Models/FrameworkDomain.cs deleted file mode 100644 index 8b36c45264e59c2410ed054937e43f4374730f54..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/Models/FrameworkDomain.cs +++ /dev/null @@ -1,68 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:FrameworkDomain -// 创 建 者:杨程 -// 创建时间:2021/9/16 16:59:46 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Vampirewal.Core.Models -{ - /// - /// 连接域 - /// - [Table("FrameworkDomains")] - public class FrameworkDomain:BaseModel - { - [StringLength(50, ErrorMessage = "长度最长50!")] - [Display(Name = "DomainName")] - [Required(ErrorMessage = "{0}required")] - [Column("DomainName")] - public string Name { get; set; } - - [StringLength(50, ErrorMessage = "长度最长50!")] - [Required(ErrorMessage = "{0}required")] - [Display(Name = "Address")] - [Column("DomainAddress")] - public string Address { get; set; } - - [Display(Name = "Port")] - [Range(1, 65535, ErrorMessage = "{0}必须是{1}到{2}之间的整数")] - [Column("DomainPort")] - public int? Port { get; set; } - - [Display(Name = "EntryUrl")] - public string EntryUrl { get; set; } - - [NotMapped] - public string Url - { - get - { - var rv = Address; - if (rv.ToLower().StartsWith("http://") == false && rv.ToLower().StartsWith("https://") == false) - { - rv = "http://" + rv; - } - if (Port != null) - { - rv += ":" + Port; - } - return rv; - } - } - } -} diff --git a/Vampirewal.Core/Models/FrameworkRole.cs b/Vampirewal.Core/Models/FrameworkRole.cs deleted file mode 100644 index 4458383c05a8b41ba5b07c5df0887b20a4022e5b..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/Models/FrameworkRole.cs +++ /dev/null @@ -1,63 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:FrameworkRole -// 创 建 者:杨程 -// 创建时间:2021/9/15 11:20:07 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Xml.Linq; - -namespace Vampirewal.Core.Models -{ - /// - /// 角色表 - /// - [Table("FrameworkRoles")] - public class FrameworkRole : BaseModel - { - /// - /// 角色ID - /// - [Display(Name = "角色ID")] - [Required(ErrorMessage = "Validate.{0}required")] - [RegularExpression("^[0-9]*$", ErrorMessage = "Validate.{0}number")] - [StringLength(100, ErrorMessage = "Validate.{0}stringmax{1}")] - public string RoleCode { get; set; } - - /// - /// 角色名称 - /// - [Display(Name = "角色名称")] - [StringLength(50, ErrorMessage = "Validate.{0}stringmax{1}")] - [Required(ErrorMessage = "Validate.{0}required")] - public string RoleName { get; set; } - - /// - /// 备注 - /// - [Display(Name = "备注")] - public string RoleRemark { get; set; } - - /// - /// 角色人数 - /// - [NotMapped] - [Display(Name = "角色人数")] - public int UsersCount { get; set; } - - - } -} diff --git a/Vampirewal.Core/Models/FrameworkUserBase.cs b/Vampirewal.Core/Models/FrameworkUserBase.cs deleted file mode 100644 index 73c351d6cdbf017625e3239fd97a40053e267511..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/Models/FrameworkUserBase.cs +++ /dev/null @@ -1,63 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:FrameworkUserBase -// 创 建 者:杨程 -// 创建时间:2021/9/15 10:53:29 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; -using System.Text; -using System.Text.Json.Serialization; -using System.Threading.Tasks; -using System.Xml.Linq; - -namespace Vampirewal.Core.Models -{ - /// - /// 系统人员基类 - /// - [Table("FrameworkUserBase")] - public class FrameworkUserBase : TopBaseModel - { - /// - /// 工号 - /// - [Display(Name = "工号")] - [StringLength(50, ErrorMessage = "Validate.{0}stringmax{1}")] - public string ITCode { get; set; } - - /// - /// 密码 - /// - [Display(Name = "密码")] - [Required(AllowEmptyStrings = false, ErrorMessage = "密码不能为空!")] - [StringLength(32, ErrorMessage = "密码最长32位!")] - public string Password { get; set; } - - /// - /// 姓名 - /// - [Display(Name = "姓名")] - [Required(ErrorMessage = "姓名不能为空")] - public string Name { get; set; } - - /// - /// 角色 - /// - [Display(Name = "角色")] - public List UserRoles { get; set; } - - //[Display(Name = "Group")] - //public List UserGroups { get; set; } - } -} diff --git a/Vampirewal.Core/Models/Logger.cs b/Vampirewal.Core/Models/Logger.cs index 8207dbe21ac810e7f7a40c50a8e00862ddd33d4f..0c5202a4a6e3a4763ee847ef718d1daddf55b2bc 100644 --- a/Vampirewal.Core/Models/Logger.cs +++ b/Vampirewal.Core/Models/Logger.cs @@ -11,55 +11,52 @@ //----------------------------------------------------------------*/ #endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace Vampirewal.Core.Models + + +namespace Vampirewal.Core.Models; + +/// +/// 日志模型 +/// +public class Logger:BillBaseModel { /// - /// 日志模型 + /// 日志类型 /// - public class Logger:TopBaseModel - { - /// - /// 日志类型 - /// - public LoggerType loggerType { get; set; } + public LoggerType loggerType { get; set; } - /// - /// 来自哪个模块 - /// - public string SystemMoudleName { get; set; } + /// + /// 来自哪个模块 + /// + public string SystemMoudleName { get; set; } - /// - /// 日志内容 - /// - public string LoggerContent { get; set; } - } + /// + /// 日志内容 + /// + [SugarColumn(Length =2000)] + public string LoggerContent { get; set; } +} +/// +/// 日志类型 +/// +public enum LoggerType +{ /// - /// 日志类型 + /// 任意操作 + /// + Debug=0, + /// + /// 警告 + /// + Warning=1, + /// + /// 错误 + /// + Error=2, + /// + /// 数据库操作 /// - public enum LoggerType - { - /// - /// 任意操作 - /// - Debug=0, - /// - /// 警告 - /// - Warning=1, - /// - /// 错误 - /// - Error=2, - /// - /// 数据库操作 - /// - SQL=3 - } + SQL=3 } diff --git a/Vampirewal.Core/Models/LoginUserInfo.cs b/Vampirewal.Core/Models/LoginUserInfo.cs deleted file mode 100644 index 6f4370012f6a630cccd6e0e849f5f20ebeff960a..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/Models/LoginUserInfo.cs +++ /dev/null @@ -1,165 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:LoginUserInfo -// 创 建 者:杨程 -// 创建时间:2021/9/15 19:33:30 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using Microsoft.VisualBasic.CompilerServices; - -namespace Vampirewal.Core.Models -{ - /// - /// 登陆用户信息 - /// 现在仅有可用于登陆 - /// - public class LoginUserInfo - { - /// - /// 单次登陆创建一个ID - /// - public Guid Id { get; set; } - - /// - /// 登录用户ID - /// - public string ITCode { get; set; } - - /// - /// 用户名 - /// - public string Name { get; set; } - - //public string Memo { get; set; } - - //public Guid? PhotoId { get; set; } - - /// - /// 关联角色 - /// - public List Roles { get; set; } - - //public List Groups { get; set; } - - //public Dictionary Attributes { get; set; } - /// - /// 用户的页面权限列表 - /// - //public List FunctionPrivileges { get; set; } - /// - /// 用户的数据权限列表 - /// - //public List DataPrivileges { get; set; } - - //private GlobalData _globalData; - //private GlobalData GlobalData - //{ - // get - // { - // if (_globalData == null) - // { - // _globalData = GlobalServices.GetRequiredService(); - // } - // return _globalData; - // } - //} - - //private Configs _configs; - //private Configs Configs - //{ - // get - // { - // if (_configs == null) - // { - // _configs = GlobalServices.GetRequiredService(); - // } - // return _configs; - // } - //} - - ///// - ///// 判断某URL是否有权限访问 - ///// - ///// url地址 - ///// true代表可以访问,false代表不能访问 - //public bool IsAccessable(string url) - //{ - // // 如果是调试 或者 url 为 null or 空字符串 - // if (Configs.IsQuickDebug || string.IsNullOrEmpty(url)) - // { - // return true; - // } - // //循环所有不限制访问的url,如果含有当前判断的url,则认为可以访问 - // var publicActions = GlobalData.AllAccessUrls; - // foreach (var au in publicActions) - // { - // if (new Regex(au + "[/\\?]?", RegexOptions.IgnoreCase).IsMatch(url)) - // { - // return true; - // } - // } - // //如果没有任何页面权限,则直接返回false - // if (FunctionPrivileges == null) - // { - // return false; - // } - - - // url = Regex.Replace(url, "/do(batch.*)", "/$1", RegexOptions.IgnoreCase); - - // //如果url以#开头,一般是javascript使用的临时地址,不需要判断,直接返回true - // url = url.Trim(); - - // if (url.StartsWith("#")) - // { - // return true; - // } - // var menus = GlobalData.AllMenus; - // var menu = Utils.FindMenu(url); - // //如果最终没有找到,说明系统菜单中并没有配置这个url,返回false - // if (menu == null) - // { - // return false; - // } - // //如果找到了,则继续验证其他权限 - // else - // { - // return IsAccessable(menu, menus); - // } - //} - - ///// - ///// 判断某菜单是否有权限访问 - ///// - ///// 菜单项 - ///// 所有系统菜单 - ///// true代表可以访问,false代表不能访问 - //public bool IsAccessable(FrameworkMenu menu, List menus) - //{ - // if (menu.IsPublic == true) - // { - // return true; - // } - // //寻找当前菜单的页面权限 - // var find = FunctionPrivileges.Where(x => x.MenuItemId == menu.ID && x.Allowed == true).FirstOrDefault(); - // //如果能找到直接对应的页面权限 - // if (find != null) - // { - // return true; - // } - // return false; - //} - } -} diff --git a/Vampirewal.Core/Models/TopBaseModel.cs b/Vampirewal.Core/Models/TopBaseModel.cs deleted file mode 100644 index f78f40a7fc1338ae05cb52510eea032c8eaa62c4..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/Models/TopBaseModel.cs +++ /dev/null @@ -1,132 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:TopBaseModel -// 创 建 者:杨程 -// 创建时间:2021/8/12 15:38:12 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; -using System.Text; -using System.Text.Json.Serialization; -using System.Threading.Tasks; -using Vampirewal.Core.Extensions; -using Vampirewal.Core.SimpleMVVM; - -namespace Vampirewal.Core.Models -{ - /// - /// model基类 - /// - public class TopBaseModel:NotifyBase - { - - #region 属性 - private string _id; - - /// - /// Id - /// - [Key] - public string ID - { - get - { - if (string.IsNullOrEmpty(_id)) - { - _id = Guid.NewGuid().ToString(); - } - return _id; - } - set - { - _id = value; - DoNotify(); - } - } - - private DateTime? _CreateTime; - /// - /// 创建时间 - /// - [Column("CreateTime")] - public DateTime? CreateTime - { - get - { - if (_CreateTime == null) - { - _CreateTime = DateTime.Now; - } - return _CreateTime; - } - set - { - _CreateTime = value; - DoNotify(); - } - } - - private string _CreateBy; - /// - /// 创建人 - /// - [Column("CreateBy")] - public string CreateBy - { - get { return _CreateBy; } - set { _CreateBy = value;DoNotify(); } - } - - private bool _Check; - /// - /// 是否选中 - /// 标识当前行数据是否被选中 - /// - [NotMapped] - [JsonIgnore] - public bool Checked { get=> _Check; set { _Check = value;DoNotify(); } } - #endregion - - #region 公共方法 - /// - /// 获取当前model的ID - /// - /// - public object GetID() - { - var idpro = this.GetType().GetProperties().Where(x => x.Name.ToLower() == "id").FirstOrDefault(); - var id = idpro.GetValue(this); - return id; - } - - /// - /// 获取父ID - /// - /// - public object GetParentID() - { - var idpro = this.GetType().GetSingleProperty("ParentId"); - var id = idpro.GetValue(this) ?? ""; - return id; - } - #endregion - - #region 私有方法 - - #endregion - - #region 命令 - - #endregion - } -} diff --git a/Vampirewal.Core/Models/TopModel.cs b/Vampirewal.Core/Models/TopModel.cs new file mode 100644 index 0000000000000000000000000000000000000000..25ba226d178da5f3d39f4d6c148b54593933d2d7 --- /dev/null +++ b/Vampirewal.Core/Models/TopModel.cs @@ -0,0 +1,78 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:TopModel +// 创 建 者:杨程 +// 创建时间:2022/1/29 16:15:55 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + + + +namespace Vampirewal.Core.Models; + +/// +/// 模型基类 +/// +public partial class TopModel : ObservableObject +{ + + private bool _IsChecked; + /// + /// 是否选中 + /// 标识当前行数据是否被选中 + /// + [SugarColumn(IsIgnore =true)] + [JsonIgnore] + public bool IsChecked + { + get + { + return _IsChecked; + } + set + { + SetProperty(ref _IsChecked, value); + } + } + + + #region 公共方法 + /// + /// 获取当前model的BillID + /// + /// + public object GetBillID() + { + var idpro = this.GetType().GetProperties().Where(x => x.Name.ToLower() == "BILLID").FirstOrDefault(); + var id = idpro.GetValue(this); + return id; + } + + /// + /// 获取当前model的DtlId + /// + /// + public object GetDtlId() + { + var idpro = this.GetType().GetProperties().Where(x => x.Name.ToLower() == "DTLID").FirstOrDefault(); + var id = idpro.GetValue(this); + return id; + } + + /// + /// 获取父ID + /// + /// + public object GetParentID() + { + var idpro = this.GetType().GetProperties().Where(x => x.Name.ToLower() == "ParentId").FirstOrDefault(); + var id = idpro.GetValue(this) ?? ""; + return id; + } + #endregion +} diff --git a/Vampirewal.Core/Models/TreeDetailBaseModel.cs b/Vampirewal.Core/Models/TreeDetailBaseModel.cs new file mode 100644 index 0000000000000000000000000000000000000000..b546b9e0c146881c249e594aa20005f5cdbfe4bd --- /dev/null +++ b/Vampirewal.Core/Models/TreeDetailBaseModel.cs @@ -0,0 +1,54 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:TreeDetailBaseModel +// 创 建 者:杨程 +// 创建时间:2022/1/29 16:33:45 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + + + +namespace Vampirewal.Core.Models; + +/// +/// 树形明细基类 +/// +/// +public class TreeDetailBaseModel:DetailBaseModel where T : DetailBaseModel +{ + public TreeDetailBaseModel() + { + //构造函数 + Childs=new ObservableCollection(); + } + + private T _Parent; + /// + /// 父类 + /// + public T Parent + { + get { return _Parent; } + set { _Parent = value; OnPropertyChanged(); } + } + + private string _ParentId; + /// + /// 父ID + /// + public string ParentId + { + get { return _ParentId; } + set { _ParentId = value; OnPropertyChanged(); } + } + + /// + /// 子集 + /// + public ObservableCollection Childs { get; set; } +} diff --git a/Vampirewal.Core/Models/ValidationBaseModel.cs b/Vampirewal.Core/Models/ValidationBaseModel.cs new file mode 100644 index 0000000000000000000000000000000000000000..9d9cea9c7a8b61028826ebf54bb1bff1cbe0ad4f --- /dev/null +++ b/Vampirewal.Core/Models/ValidationBaseModel.cs @@ -0,0 +1,100 @@ +#region 文件信息 +/*=================================================== +* 类名称: ValidationBaseModel +* 类描述: +* 创建人: YangCheng +* 创建时间: 2022/5/18 9:49:28 +* 修改人: +* 修改时间: +* 版本: @version 1.0 +=====================================================*/ +#endregion + + + + + +namespace Vampirewal.Core.Models; + +/// +/// 数据验证模型基类 +/// +public class ValidationBaseModel : TopModel, IDataErrorInfo +{ + private string _errorStr; + + /// + /// 错误信息(界面显示用) + /// + public string Error => _errorStr; + + /// + /// + /// + /// + /// + public string this[string columnName] + { + get + { + Type type = GetType(); + PropertyInfo property = type.GetProperty(columnName); + object[] customAttributes = property.GetCustomAttributes(inherit: false); + object value = property.GetValue(this, null); + object[] array = customAttributes; + foreach (object obj in array) + { + ValidationAttribute validationAttribute = obj as ValidationAttribute; + try + { + if (validationAttribute != null && !validationAttribute.IsValid(value)) + { + _errorStr = validationAttribute.ErrorMessage; + return validationAttribute.ErrorMessage; + } + } + catch (Exception) + { + return "验证异常"; + } + } + + _errorStr = string.Empty; + return string.Empty; + } + } + + /// + /// 验证是否合法(只验证带有验证标记的属性) + /// + /// 自定义排除属性 + /// + public bool IsValidation(params string[] ignoreProperties) + { + Type type = GetType(); + PropertyInfo[] properties = type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public); + PropertyInfo[] array = properties; + foreach (PropertyInfo propertyInfo in array) + { + if (ignoreProperties?.Contains(propertyInfo.Name) ?? false) + { + continue; + } + + object[] customAttributes = propertyInfo.GetCustomAttributes(inherit: false); + object value = propertyInfo.GetValue(this, null); + object[] array2 = customAttributes; + foreach (object obj in array2) + { + ValidationAttribute validationAttribute = obj as ValidationAttribute; + if (validationAttribute != null && !validationAttribute.IsValid(value)) + { + _errorStr = validationAttribute.ErrorMessage; + return false; + } + } + } + + return true; + } +} diff --git a/Vampirewal.Core/SimpleMVVM/BaseCRUDVM.cs b/Vampirewal.Core/SimpleMVVM/BaseCRUDVM.cs deleted file mode 100644 index 998f8c0076d94d9742188a29e3a5915a35901390..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/SimpleMVVM/BaseCRUDVM.cs +++ /dev/null @@ -1,982 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:BaseCRUDVM -// 创 建 者:杨程 -// 创建时间:2021/9/16 10:09:04 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; -using Microsoft.VisualBasic.CompilerServices; -using Vampirewal.Core.Extensions; -using Vampirewal.Core.Helper; -using Vampirewal.Core.Interface; -using Vampirewal.Core.Models; - -namespace Vampirewal.Core.SimpleMVVM -{ - /// - /// CRUD基类VM - /// - /// - public class BaseCRUDVM : ViewModelBase, IBaseCRUDVM where TModel : TopBaseModel, new() - { - private TModel _Entity; - /// - /// 实体类 - /// - public TModel Entity - { - get - { - return _Entity; - } - - set - { - _Entity = value; - DoNotify(); - } - } - - //保存读取时Include的内容 - private List>> _toInclude { get; set; } - - /// - /// 无参构造函数 - /// - public BaseCRUDVM() - { - //初始化Entity - var ctor = typeof(TModel).GetConstructor(Type.EmptyTypes); - Entity = ctor.Invoke(null) as TModel; - //初始化VM中所有List<>的类 - var lists = typeof(TModel).GetProperties().Where(x => x.PropertyType.IsGeneric(typeof(List<>))); - foreach (var li in lists) - { - var gs = li.PropertyType.GetGenericArguments(); - var newObj = Activator.CreateInstance(typeof(List<>).MakeGenericType(gs[0])); - li.SetValue(Entity, newObj, null); - } - BaseCRUDInit(); - } - - /// - /// 获取DC的构造函数 - /// - /// - public BaseCRUDVM(IDataContext dc):base(dc) - { - //初始化Entity - var ctor = typeof(TModel).GetConstructor(Type.EmptyTypes); - Entity = ctor.Invoke(null) as TModel; - //初始化VM中所有List<>的类 - var lists = typeof(TModel).GetProperties().Where(x => x.PropertyType.IsGeneric(typeof(List<>))); - foreach (var li in lists) - { - var gs = li.PropertyType.GetGenericArguments(); - var newObj = Activator.CreateInstance(typeof(List<>).MakeGenericType(gs[0])); - li.SetValue(Entity, newObj, null); - } - BaseCRUDInit(); - } - - /// - /// 获取DC和配置文件的构造函数 - /// - /// - /// - public BaseCRUDVM(IDataContext dc,IAppConfig config) : base(dc,config) - { - //初始化Entity - var ctor = typeof(TModel).GetConstructor(Type.EmptyTypes); - Entity = ctor.Invoke(null) as TModel; - //初始化VM中所有List<>的类 - var lists = typeof(TModel).GetProperties().Where(x => x.PropertyType.IsGeneric(typeof(List<>))); - foreach (var li in lists) - { - var gs = li.PropertyType.GetGenericArguments(); - var newObj = Activator.CreateInstance(typeof(List<>).MakeGenericType(gs[0])); - li.SetValue(Entity, newObj, null); - } - - BaseCRUDInit(); - } - - public IQueryable GetBaseQuery() - { - return DC.Set(); - } - - /// - /// 设定读取是Include的内容 - /// - /// 需要关联的类 - public void SetInclude(params Expression>[] exps) - { - _toInclude = _toInclude ?? new List>>(); - _toInclude.AddRange(exps); - } - - - /// - /// 设定添加和修改时对于重复数据的判断,子类进行相关操作时应重载这个函数 - /// - /// 唯一性属性 - public virtual DuplicatedInfo SetDuplicatedCheck() - { - return null; - } - /// - /// 添加 - /// - public void DoAdd() - { - DoAddPrepare(); - //删除不需要的附件 - if (DeletedFileIds != null) - { - foreach (var item in DeletedFileIds) - { - FileAttachmentVM ofa = new FileAttachmentVM(); - ofa.CopyVM(this); - ofa.SetEntityById(item); - ofa.DoDelete(); - } - } - DC.SaveChanges(); - } - - private void DoAddPrepare() - { - var pros = typeof(TModel).GetProperties(); - //将所有TopBaseModel的属性赋空值,防止添加关联的重复内容 - if (typeof(TModel) != typeof(FileAttachment)) - { - foreach (var pro in pros) - { - if (pro.PropertyType.GetTypeInfo().IsSubclassOf(typeof(TopBaseModel))) - { - pro.SetValue(Entity, null); - } - } - } - //自动设定添加日期和添加人 - if ( typeof(TModel).GetTypeInfo().IsSubclassOf(typeof(TopBaseModel))) - { - TopBaseModel ent = Entity as TopBaseModel; - if (ent.CreateTime == null) - { - ent.CreateTime = DateTime.Now; - } - if (string.IsNullOrEmpty(ent.CreateBy)) - { - ent.CreateBy = loginUserInfo?.ITCode; - } - } - - if (typeof(TModel).GetTypeInfo().IsSubclassOf(typeof(PersistModel))) - { - (Entity as PersistModel).IsValid = true; - } - - #region 更新子表 - foreach (var pro in pros) - { - //找到类型为List的字段 - if (pro.PropertyType.GenericTypeArguments.Count() > 0) - { - //获取xxx的类型 - var ftype = pro.PropertyType.GenericTypeArguments.First(); - //如果xxx继承自TopBaseModel - if (ftype.IsSubclassOf(typeof(TopBaseModel))) - { - //界面传过来的子表数据 - IEnumerable list = pro.GetValue(Entity) as IEnumerable; - if (list != null && list.Count() > 0) - { - string fkname = DC.GetFKName(pro.Name); - PropertyInfo[] itemPros = ftype.GetProperties(); - - bool found = false; - foreach (var newitem in list) - { - foreach (var itempro in itemPros) - { - if (itempro.PropertyType.IsSubclassOf(typeof(TopBaseModel))) - { - itempro.SetValue(newitem, null); - } - if (!string.IsNullOrEmpty(fkname)) - { - if (itempro.Name.ToLower() == fkname.ToLower()) - { - itempro.SetValue(newitem, Entity.GetID()); - found = true; - } - } - } - } - //如果没有找到相应的外建字段,则可能是多对多的关系,或者做了特殊的设定,这种情况框架无法支持,直接退出本次循环 - if (found == false) - { - continue; - } - //循环页面传过来的子表数据,自动设定添加日期和添加人 - foreach (var newitem in list) - { - var subtype = newitem.GetType(); - BaseModel ent = newitem as BaseModel; - if (ent.CreateTime == null) - { - ent.CreateTime = DateTime.Now; - } - if (string.IsNullOrEmpty(ent.CreateBy)) - { - ent.CreateBy = loginUserInfo?.ITCode; - } - } - } - } - } - } - #endregion - - - //添加数据 - DC.Set().Add(Entity); - - } - /// - /// 异步添加 - /// - /// - public async Task DoAddAsync() - { - DoAddPrepare(); - //删除不需要的附件 - if (DeletedFileIds != null) - { - foreach (var item in DeletedFileIds) - { - FileAttachmentVM ofa = new FileAttachmentVM(); - ofa.CopyVM(this); - ofa.SetEntityById(item); - await ofa.DoDeleteAsync(); - } - } - await DC.SaveChangesAsync(); - } - /// - /// 删除 - /// - public virtual void DoDelete() - { - //如果是PersistPoco,则把IsValid设为false,并不进行物理删除 - if (typeof(TModel).GetTypeInfo().IsSubclassOf(typeof(PersistModel))) - { - //FC.Add("Entity.IsValid", 0); - (Entity as PersistModel).IsValid = false; - DoEditPrepare(false); - DC.SaveChanges(); - } - //如果是普通的TopBaseModel,则进行物理删除 - else if (typeof(TModel).GetTypeInfo().IsSubclassOf(typeof(TopBaseModel))) - { - DoRealDelete(); - } - } - /// - /// 异步删除 - /// - /// - public virtual async Task DoDeleteAsync() - { - //如果是PersistPoco,则把IsValid设为false,并不进行物理删除 - if (typeof(TModel).GetTypeInfo().IsSubclassOf(typeof(PersistModel))) - { - (Entity as PersistModel).IsValid = false; - (Entity as PersistModel).UpdateTime = DateTime.Now; - (Entity as PersistModel).UpdateBy = loginUserInfo?.ITCode; - DC.UpdateProperty(Entity, "IsValid"); - DC.UpdateProperty(Entity, "UpdateTime"); - DC.UpdateProperty(Entity, "UpdateBy"); - try - { - await DC.SaveChangesAsync(); - } - catch (DbUpdateException) - { - //MSD.AddModelError("", Program._localizer["DeleteFailed"]); - } - } - //如果是普通的TopBaseModel,则进行物理删除 - else if (typeof(TModel).GetTypeInfo().IsSubclassOf(typeof(TopBaseModel))) - { - DoRealDelete(); - } - } - /// - /// 保存编辑 - /// - /// - public virtual void DoEdit(bool updateAllFields) - { - DoEditPrepare(updateAllFields); - - DC.SaveChanges(); - //删除不需要的附件 - if (DeletedFileIds != null) - { - foreach (var item in DeletedFileIds) - { - FileAttachmentVM ofa = new FileAttachmentVM(); - ofa.CopyVM(this); - ofa.SetEntityById(item); - ofa.DoDelete(); - } - } - } - /// - /// 异步保存编辑 - /// - /// - /// - public virtual async Task DoEditAsync(bool updateAllFields) - { - DoEditPrepare(updateAllFields); - - await DC.SaveChangesAsync(); - //删除不需要的附件 - if (DeletedFileIds != null) - { - foreach (var item in DeletedFileIds) - { - FileAttachmentVM ofa = new FileAttachmentVM(); - ofa.CopyVM(this); - ofa.SetEntityById(item); - await ofa.DoDeleteAsync(); - } - } - } - - private void DoEditPrepare(bool updateAllFields) - { - if (typeof(TModel).GetTypeInfo().IsSubclassOf(typeof(BaseModel))) - { - BaseModel ent = Entity as BaseModel; - if (ent.UpdateTime == null) - { - ent.UpdateTime = DateTime.Now; - } - if (string.IsNullOrEmpty(ent.UpdateBy)) - { - ent.UpdateBy = loginUserInfo?.ITCode; - } - } - var pros = typeof(TModel).GetProperties(); - - #region 更新子表 - foreach (var pro in pros) - { - //找到类型为List的字段 - if (pro.PropertyType.GenericTypeArguments.Count() > 0) - { - //获取xxx的类型 - var ftype = pro.PropertyType.GenericTypeArguments.First(); - //如果xxx继承自TopBaseModel - if (ftype.IsSubclassOf(typeof(TopBaseModel))) - { - //界面传过来的子表数据 - - if (pro.GetValue(Entity) is IEnumerable list && list.Count() > 0) - { - //获取外键字段名称 - string fkname = DC.GetFKName(pro.Name); - PropertyInfo[] itemPros = ftype.GetProperties(); - - bool found = false; - foreach (var newitem in list) - { - var subtype = newitem.GetType(); - if (subtype.IsSubclassOf(typeof(BaseModel))) - { - BaseModel ent = newitem as BaseModel; - if (ent.UpdateTime == null) - { - ent.UpdateTime = DateTime.Now; - } - if (string.IsNullOrEmpty(ent.UpdateBy)) - { - ent.UpdateBy = loginUserInfo?.ITCode; - } - } - //循环页面传过来的子表数据,将关联到TopBaseModel的字段设为null,并且把外键字段的值设定为主表ID - foreach (var itempro in itemPros) - { - if (itempro.PropertyType.IsSubclassOf(typeof(TopBaseModel))) - { - itempro.SetValue(newitem, null); - } - if (!string.IsNullOrEmpty(fkname)) - { - if (itempro.Name.ToLower() == fkname.ToLower()) - { - itempro.SetValue(newitem, Entity.GetID()); - found = true; - } - } - } - } - //如果没有找到相应的外建字段,则可能是多对多的关系,或者做了特殊的设定,这种情况框架无法支持,直接退出本次循环 - if (found == false) - { - continue; - } - - - TModel _entity = null; - //打开新的数据库联接,获取数据库中的主表和子表数据 - using (var ndc = DC.CreateNew()) - { - _entity = ndc.Set().Include(pro.Name).AsNoTracking().CheckID(Entity.GetID()).FirstOrDefault(); - } - //比较子表原数据和新数据的区别 - IEnumerable toadd = null; - IEnumerable toremove = null; - IEnumerable data = _entity.GetType().GetSingleProperty(pro.Name).GetValue(_entity) as IEnumerable; - Utils.CheckDifference(data, list, out toremove, out toadd); - //设定子表应该更新的字段 - //List setnames = new List(); - //foreach (var field in FC.Keys) - //{ - // if (field.StartsWith("Entity." + pro.Name + "[0].")) - // { - // string name = field.Replace("Entity." + pro.Name + "[0].", ""); - // setnames.Add(name); - // } - //} - - //前台传过来的数据 - //foreach (var newitem in list) - //{ - // //数据库中的数据 - // foreach (var item in data) - // { - // //需要更新的数据 - // if (newitem.GetID().ToString() == item.GetID().ToString()) - // { - // dynamic i = newitem; - // var newitemType = item.GetType(); - // foreach (var itempro in itemPros) - // { - // if (!itempro.PropertyType.IsSubclassOf(typeof(TopBaseModel)) && (updateAllFields == true || setnames.Contains(itempro.Name))) - // { - // var notmapped = itempro.GetCustomAttribute(); - // if (itempro.Name != "ID" && notmapped == null && itempro.PropertyType.IsList() == false) - // { - // DC.UpdateProperty(i, itempro.Name); - // } - // } - // } - // if (item.GetType().IsSubclassOf(typeof(BaseModel))) - // { - // DC.UpdateProperty(i, "UpdateTime"); - // DC.UpdateProperty(i, "UpdateBy"); - // } - // } - // } - //} - //需要删除的数据 - foreach (var item in toremove) - { - //如果是PersistPoco,则把IsValid设为false,并不进行物理删除 - if (ftype.IsSubclassOf(typeof(PersistModel))) - { - (item as PersistModel).IsValid = false; - (item as PersistModel).UpdateTime = DateTime.Now; - (item as PersistModel).UpdateBy = loginUserInfo?.ITCode; - dynamic i = item; - DC.UpdateEntity(i); - } - else - { - foreach (var itempro in itemPros) - { - if (itempro.PropertyType.IsSubclassOf(typeof(TopBaseModel))) - { - itempro.SetValue(item, null); - } - } - dynamic i = item; - DC.DeleteEntity(i); - } - } - //需要添加的数据 - foreach (var item in toadd) - { - if (item.GetType().IsSubclassOf(typeof(BaseModel))) - { - BaseModel ent = item as BaseModel; - if (ent.CreateTime == null) - { - ent.CreateTime = DateTime.Now; - } - if (string.IsNullOrEmpty(ent.CreateBy)) - { - ent.CreateBy = loginUserInfo?.ITCode; - } - } - DC.AddEntity(item); - } - } - //else if (FC.Keys.Contains("Entity." + pro.Name + ".DONOTUSECLEAR") || (FC.ContainsKey("Entity." + pro.Name) && pro.GetValue(Entity) is IEnumerable list2 && list2?.Count() == 0)) - //{ - // PropertyInfo[] itemPros = ftype.GetProperties(); - // var _entity = DC.Set().Include(pro.Name).AsNoTracking().CheckID(Entity.GetID()).FirstOrDefault(); - // if (_entity != null) - // { - // IEnumerable removeData = _entity.GetType().GetSingleProperty(pro.Name).GetValue(_entity) as IEnumerable; - // //如果是PersistPoco,则把IsValid设为false,并不进行物理删除 - // if (removeData is IEnumerable removePersistPocoData) - // { - // foreach (var item in removePersistPocoData) - // { - // (item as PersistPoco).IsValid = false; - // (item as PersistPoco).UpdateTime = DateTime.Now; - // (item as PersistPoco).UpdateBy = LoginUserInfo?.ITCode; - // dynamic i = item; - // DC.UpdateEntity(i); - // } - // } - // else - // { - // foreach (var item in removeData) - // { - // foreach (var itempro in itemPros) - // { - // if (itempro.PropertyType.IsSubclassOf(typeof(TopBaseModel))) - // { - // itempro.SetValue(item, null); - // } - // } - // dynamic i = item; - // DC.DeleteEntity(i); - // } - // } - - // } - //} - } - } - } - #endregion - - - if (updateAllFields == false) - { - //foreach (var field in FC.Keys) - //{ - // if (field.StartsWith("Entity.") && !field.Contains("[")) - // { - // string name = field.Replace("Entity.", ""); - // try - // { - // DC.UpdateProperty(Entity, name); - // } - // catch (Exception ea) - // { - // } - // } - //} - if (typeof(TModel).GetTypeInfo().IsSubclassOf(typeof(BaseModel))) - { - try - { - DC.UpdateProperty(Entity, "UpdateTime"); - DC.UpdateProperty(Entity, "UpdateBy"); - } - catch (Exception) - { - } - } - } - else - { - DC.UpdateEntity(Entity); - } - } - /// - /// 物理删除 - /// - public virtual void DoRealDelete() - { - try - { - List fileids = new List(); - var pros = typeof(TModel).GetProperties(); - - //如果包含附件,则先删除附件 - var fa = pros.Where(x => x.PropertyType == typeof(FileAttachment) || typeof(TopBaseModel).IsAssignableFrom(x.PropertyType)).ToList(); - foreach (var f in fa) - { - if (f.GetValue(Entity) is FileAttachment file) - { - fileids.Add(new Guid(file.ID)); - } - f.SetValue(Entity, null); - } - - var fas = pros.Where(x => typeof(IEnumerable).IsAssignableFrom(x.PropertyType)).ToList(); - foreach (var f in fas) - { - var subs = f.GetValue(Entity) as IEnumerable; - if (subs != null) - { - foreach (var sub in subs) - { - fileids.Add(sub.FileId); - } - f.SetValue(Entity, null); - } - } - if (typeof(TModel) != typeof(FileAttachment)) - { - foreach (var pro in pros) - { - if (pro.PropertyType.GetTypeInfo().IsSubclassOf(typeof(TopBaseModel))) - { - pro.SetValue(Entity, null); - } - } - } - DC.DeleteEntity(Entity); - DC.SaveChanges(); - foreach (var item in fileids) - { - FileAttachmentVM ofa = new FileAttachmentVM(); - ofa.CopyVM(this); - ofa.SetEntityById(item); - ofa.DoDelete(); - } - } - catch (Exception) - { - //MSD.AddModelError("", Program._localizer["DeleteFailed"]); - } - } - /// - /// 异步物理删除 - /// - /// - public virtual async Task DoRealDeleteAsync() - { - try - { - List fileids = new List(); - var pros = typeof(TModel).GetProperties(); - - //如果包含附件,则先删除附件 - var fa = pros.Where(x => x.PropertyType == typeof(FileAttachment) || typeof(TopBaseModel).IsAssignableFrom(x.PropertyType)).ToList(); - foreach (var f in fa) - { - if (f.GetValue(Entity) is FileAttachment file) - { - fileids.Add(new Guid(file.ID)); - } - f.SetValue(Entity, null); - } - - var fas = pros.Where(x => typeof(IEnumerable).IsAssignableFrom(x.PropertyType)).ToList(); - foreach (var f in fas) - { - var subs = f.GetValue(Entity) as IEnumerable; - foreach (var sub in subs) - { - fileids.Add(sub.FileId); - } - f.SetValue(Entity, null); - } - if (typeof(TModel) != typeof(FileAttachment)) - { - foreach (var pro in pros) - { - if (pro.PropertyType.GetTypeInfo().IsSubclassOf(typeof(TopBaseModel))) - { - pro.SetValue(Entity, null); - } - } - } - DC.DeleteEntity(Entity); - await DC.SaveChangesAsync(); - foreach (var item in fileids) - { - FileAttachmentVM ofa = new FileAttachmentVM(); - ofa.CopyVM(this); - ofa.SetEntityById(item); - await ofa.DoDeleteAsync(); - } - } - catch (Exception e) - { - //MSD.AddModelError("", Program._localizer["DeleteFailed"]); - } - } - - /// - /// 设置当前VM的数据模型 - /// - /// - public void SetEntity(object entity) - { - this.Entity = entity as TModel; - } - - /// - /// 通过ID设置当前VM的数据模型 - /// - /// - public void SetEntityById(object id) - { - this.Entity = GetById(id); - } - - /// - /// 验证数据,默认验证重复数据。子类如需要其他自定义验证,则重载这个函数 - /// - /// 验证结果 - public virtual void Validate() - { - ValidateDuplicateData(); - } - - /// - /// 根据主键获取Entity - /// - /// 主键Id - /// Entity - protected virtual TModel GetById(object Id) - { - TModel rv = null; - //建立基础查询 - var query = DC.Set().AsQueryable(); - //循环添加其他设定的Include - if (_toInclude != null) - { - foreach (var item in _toInclude) - { - query = query.Include(item); - } - } - if (typeof(TModel).IsSubclassOf(typeof(PersistModel))) - { - var mod = new IsValidModifier(); - var newExp = mod.Modify(query.Expression); - query = query.Provider.CreateQuery(newExp) as IOrderedQueryable; - } - - //获取数据 - rv = query.CheckID(Id).AsNoTracking().SingleOrDefault(); - if (rv == null) - { - throw new Exception("数据不存在"); - } - //如果TopBaseModel有关联的附件,则自动Include 附件名称 - var fa = typeof(TModel).GetProperties().Where(x => x.PropertyType == typeof(FileAttachment)).ToList(); - foreach (var f in fa) - { - var fname = DC.GetFKName2(f.Name); - var fid = typeof(TModel).GetSingleProperty(fname).GetValue(rv) as Guid?; - var file = DC.Set().Where(x => x.ID == fid.ToString()).Select(x => new FileAttachment - { - ID = x.ID, - CreateBy = x.CreateBy, - CreateTime = x.CreateTime, - UpdateBy = x.UpdateBy, - UpdateTime = x.UpdateTime, - UploadTime = x.UploadTime, - FileExt = x.FileExt, - FileName = x.FileName, - Length = x.Length, - GroupName = x.GroupName, - IsTemprory = x.IsTemprory, - Path = x.Path, - SaveFileMode = x.SaveFileMode - }).FirstOrDefault(); - rv.SetPropertyValue(f.Name, file); - } - - return rv; - } - - /// - /// 创建重复数据信息 - /// - /// 重复数据信息 - /// 重复数据信息 - protected DuplicatedInfo CreateFieldsInfo(params DuplicatedField[] FieldExps) - { - DuplicatedInfo d = new DuplicatedInfo(); - d.AddGroup(FieldExps); - return d; - } - - /// - /// 创建一个简单重复数据信息 - /// - /// 重复数据的字段 - /// 重复数据信息 - public static DuplicatedField SimpleField(Expression> FieldExp) - { - return new DuplicatedField(FieldExp); - } - - /// - /// 创建一个关联到其他表数组中数据的重复信息 - /// - /// 关联表类 - /// 指向关联表类数组的Lambda - /// 指向最终字段的Lambda - /// 重复数据信息 - public static DuplicatedField SubField(Expression>> MiddleExp, params Expression>[] FieldExps) - { - return new ComplexDuplicatedField(MiddleExp, FieldExps); - } - - /// - /// 验证重复数据 - /// - protected void ValidateDuplicateData() - { - //获取设定的重复字段信息 - var checkCondition = SetDuplicatedCheck(); - if (checkCondition != null && checkCondition.Groups.Count > 0) - { - //生成基础Query - var baseExp = DC.Set().AsQueryable(); - var modelType = typeof(TModel); - ParameterExpression para = Expression.Parameter(modelType, "tm"); - //循环所有重复字段组 - foreach (var group in checkCondition.Groups) - { - List conditions = new List(); - //生成一个表达式,类似于 x=>x.Id != id,这是为了当修改数据时验证重复性的时候,排除当前正在修改的数据 - var idproperty = typeof(TModel).GetProperties().Where(x => x.Name.ToLower() == "id").FirstOrDefault(); - MemberExpression idLeft = Expression.Property(para, idproperty); - ConstantExpression idRight = Expression.Constant(Entity.GetID()); - BinaryExpression idNotEqual = Expression.NotEqual(idLeft, idRight); - conditions.Add(idNotEqual); - List props = new List(); - //在每个组中循环所有字段 - foreach (var field in group.Fields) - { - Expression exp = field.GetExpression(Entity, para); - if (exp != null) - { - conditions.Add(exp); - } - //将字段名保存,为后面生成错误信息作准备 - props.AddRange(field.GetProperties()); - } - //如果要求判断id不重复,则去掉id不相等的判断,加入id相等的判断 - if (props.Any(x => x.Name.ToLower() == "id")) - { - conditions.RemoveAt(0); - BinaryExpression idEqual = Expression.Equal(idLeft, idRight); - conditions.Insert(0, idEqual); - } - int count = 0; - if (conditions.Count > 1) - { - //循环添加条件并生成Where语句 - Expression conExp = conditions[0]; - for (int i = 1; i < conditions.Count; i++) - { - conExp = Expression.And(conExp, conditions[i]); - } - - MethodCallExpression whereCallExpression = Expression.Call( - typeof(Queryable), - "Where", - new Type[] { modelType }, - baseExp.Expression, - Expression.Lambda>(conExp, new ParameterExpression[] { para })); - var result = baseExp.Provider.CreateQuery(whereCallExpression); - - foreach (var res in result) - { - count++; - } - } - if (count > 0) - { - //循环拼接所有字段名 - string AllName = ""; - foreach (var prop in props) - { - string name = PropertyHelper.GetPropertyDisplayName(prop); - AllName += name + ","; - } - if (AllName.EndsWith(",")) - { - AllName = AllName.Remove(AllName.Length - 1); - } - //如果只有一个字段重复,则拼接形成 xxx字段重复 这种提示 - if (props.Count == 1) - { - //MSD.AddModelError(GetValidationFieldName(props[0])[0], Program._localizer["DuplicateError", AllName]); - } - //如果多个字段重复,则拼接形成 xx,yy,zz组合字段重复 这种提示 - else if (props.Count > 1) - { - //MSD.AddModelError(GetValidationFieldName(props.First())[0], Program._localizer["DuplicateGroupError", AllName]); - } - } - } - } - } - - /// - /// 根据属性信息获取验证字段名 - /// - /// 属性信息 - /// 验证字段名称数组,用于ValidationResult - private string[] GetValidationFieldName(PropertyInfo pi) - { - return new[] { "Entity." + pi.Name }; - } - - #region 基础命令 - /// - /// 保存命令(需重写) - /// - public virtual RelayCommand SaveCommand => new RelayCommand(() => - { - - }); - - - #endregion - - /// - /// BaseCRUDVM中的数据初始化,生命周期落后于InitData() - /// - protected virtual void BaseCRUDInit() - { - - } - } -} diff --git a/Vampirewal.Core/SimpleMVVM/BaseListVM.cs b/Vampirewal.Core/SimpleMVVM/BaseListVM.cs deleted file mode 100644 index bc67a7592279f86bf86169a9ab35d6d890523a4f..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/SimpleMVVM/BaseListVM.cs +++ /dev/null @@ -1,1151 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:BaseListVM -// 创 建 者:杨程 -// 创建时间:2021/9/16 13:32:07 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations.Schema; -using System.Data.Common; -using System.Data; -using System.IO; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; -using NPOI.HSSF.Util; -using NPOI.SS.UserModel; -using NPOI.SS.Util; -using NPOI.XSSF.UserModel; -using Vampirewal.Core.Extensions; -using Vampirewal.Core.Helper; -using Vampirewal.Core.Interface; -using Vampirewal.Core.Models; -using System.Text.Json.Serialization; - -namespace Vampirewal.Core.SimpleMVVM -{ - /// - /// ListVM的基类,所有ListVM应该继承这个类, 基类提供了搜索,导出等列表常用功能 - /// - /// ListVM中的Model类 - /// ListVM使用的Searcher类 - public class BaseListVM : ViewModelBase, IBaseListVM - where TModel : TopBaseModel - where TSearcher : BaseSearcher - { - [JsonIgnore] - public string TotalText { get; set; } - - public virtual DbCommand GetSearchCommand() - { - return null; - } - - - - #region GenerateExcel - - - - /// - /// 根据集合生成单个Excel - /// - /// - /// - //private IWorkbook GenerateWorkBook(List List) - //{ - // IWorkbook book = new XSSFWorkbook(); - // ISheet sheet = book.CreateSheet(); - // IRow row = sheet.CreateRow(0); - - // //创建表头样式 - // ICellStyle headerStyle = book.CreateCellStyle(); - // headerStyle.FillBackgroundColor = ExportTitleBackColor == null ? HSSFColor.LightBlue.Index : ExportTitleBackColor.Value; - // headerStyle.FillPattern = FillPattern.SolidForeground; - // headerStyle.FillForegroundColor = ExportTitleBackColor == null ? HSSFColor.LightBlue.Index : ExportTitleBackColor.Value; - // headerStyle.BorderBottom = BorderStyle.Thin; - // headerStyle.BorderTop = BorderStyle.Thin; - // headerStyle.BorderLeft = BorderStyle.Thin; - // headerStyle.BorderRight = BorderStyle.Thin; - // IFont font = book.CreateFont(); - // font.FontName = "Calibri"; - // font.FontHeightInPoints = 12; - // font.Color = ExportTitleFontColor == null ? HSSFColor.Black.Index : ExportTitleFontColor.Value; - // headerStyle.SetFont(font); - - // ICellStyle cellStyle = book.CreateCellStyle(); - // cellStyle.BorderBottom = BorderStyle.Thin; - // cellStyle.BorderTop = BorderStyle.Thin; - // cellStyle.BorderLeft = BorderStyle.Thin; - // cellStyle.BorderRight = BorderStyle.Thin; - - // //生成表头 - // int max = MakeExcelHeader(sheet, GridHeaders, 0, 0, headerStyle); - - // //放入数据 - // var ColIndex = 0; - // for (int i = 0; i < List.Count; i++) - // { - // ColIndex = 0; - // var DR = sheet.CreateRow(i + max); - // foreach (var baseCol in GridHeaders) - // { - - // foreach (var col in baseCol.BottomChildren) - // { - // //处理枚举变量的多语言 - // bool IsEmunBoolParp = false; - // var proType = col.FieldType; - // if (proType.IsEnumOrNullableEnum()) - // { - // IsEmunBoolParp = true; - // } - // //获取数据,并过滤特殊字符 - // string text = Regex.Replace(col.GetText(List[i]).ToString(), @"<[^>]*>", String.Empty); - - // //处理枚举变量的多语言 - // if (IsEmunBoolParp) - // { - // if (int.TryParse(text, out int enumvalue)) - // { - // text = PropertyHelper.GetEnumDisplayName(proType, enumvalue); - // } - // } - - // //建立excel单元格 - // ICell cell; - // if (col.FieldType?.IsNumber() == true) - // { - // cell = DR.CreateCell(ColIndex, CellType.Numeric); - // try - // { - // cell.SetCellValue(Convert.ToDouble(text)); - // } - // catch { } - // } - // else - // { - // cell = DR.CreateCell(ColIndex); - // cell.SetCellValue(text); - // } - // cell.CellStyle = cellStyle; - // ColIndex++; - // } - // } - // } - // return book; - //} - - //private byte[] DownLoadExcel() - //{ - // var book = GenerateWorkBook(EntityList); - // byte[] rv = new byte[] { }; - // using (MemoryStream ms = new MemoryStream()) - // { - // book.Write(ms); - // rv = ms.ToArray(); - // } - // return rv; - //} - - //private byte[] DownLoadZipPackage(string FileName) - //{ - // //文件根目录 - // string RootPath = $"{GlobalServices.GetRequiredService().WebRootPath}\\{FileName}"; - - // //文件夹目录 - // string FilePath = $"{RootPath}//FileFolder"; - - // //压缩包目录 - // string ZipPath = $"{RootPath}//{FileName}.zip"; - - // //打开文件夹 - // DirectoryInfo FileFolder = new DirectoryInfo(FilePath); - // if (!FileFolder.Exists) - // { - // //创建文件夹 - // FileFolder.Create(); - // } - // else - // { - // //清空文件夹 - // FileSystemInfo[] Files = FileFolder.GetFileSystemInfos(); - // foreach (var item in Files) - // { - // if (item is DirectoryInfo) - // { - // DirectoryInfo Directory = new DirectoryInfo(item.FullName); - // Directory.Delete(true); - // } - // else - // { - // File.Delete(item.FullName); - // } - // } - // } - - // //放入数据 - // for (int i = 0; i < ExportExcelCount; i++) - // { - // var List = EntityList.Skip(i * ExportMaxCount).Take(ExportMaxCount).ToList(); - // var WorkBook = GenerateWorkBook(List); - // string SavePath = $"{FilePath}/{FileName}_{i + 1}.xlsx"; - // using (FileStream FS = new FileStream(SavePath, FileMode.CreateNew)) - // { - // WorkBook.Write(FS); - // } - // } - - // //生成压缩包 - // ZipFile.CreateFromDirectory(FilePath, ZipPath); - - // //读取压缩包 - // FileStream ZipFS = new FileStream(ZipPath, FileMode.Open, FileAccess.Read); - // byte[] bt = new byte[ZipFS.Length]; - // ZipFS.Read(bt, 0, bt.Length); - // ZipFS.Close(); - - // //删除根目录文件夹 - // DirectoryInfo RootFolder = new DirectoryInfo(RootPath); - // if (RootFolder.Exists) - // { - // RootFolder.Delete(true); - // } - - // return bt; - //} - - /// - /// 生成Excel的表头 - /// - /// - /// - /// - /// - /// - /// - //private int MakeExcelHeader(ISheet sheet, IEnumerable> cols, int rowIndex, int colIndex, ICellStyle style) - //{ - // var row = sheet.GetRow(rowIndex); - // if (row == null) - // { - // row = sheet.CreateRow(rowIndex); - // } - // int maxLevel = cols.Select(x => x.MaxLevel).Max(); - // //循环所有列 - // foreach (var col in cols) - // { - // //添加新单元格 - // var cell = row.CreateCell(colIndex); - // cell.CellStyle = style; - // cell.SetCellValue(col.Title); - // var bcount = col.BottomChildren.Count(); - // var rowspan = 0; - // if (rowIndex >= 0) - // { - // rowspan = maxLevel - col.MaxLevel; - // } - // var cellRangeAddress = new CellRangeAddress(rowIndex, rowIndex + rowspan, colIndex, colIndex + bcount - 1); - // sheet.AddMergedRegion(cellRangeAddress); - // if (rowspan > 0 || bcount > 1) - // { - // cell.CellStyle.Alignment = HorizontalAlignment.Center; - // cell.CellStyle.VerticalAlignment = VerticalAlignment.Center; - // } - // for (int i = cellRangeAddress.FirstRow; i <= cellRangeAddress.LastRow; i++) - // { - // IRow r = CellUtil.GetRow(i, sheet); - // for (int j = cellRangeAddress.FirstColumn; j <= cellRangeAddress.LastColumn; j++) - // { - // ICell c = CellUtil.GetCell(r, (short)j); - // c.CellStyle = style; - // } - // } - // if (col.Children != null && col.Children.Count() > 0) - // { - // MakeExcelHeader(sheet, col.Children, rowIndex + rowspan + 1, colIndex, style); - // } - // colIndex += bcount; - // } - // return maxLevel; - //} - - #endregion - - #region Old - public SortInfo CreateSortInfo(Expression> pro, SortDir dir) - { - SortInfo rv = new SortInfo - { - Property = PropertyHelper.GetPropertyName(pro), - Direction = dir - }; - return rv; - } - - /// - /// InitList后触发的事件 - /// - public event Action> OnAfterInitList; - - /// - ///记录批量操作时列表中选择的Id - /// - public List Ids { get; set; } - - /// - /// 每页行数 - /// - [Obsolete("弃用,改用 DataTableHelper上的Limit")] - public int RecordsPerPage { get; set; } - - /// - /// 是否已经搜索过 - /// - [JsonIgnore] - public bool IsSearched { get; set; } - - [JsonIgnore] - public bool PassSearch { get; set; } - /// - /// 查询模式 - /// - [JsonIgnore] - public ListVMSearchModeEnum SearcherMode { get; set; } - - /// - /// 是否需要分页 - /// - [JsonIgnore] - public bool NeedPage { get; set; } - - /// - /// 允许导出Excel的最大行数,超过行数会分成多个文件,最多不能超过100万 - /// - [JsonIgnore] - public int ExportMaxCount { get; set; } - - /// - /// 根据允许导出的Excel最大行数,算出最终导出的Excel个数 - /// - [JsonIgnore] - public int ExportExcelCount { get; set; } - - /// - /// 导出文件第一行背景颜色,使用HSSFColor,例如:HSSFColor.Red.Index - /// - [JsonIgnore] - public short? ExportTitleBackColor { get; set; } - - /// - /// 导出文件第一行文字颜色,使用HSSFColor,例如:HSSFColor.Red.Index - /// - [JsonIgnore] - public short? ExportTitleFontColor { get; set; } - - private List _EntityList; - /// - /// 数据列表 - /// - [JsonIgnore] - public List EntityList - { - get - { - return _EntityList; - } - set - { - _EntityList = value; - DoNotify(); - } - } - - - /// - /// 搜索条件 - /// - [JsonIgnore] - public TSearcher Searcher { get; set; } - - /// - /// 使用 VM 的 Id 来生成 SearcherDiv 的 Id - /// - [JsonIgnore] - public string SearcherDivId - { - get { return Guid.NewGuid().ToString() + "Searcher"; } - } - - - /// - /// 替换查询条件,如果被赋值,则列表会使用里面的Lambda来替换原有Query里面的Where条件 - /// - [JsonIgnore()] - public Expression> ReplaceWhere { get; set; } - - /// - /// 构造函数 - /// - public BaseListVM() - { - //默认需要分页 - NeedPage = true; - //初始化数据列表 - EntityList = new List(); - //初始化搜索条件 - Searcher = typeof(TSearcher).GetConstructor(Type.EmptyTypes).Invoke(null) as TSearcher; - } - - /// - /// 获取数据列表 - /// - /// 数据列表 - public IEnumerable GetEntityList() - { - if (IsSearched == false && (EntityList == null || EntityList.Count == 0)) - { - DoSearch(); - } - return EntityList?.AsEnumerable(); - } - - - /// - /// 调用InitListVM并触发OnAfterInitList事件 - /// - public void DoInitListVM() - { - InitListVM(); - OnAfterInitList?.Invoke(this); - } - - - /// - /// 初始化ListVM,继承的类应该重载这个函数来设定数据的列和动作 - /// - protected virtual void InitListVM() - { - - } - - public virtual bool GetIsSelected(object item) - { - return false; - } - - public void Validate() - { - Searcher?.Validate(); - //base.Validate(); - } - - /// - /// 设定行前景色,继承的类应重载这个函数来根据每行的数据显示不同的前景色 - /// - /// 数据 - /// 前景颜色 - public virtual string SetFullRowColor(object entity) - { - return ""; - } - - /// - /// 设定行背景色,继承的类应重载这个函数来根据每行的数据显示不同的背景色 - /// - /// 数据 - /// 背景颜色 - public virtual string SetFullRowBgColor(object entity) - { - return ""; - } - - /// - /// 设定搜索语句,继承的类应该重载这个函数来指定自己的搜索语句 - /// - /// 搜索语句 - public virtual IOrderedQueryable GetSearchQuery() - { - return DC.Set().OrderByDescending(x => x.ID); - } - - /// - /// 设定导出时搜索语句,继承的类应该重载这个函数来指定自己导出时的搜索语句,如不指定则默认和搜索用的搜索语句相同 - /// - /// 搜索语句 - public virtual IOrderedQueryable GetExportQuery() - { - return GetSearchQuery(); - } - - /// - /// 设定搜索语句,继承的类应该重载这个函数来指定自己导出时的搜索语句,如不指定则默认和搜索用的搜索语句相同 - /// - /// 搜索语句 - public virtual IOrderedQueryable GetSelectorQuery() - { - return GetSearchQuery(); - } - - /// - /// 设定勾选后导出的搜索语句,继承的类应该重载这个函数来指定自己导出时的搜索语句,如不指定则默认和搜索用的搜索语句相同 - /// - /// 搜索语句 - public virtual IOrderedQueryable GetCheckedExportQuery() - { - var baseQuery = GetBatchQuery(); - return baseQuery; - } - - /// - /// 设定批量模式下的搜索语句,继承的类应重载这个函数来指定自己批量模式的搜索语句,如果不指定则默认使用Ids.Contains(x.Id)来代替搜索语句中的Where条件 - /// - /// 搜索语句 - public virtual IOrderedQueryable GetBatchQuery() - { - var baseQuery = GetSearchQuery(); - if (ReplaceWhere == null) - { - var mod = new WhereReplaceModifier(Ids.GetContainIdExpression()); - var newExp = mod.Modify(baseQuery.Expression); - var newQuery = baseQuery.Provider.CreateQuery(newExp) as IOrderedQueryable; - return newQuery; - } - else - { - return baseQuery; - } - } - - /// - /// 设定主从模式的搜索语句,继承的类应该重载这个函数来指定自己主从模式的搜索语句,如不指定则默认和搜索用的搜索语句相同 - /// - /// 搜索语句 - public virtual IOrderedQueryable GetMasterDetailsQuery() - { - return GetSearchQuery(); - } - - /// - /// 进行搜索 - /// - public virtual void DoSearch() - { - var cmd = GetSearchCommand(); - if (cmd == null) - { - IOrderedQueryable query = null; - //根据搜索模式调用不同的函数 - switch (SearcherMode) - { - case ListVMSearchModeEnum.Search: - query = GetSearchQuery(); - break; - case ListVMSearchModeEnum.Export: - query = GetExportQuery(); - break; - case ListVMSearchModeEnum.Batch: - query = GetBatchQuery(); - break; - case ListVMSearchModeEnum.MasterDetail: - query = GetMasterDetailsQuery(); - break; - case ListVMSearchModeEnum.CheckExport: - query = GetCheckedExportQuery(); - break; - case ListVMSearchModeEnum.Selector: - query = GetSelectorQuery(); - break; - default: - query = GetSearchQuery(); - break; - } - - //如果设定了替换条件,则使用替换条件替换Query中的Where语句 - if (ReplaceWhere != null) - { - var mod = new WhereReplaceModifier(ReplaceWhere); - var newExp = mod.Modify(query.Expression); - query = query.Provider.CreateQuery(newExp) as IOrderedQueryable; - } - if (Searcher.SortInfo != null) - { - var mod = new OrderReplaceModifier(Searcher.SortInfo); - var newExp = mod.Modify(query.Expression); - query = query.Provider.CreateQuery(newExp) as IOrderedQueryable; - } - if (typeof(TModel).IsSubclassOf(typeof(PersistModel))) - { - var mod = new IsValidModifier(); - var newExp = mod.Modify(query.Expression); - query = query.Provider.CreateQuery(newExp) as IOrderedQueryable; - } - if (PassSearch == false) - { - //如果需要分页,则添加分页语句 - if (NeedPage && Searcher.Limit != -1) - { - //获取返回数据的数量 - var count = query.Count(); - if (count < 0) - { - count = 0; - } - if (Searcher.Limit == 0) - { - //TODO 暂时没有配置文件来进行获取,进行动态设置 - //Searcher.Limit = ConfigInfo?.UiOptions.DataTable.RPP ?? 20; - Searcher.Limit = 20; - } - //根据返回数据的数量,以及预先设定的每页行数来设定数据量和总页数 - Searcher.Count = count; - Searcher.PageCount = (int)Math.Ceiling((1.0 * Searcher.Count / Searcher.Limit)); - if (Searcher.Page <= 0) - { - Searcher.Page = 1; - } - if (Searcher.PageCount > 0 && Searcher.Page > Searcher.PageCount) - { - Searcher.Page = Searcher.PageCount; - } - EntityList = query.Skip((Searcher.Page - 1) * Searcher.Limit).Take(Searcher.Limit).AsNoTracking().ToList(); - } - else //如果不需要分页则直接获取数据 - { - EntityList = query.AsNoTracking().ToList(); - Searcher.Count = EntityList.Count(); - Searcher.Limit = EntityList.Count(); - Searcher.PageCount = 1; - Searcher.Page = 1; - } - } - else - { - EntityList = query.AsNoTracking().ToList(); - } - } - else - { - ProcessCommand(cmd); - } - IsSearched = true; - //调用AfterDoSearch函数来处理自定义的后续操作 - AfterDoSearcher(); - } - - - private void ProcessCommand(DbCommand cmd) - { - object total; - - if (Searcher.Page <= 0) - { - Searcher.Page = 1; - } - //if (DC.Database.IsMySql()) - //{ - // List parms = new List(); - // foreach (MySqlParameter item in cmd.Parameters) - // { - // parms.Add(new MySqlParameter(string.Format("@{0}", item.ParameterName), item.Value)); - // } - // if (cmd.CommandType == CommandType.StoredProcedure) - // { - // parms.Add(new MySqlParameter("@SearchMode", Enum.GetName(typeof(ListVMSearchModeEnum), SearcherMode))); - // parms.Add(new MySqlParameter("@NeedPage", (NeedPage && Searcher.Limit != -1))); - // parms.Add(new MySqlParameter("@CurrentPage", Searcher.Page)); - // parms.Add(new MySqlParameter("@RecordsPerPage", Searcher.Limit)); - // parms.Add(new MySqlParameter("@Sort", Searcher.SortInfo?.Property)); - // parms.Add(new MySqlParameter("@SortDir", Searcher.SortInfo?.Direction)); - // parms.Add(new MySqlParameter("@IDs", Ids == null ? "" : Ids.ToSpratedString())); - - // MySqlParameter outp = new MySqlParameter("@TotalRecords", MySqlDbType.Int64) - // { - // Value = 0, - // Direction = ParameterDirection.Output - // }; - // parms.Add(outp); - // } - // var pa = parms.ToArray(); - - // EntityList = DC.Run(cmd.CommandText, cmd.CommandType, pa).ToList(); - // if (cmd.CommandType == CommandType.StoredProcedure) - // { - // total = pa.Last().Value; - // } - // else - // { - // total = EntityList.Count; - // } - //} - //else if (DC.Database.IsNpgsql()) - //{ - // List parms = new List(); - // foreach (NpgsqlParameter item in cmd.Parameters) - // { - // parms.Add(new NpgsqlParameter(string.Format("@{0}", item.ParameterName), item.Value)); - // } - - // if (cmd.CommandType == CommandType.StoredProcedure) - // { - // parms.Add(new NpgsqlParameter("@SearchMode", Enum.GetName(typeof(ListVMSearchModeEnum), SearcherMode))); - // parms.Add(new NpgsqlParameter("@NeedPage", (NeedPage && Searcher.Limit != -1))); - // parms.Add(new NpgsqlParameter("@CurrentPage", Searcher.Page)); - // parms.Add(new NpgsqlParameter("@RecordsPerPage", Searcher.Limit)); - // parms.Add(new NpgsqlParameter("@Sort", Searcher.SortInfo?.Property)); - // parms.Add(new NpgsqlParameter("@SortDir", Searcher.SortInfo?.Direction)); - // parms.Add(new NpgsqlParameter("@IDs", Ids == null ? "" : Ids.ToSpratedString())); - - // NpgsqlParameter outp = new NpgsqlParameter("@TotalRecords", NpgsqlDbType.Bigint) - // { - // Value = 0, - // Direction = ParameterDirection.Output - // }; - // parms.Add(outp); - // } - // var pa = parms.ToArray(); - - // EntityList = DC.Run(cmd.CommandText, cmd.CommandType, pa).ToList(); - // if (cmd.CommandType == CommandType.StoredProcedure) - // { - // total = pa.Last().Value; - // } - // else - // { - // total = EntityList.Count; - // } - //} - //else - //{ - // List parms = new List(); - // foreach (SqlParameter item in cmd.Parameters) - // { - // parms.Add(new SqlParameter(string.Format("@{0}", item.ParameterName), item.Value)); - // } - // if (cmd.CommandType == CommandType.StoredProcedure) - // { - - // parms.Add(new SqlParameter("@SearchMode", Enum.GetName(typeof(ListVMSearchModeEnum), SearcherMode))); - // parms.Add(new SqlParameter("@NeedPage", (NeedPage && Searcher.Limit != -1))); - // parms.Add(new SqlParameter("@CurrentPage", Searcher.Page)); - // parms.Add(new SqlParameter("@RecordsPerPage", Searcher.Limit)); - // parms.Add(new SqlParameter("@Sort", Searcher.SortInfo?.Property)); - // parms.Add(new SqlParameter("@SortDir", Searcher.SortInfo?.Direction)); - // parms.Add(new SqlParameter("@IDs", Ids == null ? "" : Ids.ToSpratedString())); - - // SqlParameter outp = new SqlParameter("@TotalRecords", 0) - // { - // Direction = ParameterDirection.Output - // }; - // parms.Add(outp); - // } - // var pa = parms.ToArray(); - - // EntityList = DC.Run(cmd.CommandText, cmd.CommandType, pa).ToList(); - // if (cmd.CommandType == CommandType.StoredProcedure) - // { - // total = pa.Last().Value; - // } - // else - // { - // total = EntityList.Count; - // } - - //} - //if (NeedPage && Searcher.Limit != -1) - //{ - // if (total != null) - // { - // try - // { - // Searcher.Count = long.Parse(total.ToString()); - // Searcher.PageCount = (int)((Searcher.Count - 1) / Searcher.Limit + 1); - // } - // catch { } - // } - //} - //else - //{ - // Searcher.PageCount = EntityList.Count; - //} - - } - - public DateTime AddTime(DateTime dt, string type, int size) - { - switch (type) - { - case "year": - return dt.AddYears(size); - case "month": - return dt.AddMonths(size); - case "day": - return dt.AddDays(size); - case "hour": - return dt.AddHours(size); - case "minute": - return dt.AddMinutes(size); - case "second": - return dt.AddSeconds(size); - default: - return dt; - } - } - - /// - /// 搜索后运行的函数,继承的类如果需要在搜索结束后进行其他操作,可重载这个函数 - /// - public virtual void AfterDoSearcher() - { - if (SearcherMode == ListVMSearchModeEnum.Selector && Ids != null && Ids.Count > 0 && EntityList != null && EntityList.Count > 0) - { - foreach (var item in EntityList) - { - var id = item.GetID(); - if (Ids.Contains(id.ToString())) - { - item.Checked = true; - } - } - } - } - - /// - /// 删除所有ActionGridColumn的列 - /// - public void RemoveActionColumn(object root = null) - { - //if (root == null) - //{ - // if (GridHeaders == null) - // { - // GetHeaders(); - // } - // root = GridHeaders; - //} - //if (root != null) - //{ - // //IEnumerable> - // var aroot = root as List>; - // var toRemove = aroot.Where(x => x.ColumnType == GridColumnTypeEnum.Action).FirstOrDefault(); - // aroot.Remove(toRemove); - // foreach (var child in aroot) - // { - // if (child.Children != null && child.Children.Count() > 0) - // { - // RemoveActionColumn(child.Children); - // } - // } - //} - } - - public void RemoveAction() - { - //_gridActions = new List(); - } - - //public void RemoveActionAndIdColumn(IEnumerable> root = null) - //{ - // if (root == null) - // { - // if (GridHeaders == null) - // { - // GetHeaders(); - // } - // root = GridHeaders; - // } - // if (root != null) - // { - // var aroot = root as List>; - // List> remove = null; - // var idpro = typeof(TModel).GetProperties().Where(x => x.Name.ToLower() == "id").Select(x => x.PropertyType).FirstOrDefault(); - // if (idpro == typeof(string)) - // { - // remove = aroot.Where(x => x.ColumnType == GridColumnTypeEnum.Action || x.Hide == true || x.DisableExport).ToList(); - // } - // else - // { - // remove = aroot.Where(x => x.ColumnType == GridColumnTypeEnum.Action || x.Hide == true || x.DisableExport || x.FieldName?.ToLower() == "id").ToList(); - // } - // foreach (var item in remove) - // { - // aroot.Remove(item); - // } - // foreach (var child in root) - // { - // if (child.Children != null && child.Children.Count() > 0) - // { - // RemoveActionAndIdColumn(child.Children); - // } - // } - // } - //} - - - /// - /// 添加Error列,主要为批量模式使用 - /// - //public void AddErrorColumn() - //{ - // GetHeaders(); - // //寻找所有Header为错误信息的列,如果没有则添加 - // if (GridHeaders.Where(x => x.Field == "BatchError").FirstOrDefault() == null) - // { - // var temp = GridHeaders as List>; - // if (temp.Where(x => x.ColumnType == GridColumnTypeEnum.Action).FirstOrDefault() == null) - // { - // temp.Add(this.MakeGridColumn(x => x.BatchError, Width: 200, Header: Core.Program._localizer["Error"]).SetForeGroundFunc(x => "ff0000")); - // } - // else - // { - // temp.Insert(temp.Count - 1, this.MakeGridColumn(x => x.BatchError, Width: 200, Header: Core.Program._localizer["Error"]).SetForeGroundFunc(x => "ff0000")); - // } - // } - //} - - //public void ProcessListError(List Entities) - //{ - // if (Entities == null) - // { - // return; - // } - // EntityList = Entities; - // IsSearched = true; - // bool haserror = false; - // List keys = new List(); - // if (string.IsNullOrEmpty(DetailGridPrix) == false) - // { - // foreach (var item in MSD.Keys) - // { - // if (item.StartsWith(DetailGridPrix)) - // { - // var errors = MSD[item]; - // if (errors.Count > 0) - // { - // Regex r = new Regex($"{DetailGridPrix}\\[(.*?)\\]"); - // try - // { - // if (int.TryParse(r.Match(item).Groups[1].Value, out int index)) - // { - // EntityList[index].BatchError = errors.Select(x => x.ErrorMessage).ToSpratedString(); - // keys.Add(item); - // haserror = true; - // } - // } - // catch { } - // } - // } - // } - // foreach (var item in keys) - // { - // //MSD.RemoveModelError(item); - // } - // if (haserror) - // { - // AddErrorColumn(); - // } - // } - //} - - public TModel CreateEmptyEntity() - { - return typeof(TModel).GetConstructor(Type.EmptyTypes).Invoke(null) as TModel; - } - - public void ClearEntityList() - { - EntityList?.Clear(); - } - - public string DetailGridPrix { get; set; } - - #endregion - - public virtual void UpdateEntityList(bool updateAllFields = false) - { - if (EntityList != null) - { - var ftype = EntityList.GetType().GenericTypeArguments.First(); - PropertyInfo[] itemPros = ftype.GetProperties(); - - foreach (var newitem in EntityList) - { - var subtype = newitem.GetType(); - if (subtype.IsSubclassOf(typeof(BaseModel))) - { - BaseModel ent = newitem as BaseModel; - if (ent.UpdateTime == null) - { - ent.UpdateTime = DateTime.Now; - } - if (string.IsNullOrEmpty(ent.UpdateBy)) - { - ent.UpdateBy = loginUserInfo?.ITCode; - } - } - //循环页面传过来的子表数据,将关联到TopBaseModel的字段设为null,并且把外键字段的值设定为主表ID - foreach (var itempro in itemPros) - { - if (itempro.PropertyType.IsSubclassOf(typeof(TopBaseModel))) - { - itempro.SetValue(newitem, null); - } - } - } - - IEnumerable data = null; - //打开新的数据库联接,获取数据库中的主表和子表数据 - using (var ndc = DC.CreateNew()) - { - var ids = EntityList.Select(x => x.GetID().ToString()).ToList(); - data = ndc.Set().AsNoTracking().Where(ids.GetContainIdExpression()).ToList(); - } - //比较子表原数据和新数据的区别 - IEnumerable toadd = null; - IEnumerable toremove = null; - Utils.CheckDifference(data, EntityList, out toremove, out toadd); - //设定子表应该更新的字段 - List setnames = new List(); - //foreach (var field in FC.Keys) - //{ - // if (field.StartsWith("EntityList[0].")) - // { - // string name = field.Replace("EntityList[0].", ""); - // setnames.Add(name); - // } - //} - - //前台传过来的数据 - foreach (var newitem in EntityList) - { - //数据库中的数据 - foreach (var item in data) - { - //需要更新的数据 - if (newitem.GetID().ToString() == item.GetID().ToString()) - { - dynamic i = newitem; - var newitemType = item.GetType(); - foreach (var itempro in itemPros) - { - if (!itempro.PropertyType.IsSubclassOf(typeof(TopBaseModel)) && (updateAllFields == true || setnames.Contains(itempro.Name))) - { - var notmapped = itempro.GetCustomAttribute(); - if (itempro.Name != "ID" && notmapped == null && itempro.PropertyType.IsList() == false) - { - DC.UpdateProperty(i, itempro.Name); - } - } - } - if (item.GetType().IsSubclassOf(typeof(BaseModel))) - { - DC.UpdateProperty(i, "UpdateTime"); - DC.UpdateProperty(i, "UpdateBy"); - } - } - } - } - //需要删除的数据 - foreach (var item in toremove) - { - //如果是PersistModel,则把IsValid设为false,并不进行物理删除 - if (ftype.IsSubclassOf(typeof(PersistModel))) - { - (item as PersistModel).IsValid = false; - (item as PersistModel).UpdateTime = DateTime.Now; - (item as PersistModel).UpdateBy = loginUserInfo?.ITCode; - dynamic i = item; - DC.UpdateEntity(i); - } - else - { - foreach (var itempro in itemPros) - { - if (itempro.PropertyType.IsSubclassOf(typeof(TopBaseModel))) - { - itempro.SetValue(item, null); - } - } - dynamic i = item; - DC.DeleteEntity(i); - } - } - //需要添加的数据 - foreach (var item in toadd) - { - if (item.GetType().IsSubclassOf(typeof(BaseModel))) - { - BaseModel ent = item as BaseModel; - if (ent.CreateTime == null) - { - ent.CreateTime = DateTime.Now; - } - if (string.IsNullOrEmpty(ent.CreateBy)) - { - ent.CreateBy = loginUserInfo?.ITCode; - } - } - DC.AddEntity(item); - - - } - - DC.SaveChanges(); - } - } - - public byte[] GenerateExcel() - { - return default; - } - - public void CopyContext(IBaseVM vm) - { - - } - - /// - /// 批量删除 - /// - public void DoBatchDelete() - { - var SelectEntity = EntityList.Where(w => w.Checked); - if (SelectEntity.Count()>0) - { - var ftype = EntityList.GetType().GenericTypeArguments.First(); - - foreach (TModel item in SelectEntity) - { - //如果是PersistModel,则把IsValid设为false,并不进行物理删除 - if (ftype.IsSubclassOf(typeof(PersistModel))) - { - (item as PersistModel).IsValid = false; - (item as PersistModel).UpdateTime = DateTime.Now; - (item as PersistModel).UpdateBy = loginUserInfo?.ITCode; - dynamic i = item; - DC.UpdateEntity(i); - } - else - { - - dynamic i = item; - DC.DeleteEntity(i); - } - } - } - - } - } -} diff --git a/Vampirewal.Core/SimpleMVVM/BaseSearcher.cs b/Vampirewal.Core/SimpleMVVM/BaseSearcher.cs deleted file mode 100644 index 941e248c875a05b73a372147b7a406a88a1010a5..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/SimpleMVVM/BaseSearcher.cs +++ /dev/null @@ -1,189 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:BaseSearcher -// 创 建 者:杨程 -// 创建时间:2021/9/16 13:34:45 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Text; -using System.Text.Json.Serialization; -using System.Threading.Tasks; -using Vampirewal.Core.Interface; -using Vampirewal.Core.Models; - -namespace Vampirewal.Core.SimpleMVVM -{ - public class BaseSearcher : ISearcher - { - #region Property - - #region 分页相关 - /// - /// 当前页 - /// - public int Page { get; set; } - /// - /// 每页数 - /// - public int Limit { get; set; } - /// - /// 记录数 - /// - public long Count { get; set; } - /// - /// 分页数 - /// - public int PageCount { get; set; } - #endregion - - /// - /// 记录 Controller 中的表单数据 - /// - [JsonIgnore] - public Dictionary FC { get; set; } - - - /// - /// 获取VM的全名 - /// - [JsonIgnore] - public string VMFullName - { - get - { - var name = GetType().AssemblyQualifiedName; - name = name.Substring(0, name.LastIndexOf(", Version=")); - return name; - } - } - - /// - /// 数据库环境 - /// - [JsonIgnore] - public IDataContext DC { get; set; } - - - /// - /// 当前登录人信息 - /// - [JsonIgnore] - public LoginUserInfo LoginUserInfo { get; set; } - - #region 未使用 - /// - /// 排序信息 - /// - public SortInfo SortInfo { get; set; } - /// - /// 是否搜索树形结构数据 - /// - [JsonIgnore] - public bool TreeMode { get; set; } - /// - /// 树形结构数据父Id - /// - [JsonIgnore] - public Guid? ParentId { get; set; } - /// - /// 是否有效,针对继承PersistPoco的Model - /// - [Display(Name = "IsValid")] - [JsonIgnore] - public bool? IsValid { get; set; } - /// - /// 用于框架判断列表页是否全局刷新 - /// - [JsonIgnore] - public bool IsPostBack { get; set; } - - /// - /// 前台搜索框是否展开 - /// - [JsonIgnore] - public bool? IsExpanded { get; set; } - - #endregion - - #endregion - - #region Event - - /// - /// InitVM 完成后触发的事件 - /// - public event Action OnAfterInit; - /// - /// ReInitVM 完成后触发的事件 - /// - public event Action OnAfterReInit; - - #endregion - - #region Method - - /// - /// 调用 InitVM 并触发 OnAfterInit 事件 - /// - public void DoInit() - { - InitVM(); - OnAfterInit?.Invoke(this); - } - - /// - /// 调用 ReInitVM 并触发 OnAfterReInit 事件 - /// - public void DoReInit() - { - ReInitVM(); - OnAfterReInit?.Invoke(this); - } - - /// - /// 初始化ViewModel,框架会在创建VM实例之后自动调用本函数 - /// - protected virtual void InitVM() - { - } - - /// - /// 从新初始化ViewModel,框架会在验证失败时自动调用本函数 - /// - protected virtual void ReInitVM() - { - InitVM(); - } - - public virtual void Validate() - { - - } - /// - /// 将源 VM 的 FC 等内容复制到本VM中 - /// - /// - public void CopyContext(ViewModelBase vm) - { - //FC = vm.FC; - this.DC = vm.DC; - //this.Session = vm.Session; - this.LoginUserInfo = vm.loginUserInfo; - //this.MSD = vm.MSD; - //var CurrentCS = vm.CurrentCS; - //var CreatorAssembly = vm.CreatorAssembly; - } - - #endregion - } -} diff --git a/Vampirewal.Core/SimpleMVVM/BaseVM.cs b/Vampirewal.Core/SimpleMVVM/BaseVM.cs deleted file mode 100644 index 25735dc2eab1f8faee9a7d88bf43506e3f2549e3..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/SimpleMVVM/BaseVM.cs +++ /dev/null @@ -1,123 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:BaseVM -// 创 建 者:杨程 -// 创建时间:2021/9/16 14:15:05 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using Vampirewal.Core.Interface; -using Vampirewal.Core.Models; - -namespace Vampirewal.Core.SimpleMVVM -{ - /// - /// VM的基类 - /// - public class BaseVM:NotifyBase,IBaseVM - { - - public BaseVM() - { - //构造函数 - InitData(); - MessengerRegister(); - } - - - /// - /// VMId - /// - public string VMId - { - get - { - return Guid.NewGuid().ToString(); - } - } - - /// - /// 标题 - /// - public string Title { get; set; } = "未命名窗体"; - - /// - /// 绑定的窗体 - /// - public FrameworkElement View { get ; set ; } - - /// - /// 数据库操作 - /// - public IDataContext DC { get ; set ; } - - /// - /// 当前登陆人员 - /// - public LoginUserInfo loginUserInfo { get; set ; } - - /// - /// 将VM内的一些内容复制到这个VM中 - /// - /// - public void CopyVM(IBaseVM self) - { - loginUserInfo = self.loginUserInfo; - DC = self.DC; - } - - /// - /// 当窗体是DialogShow的方式打开的时候,可以通过重写这个方法,将值传回主窗体 - /// - /// - public virtual object GetResult() - { - return null; - } - - /// - /// 初始化页面数据,由ViewModelBase的构造函数调用,重写后不用再调用 - /// - public virtual void InitData() - { - - } - - /// - /// 通用消息注册 - /// - public void MessengerRegister() - { - - } - - /// - /// 初始化页面数据,由创建时传递参数 - /// - /// 传入参数 - public void PassData(object obj) - { - - } - - /// - /// UI线程调用 - /// - /// - public void UIInvoke(Action action) - { - this.View?.Dispatcher.Invoke(action); - } - } -} diff --git a/Vampirewal.Core/SimpleMVVM/BillListBaseVM.cs b/Vampirewal.Core/SimpleMVVM/BillListBaseVM.cs new file mode 100644 index 0000000000000000000000000000000000000000..59127cc7df1a4406bf0440da7fc6227862262c36 --- /dev/null +++ b/Vampirewal.Core/SimpleMVVM/BillListBaseVM.cs @@ -0,0 +1,333 @@ +#region << 文 件 说 明 >> + +/*---------------------------------------------------------------- +// 文件名称:BillListBaseVM +// 创 建 者:杨程 +// 创建时间:2022/2/9 19:48:54 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ + +#endregion + +namespace Vampirewal.Core.SimpleMVVM; + +/// +/// 列表查询VM基类 +/// +/// 弹窗实体模型 +/// 列表模型 +public abstract partial class BillListBaseVM : ViewModelBase + where TBillEntity : BillBaseModel, new() + where TSearchEntity : ObservableObject, new() +{ + /// + /// 弹窗服务 + /// + protected IVampirewalCoreDialogMessage Dialog { get; set; } + + /// + /// 实体模型数据库 + /// + protected SqlSugarRepository RepBill { get; set; } + + /// + /// 列表模型数据库 + /// + protected SqlSugarRepository RepSearch { get; set; } + + /// + /// 构造函数 + /// + public BillListBaseVM() + { + if (EntityList == null) + { + EntityList = new ObservableCollection(); + } + SetDialogWindowSetting(null); + Limit = VampirewalCoreContext.GetInstance().GetOptions().Limit; + InitVM(); + } + + /// + /// 分页设置 + /// + public PagingOptions pageSetting { get; set; } + + /// + /// 构造函数 + /// + public BillListBaseVM(IVampirewalCoreDialogMessage dialog, SqlSugarRepository repBill, SqlSugarRepository repSearch) : base() + { + Dialog = dialog; + RepBill = repBill; + RepSearch = repSearch; + //构造函数 + if (EntityList == null) + { + EntityList = new ObservableCollection(); + } + Limit = VampirewalCoreContext.GetInstance().GetOptions().Limit; + + SetDialogWindowSetting(null); + InitVM(); + } + + #region 属性 + + /// + /// 界面上显示的预制按钮 + /// + [ObservableProperty] + public ListViewButton listButton; + + /// + /// 列表 + /// + public ObservableCollection EntityList { get; set; } + + #region 分页相关 + + /// + /// 当前页 + /// + [ObservableProperty] + public int page = 1; + + /// + /// 每页数 + /// + [ObservableProperty] + public int limit = 20; + + /// + /// 记录数 + /// + [ObservableProperty] + public long count; + + /// + /// 分页数 + /// + [ObservableProperty] + public int pageCount = 0; + + /// + /// 数据总条数 + /// + [ObservableProperty] + public int totalCount; + + #endregion + + #region 弹窗相关 + + /// + /// 弹窗窗体属性设置 + /// + protected DialogWindowSetting DialogSetting { get; private set; } + + /// + /// ★设置弹窗窗体的基本属性★ + /// 无需设置:UiView和PassData(UiView通过SetView()取值,PassData需要传递当前ListVM的选择项) + /// + /// + protected void SetDialogWindowSetting(DialogWindowSetting setting) + { + DialogSetting = setting; + + if (setting == null) + { + DialogSetting = new DialogWindowSetting() + { + WindowWidth = 1366, + WindowHeight = 768, + IsShowMaxButton = true, + IsShowMinButton = true, + IsOpenWindowSize = false, + TitleFontSize = 15, + CloseDialogWindowCallBackCommand = new RelayCommand(ExecuteBeforeCloseDialogWindow) + }; + } + } + + #endregion + + #endregion + + #region 公共方法 + + /// + /// 初始化ViewModel + /// + protected abstract void InitVM(); + + /// + /// 重新初始化ViewModel(需保留Base) + /// + protected virtual void ReInitVM() + { + InitVM(); + } + + ///// + ///// ★调用之后给进行赋值★ + ///// 1、如果使用进行取值的话,直接赋值即可 + ///// 2、如果使用其他方式给赋值,这个方法可重写,也可以自己写方法给赋值 + ///// + ///// 是否使用GetSearchQuery()进行查询,如果为false的话,需要对进行赋值 + ///// 是否使用分页查询,默认 + //protected virtual void GetList(bool IsUseGetSearchQuery,bool UsePageQuery=false) + //{ + // //EntityList.Clear(); + + // //var baseQuery = IsUseGetSearchQuery? GetSearchQuery(): Queryable; + + // //List list = new List(); + + // //if (UsePageQuery) + // //{ + // // int total = 0; + // // int totalPage = 0; + + // // list = RepBill.AsQueryable(baseQuery).ToPageList(Page, Limit, ref total, ref totalPage); + + // // PageCount = totalPage; + // // TotalCount = total; + // //} + // //else + // //{ + // // list = RepBill.AsQueryable(baseQuery).ToList(); + // //} + + // //foreach (var item in list) + // //{ + // // EntityList.Add(item); + // //} + //} + + /// + /// ★调用之后给进行赋值★ + /// 如果使用其他方式给赋值,这个方法可重写,也可以自己写方法给赋值 + /// + /// 查询条件 + /// 排序条件 + /// 排序类型 + /// 是否使用分页 + protected virtual void GetPageList(Expression> expression, Expression> order, OrderByType type = OrderByType.Asc, bool UsePage = true) + { + EntityList.Clear(); + + List list = new List(); + + if (UsePage) + { + int total = 0; + int totalPage = 0; + list = RepBill.QueryableToPage(expression, order, type, Page, limit, ref total, ref totalPage); + + PageCount = totalPage; + TotalCount = total; + } + else + { + list = RepBill.Entities.OrderByIF(order != null, order, type).Where(expression).ToList(); + } + + foreach (var item in list) + { + EntityList.Add(item); + } + } + + /// + /// 获取需要弹窗的窗体 + /// + /// + protected abstract FrameworkElement SetView(); + + #endregion + + + + #region 命令 + + /// + /// 搜索命令执行方法 + /// + /// 模糊搜索文本 + [RelayCommand] + protected virtual void ExecuteSearch(string SearchText) + { + } + + /// + /// 高级搜索命令执行方法 + /// + /// 高级搜索对应模型 + [RelayCommand] + protected virtual void ExecuteSeniorSearch(object s) + { + } + + /// + /// 点击之后会弹出窗体方法 + /// + /// 传递过去的参数 + [RelayCommand] + protected virtual void ExecuteShowDialogWindow(object PassEntity) + { + try + { + var DialogWindow = SetView(); + + if (DialogWindow != null) + { + //var vm = DialogWindow.DataContext as BillVM; + var vm = DialogWindow.DataContext as ViewModelBase; + + if (vm == null) + { + //throw new Exception("对应弹窗窗体的ViewModel不是BillVM!"); + throw new Exception("对应弹窗窗体的ViewModel不是ViewModelBase!"); + } + + DialogSetting.UiView = DialogWindow; + DialogSetting.PassData = PassEntity; + + Dialog.OpenDialogWindow(DialogSetting); + } + else + { + throw new Exception("未找到对应窗体!"); + } + } + catch (Exception ex) + { + throw ex; + } + } + + /// + /// 弹窗关闭窗口的时候,先执行这个方法,然后关闭 + /// + [RelayCommand] + public virtual void ExecuteBeforeCloseDialogWindow(object obj) + { + } + + /// + /// 执行导出Excel方法 + /// + /// + [RelayCommand] + public virtual void ExecuteExportExcel(List searches) + { + } + + #endregion +} \ No newline at end of file diff --git a/Vampirewal.Core/SimpleMVVM/BillVM.cs b/Vampirewal.Core/SimpleMVVM/BillVM.cs new file mode 100644 index 0000000000000000000000000000000000000000..11c7c972687376b7891b31e072c73ea5d17c5272 --- /dev/null +++ b/Vampirewal.Core/SimpleMVVM/BillVM.cs @@ -0,0 +1,458 @@ +#region << 文 件 说 明 >> + +/*---------------------------------------------------------------- +// 文件名称:BillVM +// 创 建 者:杨程 +// 创建时间:2022/2/7 10:02:40 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ + +#endregion + +namespace Vampirewal.Core.SimpleMVVM; + +/// +/// 单据基本信息页VM +/// 基本功能: +/// 1、打开一个单据,框架会自动创建一个空的Entity +/// 2、可通过在构造函数中调用来获取当前的基本信息数据 +/// 3、如果自身存在N个关联的明细数据,可通过调用来获取数据 +/// +public abstract partial class BillVM : ViewModelBase where TEntity : BillBaseModel, new() +{ + #region 构造函数 + + public BillVM(SqlSugarRepository rep) : base() + { + if (Entity == null) + { + var ctor = typeof(TEntity).GetConstructor(Type.EmptyTypes); + Entity = ctor.Invoke(null) as TEntity; + } + + Rep = rep; + BillVmInitData(); + } + + public BillVM() : base() + { + if (Entity == null) + { + var ctor = typeof(TEntity).GetConstructor(Type.EmptyTypes); + Entity = ctor.Invoke(null) as TEntity; + } + + BillVmInitData(); + } + + #endregion + + #region 属性 + + /// + /// 单据基本信息实体类 + /// + [ObservableProperty] + public TEntity entity; + + protected SqlSugarRepository Rep { get; set; } + + #endregion + + #region 公共方法 + + /// + /// 直连数据库的话需要通过调用该方法获取Entity + /// ★通过其他方式获取数据的话,需重写★ + /// + /// + protected virtual void GetById(string BillId) + { + Entity = Rep.Single(w => w.BillId == BillId); + } + + /// + /// 通过HttpClient等方式获取的Entity可调用该方法赋值 + /// + /// + protected void SetEntity(TEntity t) + { + if (t != null) + Entity = t; + } + + /// + /// 获取该单据的明细数据 + /// + /// 明细类型 + /// 成功之后的执行的方法 + /// 异常之后执行的方法 + /// 自定义查询条件 + /// + protected void GetDetail(Action> Success = null, Action Fail = null, string DbName = "default", Expression> CustomQueryable = null) + where TDetail : DetailBaseModel, new() + { + if (DbName != "default") + { + Rep.Context.ChangeDatabase(DbName); + } + + try + { + List list = null; + + if (CustomQueryable == null) + { + list = Rep.Change().ToList(w => w.BillId == Entity.BillId); + } + else + { + list = Rep.Change().AsQueryable(CustomQueryable).ToList(); + } + + Success?.Invoke(list); + } + catch (Exception ex) + { + Fail?.Invoke(ex); + } + finally + { + Rep.Context.ChangeDatabase("default"); + } + } + + /// + /// 获取任意数据填充到List + /// + /// 实体模型 + /// 自定义查询条件 + /// 成功之后的执行的方法 + /// 异常之后执行的方法 + /// 数据库名称 + /// + protected void GetList(Expression> CustomQueryable, Action> Success, Action Fail, string DbName = "default") where TModel : TopModel, new() + { + if (DbName != "default") + { + Rep.Context.ChangeDatabase(DbName); + } + try + { + List list = Rep.Change().AsQueryable(CustomQueryable).ToList(); + + Success?.Invoke(list); + } + catch (Exception ex) + { + Fail?.Invoke(ex); + } + finally + { + Rep.Context.ChangeDatabase("default"); + } + } + + #endregion + + #region 私有方法 + + /// + /// 验证数据库连接 + /// + /// + /// + private void CheckClient(string DbName) + { + if (DbName != "default") + { + Rep.Context.ChangeDatabase(DbName); + } + } + + private void DoCRUD(string OperationCommand) + { + Rep.BeginTran(); + try + { + switch (OperationCommand) + { + case "add": + Rep.Insert(Entity); + break; + + case "update": + Rep.Update(Entity); + break; + + case "delete": + { + Type type = typeof(TEntity); + + var Interfaces = type.GetInterface("IPersistModel"); + + if (Interfaces != null) + { + (Entity as IPersistModel).IsDelete = true; + Rep.Update(Entity); + } + else + { + Entity.UpdateBy = VampirewalCoreContext.GetInstance().GetContext("UserName", out object UserName) == true ? UserName.ToString() : ""; + Entity.UpdateUserId = VampirewalCoreContext.GetInstance().GetContext("UserId", out object UserId) == true ? UserId.ToString() : ""; + Entity.UpdateTime = DateTime.Now; + Rep.Delete(Entity); + } + } + + break; + } + + Rep.CommitTran(); + } + catch + { + Rep.RollbackTran(); + } + finally + { + Rep.Context.ChangeDatabase("default"); + } + } + + private async Task DoCRUDasync(string OperationCommand) + { + Rep.BeginTran(); + try + { + switch (OperationCommand) + { + case "add": + await Rep.InsertAsync(Entity); + break; + + case "update": + await Rep.UpdateAsync(Entity); + break; + + case "delete": + { + Type type = typeof(TEntity); + + var Interfaces = type.GetInterface("IPersistModel"); + + if (Interfaces != null) + { + (Entity as IPersistModel).IsDelete = true; + await Rep.UpdateAsync(Entity); + } + else + { + Entity.UpdateBy = VampirewalCoreContext.GetInstance().GetContext("UserName", out object UserName) == true ? UserName.ToString() : ""; + Entity.UpdateUserId = VampirewalCoreContext.GetInstance().GetContext("UserId", out object UserId) == true ? UserId.ToString() : ""; + Entity.UpdateTime = DateTime.Now; + await Rep.DeleteAsync(Entity); + } + } + + break; + } + + Rep.CommitTran(); + } + catch + { + Rep.RollbackTran(); + } + finally + { + Rep.Context.ChangeDatabase("default"); + } + } + + #endregion + + #region 重写 + + /// + /// BillVM的数据化方法 + /// + public virtual void BillVmInitData() + { + } + + /// + /// 执行entity的新增到数据库操作 + /// + /// + public virtual void DoAdd(string DbName = "default") + { + CheckClient(DbName); + + //Entity.CreateBy = SystemDataContext.GetInstance().loginUserInfo.ITCode; + + DoCRUD("add"); + } + + /// + /// 异步执行entity的新增到数据库操作 + /// + /// + public virtual async void DoAddAsync(string DbName = "default") + { + CheckClient(DbName); + + //Entity.CreateBy = SystemDataContext.GetInstance().loginUserInfo.ITCode; + + await DoCRUDasync("add"); + } + + /// + /// 执行entity的修改到数据库操作 + /// + /// + public virtual void DoUpdate(string DbName = "default") + { + CheckClient(DbName); + + //Entity.UpdateBy = SystemDataContext.GetInstance().loginUserInfo.ITCode; + + DoCRUD("update"); + } + + /// + /// 异步执行entity的修改到数据库操作 + /// + /// + public virtual async void DoUpdateAsync(string DbName = "default") + { + CheckClient(DbName); + + //Entity.UpdateBy = SystemDataContext.GetInstance().loginUserInfo.ITCode; + + await DoCRUDasync("update"); + } + + /// + /// 执行entity的删除到数据库操作 + /// + /// + public virtual void DoDelete(string DbName = "default") + { + CheckClient(DbName); + + DoCRUD("delete"); + } + + /// + /// 异步执行entity的删除到数据库操作 + /// + /// + public virtual async void DoDeleteAsync(string DbName = "default") + { + CheckClient(DbName); + + await DoCRUDasync("delete"); + } + + /// + /// 修改明细 + /// + /// + /// + /// + public virtual void UpdateDetail(List DataSource, string DbName = "default") where TDetail : DetailBaseModel, new() + { + CheckClient(DbName); + Rep.Change().BeginTran(); + try + { + if (DataSource.Count > 1000) + { + Rep.Change().Context.Fastest().PageSize(1000).BulkUpdate(DataSource); + } + else + { + Rep.Change().Update(DataSource); + } + + Rep.Change().CommitTran(); + } + catch + { + Rep.RollbackTran(); + } + finally + { + Rep.Context.ChangeDatabase("default"); + } + } + + /// + /// 添加明细数据 + /// + /// + /// + /// + public virtual void AddDetail(List DataSource, string DbName = "default") where TDetail : DetailBaseModel, new() + { + CheckClient(DbName); + + Rep.BeginTran(); + try + { + if (DataSource.Count > 1000) + { + Rep.Change().Context.Fastest().PageSize(1000).BulkCopy(DataSource); + } + else + { + Rep.Change().Insert(DataSource); + } + + Rep.Change().CommitTran(); + } + catch + { + Rep.RollbackTran(); + } + finally + { + Rep.Context.ChangeDatabase("default"); + } + } + + /// + /// 删除明细数据 + /// + /// + /// + /// + public virtual void DeleteDetail(List DataSource, string DbName = "default") where TDetail : DetailBaseModel, new() + { + CheckClient(DbName); + + try + { + Rep.Change().BeginTran(); + + Rep.Change().Delete(DataSource); + + Rep.Change().CommitTran(); + } + catch + { + Rep.Change().RollbackTran(); + } + finally + { + Rep.Context.ChangeDatabase("default"); + } + } + + #endregion +} \ No newline at end of file diff --git a/Vampirewal.Core/SimpleMVVM/CustomIoC.cs b/Vampirewal.Core/SimpleMVVM/CustomIoC.cs deleted file mode 100644 index 851e187b94d858750a9ee32003cbf8367f4461ee..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/SimpleMVVM/CustomIoC.cs +++ /dev/null @@ -1,1016 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:CustomIoC -// 创 建 者:杨程 -// 创建时间:2021/9/7 10:12:24 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using Vampirewal.Core.Interface; -using Vampirewal.Core.SimpleMVVM.Attributes; - -namespace Vampirewal.Core.SimpleMVVM -{ - /// - /// IOC容器 - /// - public class CustomIoC : IIoC - { - private readonly Dictionary _constructorInfos - = new Dictionary(); - - private readonly string _defaultKey = Guid.NewGuid().ToString(); - - private readonly object[] _emptyArguments = new object[0]; - - private readonly Dictionary> _factories = new Dictionary>(); - - private readonly Dictionary> _instancesRegistry = new Dictionary>(); - - private readonly Dictionary _interfaceToClassMap = new Dictionary(); - - private readonly object _syncLock = new object(); - - private static readonly object _instanceLock = new object(); - - private static CustomIoC instance; - - /// - /// CustomIoC单例 - /// - public static CustomIoC Instance - { - get - { - if (instance == null) - { - lock (_instanceLock) - { - if (instance == null) - { - instance = new CustomIoC(); - } - } - } - - return instance; - } - } - - /// - /// 检查容器中是否已经创建了给定类的至少一个实例 - /// - /// 查询的类. - /// 如果类的实例至少已经创建,则为True,否则为false. - public bool ContainsCreated() - { - return ContainsCreated(null); - } - - /// - /// 检查具有给定键的实例是否已经为给定类创建 - /// 在容器中. - /// - /// 查询的类. - /// 查询的密钥. - /// 如果给定键的实例已经注册到给定的类,则为True,否则为false - public bool ContainsCreated(string key) - { - var classType = typeof(TClass); - - if (!_instancesRegistry.ContainsKey(classType)) - { - return false; - } - - if (string.IsNullOrEmpty(key)) - { - return _instancesRegistry[classType].Count > 0; - } - - return _instancesRegistry[classType].ContainsKey(key); - } - - /// - /// 获取一个值,该值指示给定类型T是否已注册. - /// - /// 方法检查的类型. - /// 如果类型已注册,则为True,否则为false. - public bool IsRegistered() - { - var classType = typeof(T); - return _interfaceToClassMap.ContainsKey(classType); - } - - /// - /// 获取一个值,该值指示是否已注册给定类型T和给定键 - /// - /// 方法检查的类型. - /// 方法检查的键. - /// 如果已注册类型和密钥,则为True,否则为false. - public bool IsRegistered(string key) - { - var classType = typeof(T); - - if (!_interfaceToClassMap.ContainsKey(classType) - || !_factories.ContainsKey(classType)) - { - return false; - } - - return _factories[classType].ContainsKey(key); - } - - /// - /// 为给定的接口注册给定的类型. - /// - /// 将为其解析实例的接口. - /// 创建实例必须使用的类型. - - public void Register() - where TInterface : class - where TClass : class, TInterface - { - Register(false); - } - - /// - /// 为给定的接口注册给定的类型,并有可能立即注册 - /// 创建实例 - /// - /// 将为其解析实例的接口 - /// 创建实例必须使用的类型 - /// 如果为true,则强制创建默认值所提供类的实例. - public void Register(bool createInstanceImmediately) - where TInterface : class - where TClass : class, TInterface - { - lock (_syncLock) - { - var interfaceType = typeof(TInterface); - var classType = typeof(TClass); - - if (_interfaceToClassMap.ContainsKey(interfaceType)) - { - if (_interfaceToClassMap[interfaceType] != classType) - { - throw new InvalidOperationException( - string.Format( - CultureInfo.InvariantCulture, - "There is already a class registered for {0}.", - interfaceType.FullName)); - } - } - else - { - _interfaceToClassMap.Add(interfaceType, classType); - _constructorInfos.Add(classType, GetConstructorInfo(classType)); - } - - Func factory = MakeInstance; - DoRegister(interfaceType, factory, _defaultKey); - - if (createInstanceImmediately) - { - GetInstance(); - } - } - } - - /// - /// 注册给定类型. - /// - /// 创建实例必须使用的类型. - public void Register() - where TClass : class - { - Register(false); - } - - /// - /// 注册一个给定的类型,以便立即创建实例 - /// - /// 创建实例必须使用的类型。 - /// 如果为true,则强制创建所提供类的默认实例 - public void Register(bool createInstanceImmediately) where TClass : class - { - var classType = typeof(TClass); -#if NETFX_CORE - if (classType.GetTypeInfo().IsInterface) -#else - if (classType.IsInterface) -#endif - { - throw new ArgumentException("An interface cannot be registered alone."); - } - - lock (_syncLock) - { - if (_factories.ContainsKey(classType) - && _factories[classType].ContainsKey(_defaultKey)) - { - if (!_constructorInfos.ContainsKey(classType)) - { - // Throw only if constructorinfos have not been - // registered, which means there is a default factory - // for this class. - throw new InvalidOperationException( - string.Format( - CultureInfo.InvariantCulture, - "Class {0} is already registered.", - classType)); - } - - return; - } - - if (!_interfaceToClassMap.ContainsKey(classType)) - { - _interfaceToClassMap.Add(classType, null); - } - - _constructorInfos.Add(classType, GetConstructorInfo(classType)); - Func factory = MakeInstance; - DoRegister(classType, factory, _defaultKey); - - if (createInstanceImmediately) - { - GetInstance(); - } - } - } - - /// - /// 为给定类型注册给定实例 - /// - /// 正在注册的类型 - /// 能够创建在解析给定类型时必须返回的实例的工厂方法 - public void Register(Func factory) - where TClass : class - { - Register(factory, false); - } - - /// - /// 为给定类型注册给定实例,以便立即创建该实例 - /// - /// 正在注册的类型. - /// 能够创建在解析给定类型时必须返回的实例的工厂方法 - /// 如果为true,则强制创建所提供类的默认实例 - public void Register(Func factory, bool createInstanceImmediately) - where TClass : class - { - if (factory == null) - { - throw new ArgumentNullException("factory"); - } - - lock (_syncLock) - { - var classType = typeof(TClass); - - if (_factories.ContainsKey(classType) - && _factories[classType].ContainsKey(_defaultKey)) - { - throw new InvalidOperationException( - string.Format( - CultureInfo.InvariantCulture, - "There is already a factory registered for {0}.", - classType.FullName)); - } - - if (!_interfaceToClassMap.ContainsKey(classType)) - { - _interfaceToClassMap.Add(classType, null); - } - - DoRegister(classType, factory, _defaultKey); - - if (createInstanceImmediately) - { - GetInstance(); - } - } - } - - /// - /// 为给定类型和给定键注册给定实例. - /// - /// 正在注册的类型. - /// 能够创建在解析给定类型时必须返回的实例的工厂方法 - /// 给定实例为其注册的键. - public void Register(Func factory, string key) - where TClass : class - { - Register(factory, key, false); - } - - /// - /// 为给定类型和给定键注册给定实例,以便立即创建该实例 - /// - /// 正在注册的类型. - /// 能够创建在解析给定类型时必须返回的实例的工厂方法 - /// 给定实例为其注册的键. - /// 如果为true,则强制创建所提供类的默认实例 - public void Register( - Func factory, - string key, - bool createInstanceImmediately) - where TClass : class - { - - if (factory == null) - { - throw new ArgumentNullException("factory"); - } - - lock (_syncLock) - { - var classType = typeof(TClass); - - if (_factories.ContainsKey(classType) - && _factories[classType].ContainsKey(key)) - { - throw new InvalidOperationException( - string.Format( - CultureInfo.InvariantCulture, - "There is already a factory registered for {0} with key {1}.", - classType.FullName, - key)); - } - - if (!_interfaceToClassMap.ContainsKey(classType)) - { - _interfaceToClassMap.Add(classType, null); - } - - DoRegister(classType, factory, key); - - if (createInstanceImmediately) - { - GetInstance(key); - } - } - } - - /// - /// 重置实例的初始状态。这将删除所有注册。 - /// - public void Reset() - { - _interfaceToClassMap.Clear(); - _instancesRegistry.Clear(); - _constructorInfos.Clear(); - _factories.Clear(); - } - - /// - /// 从缓存中注销类并删除所有先前创建的实例 - /// - /// 必须删除的类 - - public void Unregister() - where TClass : class - { - lock (_syncLock) - { - var serviceType = typeof(TClass); - Type resolveTo; - - if (_interfaceToClassMap.ContainsKey(serviceType)) - { - resolveTo = _interfaceToClassMap[serviceType] ?? serviceType; - } - else - { - resolveTo = serviceType; - } - - if (_instancesRegistry.ContainsKey(serviceType)) - { - _instancesRegistry.Remove(serviceType); - } - - if (_interfaceToClassMap.ContainsKey(serviceType)) - { - _interfaceToClassMap.Remove(serviceType); - } - - if (_factories.ContainsKey(serviceType)) - { - _factories.Remove(serviceType); - } - - if (_constructorInfos.ContainsKey(resolveTo)) - { - _constructorInfos.Remove(resolveTo); - } - } - } - - /// - /// 从缓存中删除给定的实例。类本身保持注册状态,并可用于创建其他实例。 - /// - /// 要删除的实例的类型. - /// 必须删除的实例. - public void Unregister(TClass instance) - where TClass : class - { - lock (_syncLock) - { - var classType = typeof(TClass); - - if (_instancesRegistry.ContainsKey(classType)) - { - var list = _instancesRegistry[classType]; - - var pairs = list.Where(pair => pair.Value == instance).ToList(); - for (var index = 0; index < pairs.Count(); index++) - { - var key = pairs[index].Key; - - list.Remove(key); - } - } - } - } - - /// - /// 从缓存中删除与给定键对应的实例。类本身保持注册状态,并可用于创建其他实例。 - /// - /// 要删除的实例的类型 - /// 与必须删除的实例对应的键. - public void Unregister(string key) - where TClass : class - { - lock (_syncLock) - { - var classType = typeof(TClass); - - if (_instancesRegistry.ContainsKey(classType)) - { - var list = _instancesRegistry[classType]; - - var pairs = list.Where(pair => pair.Key == key).ToList(); - for (var index = 0; index < pairs.Count(); index++) - { - list.Remove(pairs[index].Key); - } - } - - if (_factories.ContainsKey(classType)) - { - if (_factories[classType].ContainsKey(key)) - { - _factories[classType].Remove(key); - } - } - } - } - - private object DoGetService(Type serviceType, string key, bool cache = true) - { - lock (_syncLock) - { - if (string.IsNullOrEmpty(key)) - { - key = _defaultKey; - } - - Dictionary instances = null; - - if (!_instancesRegistry.ContainsKey(serviceType)) - { - if (!_interfaceToClassMap.ContainsKey(serviceType)) - { - - throw new InvalidOperationException( - - string.Format( - CultureInfo.InvariantCulture, - "Type not found in cache: {0}.", - serviceType.FullName)); - } - - if (cache) - { - instances = new Dictionary(); - _instancesRegistry.Add(serviceType, instances); - } - } - else - { - instances = _instancesRegistry[serviceType]; - } - - if (instances != null && instances.ContainsKey(key)) - { - return instances[key]; - } - - object instance = null; - - if (_factories.ContainsKey(serviceType)) - { - if (_factories[serviceType].ContainsKey(key)) - { - instance = _factories[serviceType][key].DynamicInvoke(null); - } - else - { - if (_factories[serviceType].ContainsKey(_defaultKey)) - { - instance = _factories[serviceType][_defaultKey].DynamicInvoke(null); - } - else - { - - throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture,"Type not found in cache without a key: {0}",serviceType.FullName)); - } - } - } - - if (cache - && instances != null) - { - instances.Add(key, instance); - } - - return instance; - } - } - - private void DoRegister(Type classType, Func factory, string key) - { - if (_factories.ContainsKey(classType)) - { - if (_factories[classType].ContainsKey(key)) - { - // The class is already registered, ignore and continue. - return; - } - - _factories[classType].Add(key, factory); - } - else - { - var list = new Dictionary - { - { - key, - factory - } - }; - - _factories.Add(classType, list); - } - } - - private ConstructorInfo GetConstructorInfo(Type serviceType) - { - Type resolveTo; - - if (_interfaceToClassMap.ContainsKey(serviceType)) - { - resolveTo = _interfaceToClassMap[serviceType] ?? serviceType; - } - else - { - resolveTo = serviceType; - } - -#if NETFX_CORE - var constructorInfos = resolveTo.GetTypeInfo().DeclaredConstructors.Where(c => c.IsPublic).ToArray(); -#else - var constructorInfos = resolveTo.GetConstructors(); -#endif - - if (constructorInfos.Length > 1) - { - if (constructorInfos.Length > 2) - { - return GetPreferredConstructorInfo(constructorInfos, resolveTo); - } - - if (constructorInfos.FirstOrDefault(i => i.Name == ".cctor") == null) - { - return GetPreferredConstructorInfo(constructorInfos, resolveTo); - } - - var first = constructorInfos.FirstOrDefault(i => i.Name != ".cctor"); - - if (first == null - || !first.IsPublic) - { - - throw new InvalidOperationException( - string.Format( - CultureInfo.InvariantCulture, - "Cannot register: No public constructor found in {0}.", - resolveTo.Name)); - } - - return first; - } - - if (constructorInfos.Length == 0 - || (constructorInfos.Length == 1 - && !constructorInfos[0].IsPublic)) - { - - throw new InvalidOperationException( - string.Format( - CultureInfo.InvariantCulture, - "Cannot register: No public constructor found in {0}.", - resolveTo.Name)); - } - - return constructorInfos[0]; - } - - - private static ConstructorInfo GetPreferredConstructorInfo(IEnumerable constructorInfos, Type resolveTo) - { - var preferredConstructorInfo - = (from t in constructorInfos -#if NETFX_CORE - let attribute = t.GetCustomAttribute(typeof(PreferredConstructorAttribute)) -#else - let attribute = Attribute.GetCustomAttribute(t, typeof(PreferredConstructorAttribute)) -#endif - where attribute != null - select t).FirstOrDefault(); - - if (preferredConstructorInfo == null) - { - throw new InvalidOperationException( - string.Format( - CultureInfo.InvariantCulture, - "Cannot register: Multiple constructors found in {0} but none marked with PreferredConstructor.", - resolveTo.Name)); - } - - return preferredConstructorInfo; - } - - private TClass MakeInstance() - { - var serviceType = typeof(TClass); - - var constructor = _constructorInfos.ContainsKey(serviceType) - ? _constructorInfos[serviceType] - : GetConstructorInfo(serviceType); - - var parameterInfos = constructor.GetParameters(); - - if (parameterInfos.Length == 0) - { - return (TClass)constructor.Invoke(_emptyArguments); - } - - var parameters = new object[parameterInfos.Length]; - - foreach (var parameterInfo in parameterInfos) - { - parameters[parameterInfo.Position] = GetService(parameterInfo.ParameterType); - } - - return (TClass)constructor.Invoke(parameters); - } - - /// - /// 提供一种方法,使所创建的给定类型的所有实例在缓存中可用。注册类或工厂不会自动创建相应的实例!要创建实例,可以将createInstanceImmediately设置为true注册类或工厂,或者在调用GetAllCreatedInstances之前调用GetInstance方法。或者,使用GetAllInstances方法,它会为所有已注册的类自动创建默认实例。 - /// - /// 必须返回其所有实例的类 - /// 给定类型的所有已经创建的实例 - public IEnumerable GetAllCreatedInstances(Type serviceType) - { - if (_instancesRegistry.ContainsKey(serviceType)) - { - return _instancesRegistry[serviceType].Values; - } - - return new List(); - } - - /// - /// 提供一种方法,使所创建的给定类型的所有实例在缓存中可用。注册类或工厂不会自动创建相应的实例!要创建实例,可以将createInstanceImmediately设置为true注册类或工厂,或者在调用GetAllCreatedInstances之前调用GetInstance方法。或者,使用GetAllInstances方法,它会为所有已注册的类自动创建默认实例。 - /// - /// 必须返回其所有实例的类 - /// 给定类型的所有已经创建的实例。 - public IEnumerable GetAllCreatedInstances() - { - var serviceType = typeof(TService); - return GetAllCreatedInstances(serviceType) - .Select(instance => (TService)instance); - } - - #region Implementation of IServiceProvider - -#if NETSTANDARD1_0 - /// - /// Gets the service object of the specified type. - /// - /// If the type serviceType has not - /// been registered before calling this method. - /// - /// A service object of type . - /// - /// An object that specifies the type of service object to get. -#else - /// - /// 获取指定类型的服务对象 - /// - /// 如果serviceType类型在调用此方法之前没有注册 - /// - /// 类型的服务对象. - /// - /// 指定要获取的服务对象类型的对象. -#endif - public object GetService(Type serviceType) - { - return DoGetService(serviceType, _defaultKey); - } - - #endregion - - #region Implementation of IServiceLocator - - /// - /// Provides a way to get all the created instances of a given type available in the - /// cache. Calling this method auto-creates default - /// instances for all registered classes. - /// - /// The class of which all instances - /// must be returned. - /// All the instances of the given type. - public IEnumerable GetAllInstances(Type serviceType) - { - lock (_factories) - { - if (_factories.ContainsKey(serviceType)) - { - foreach (var factory in _factories[serviceType]) - { - GetInstance(serviceType, factory.Key); - } - } - } - - if (_instancesRegistry.ContainsKey(serviceType)) - { - return _instancesRegistry[serviceType].Values; - } - - - return new List(); - } - - /// - /// Provides a way to get all the created instances of a given type available in the - /// cache. Calling this method auto-creates default - /// instances for all registered classes. - /// - /// The class of which all instances - /// must be returned. - /// All the instances of the given type. - public IEnumerable GetAllInstances() - { - var serviceType = typeof(TService); - return GetAllInstances(serviceType) - .Select(instance => (TService)instance); - } - -#if NETSTANDARD1_0 - /// - /// Provides a way to get an instance of a given type. If no instance had been instantiated - /// before, a new instance will be created. If an instance had already - /// been created, that same instance will be returned. - /// - /// If the type serviceType has not - /// been registered before calling this method. - /// The class of which an instance - /// must be returned. - /// An instance of the given type. -#else - /// - /// Provides a way to get an instance of a given type. If no instance had been instantiated - /// before, a new instance will be created. If an instance had already - /// been created, that same instance will be returned. - /// - /// If the type serviceType has not - /// been registered before calling this method. - /// The class of which an instance - /// must be returned. - /// An instance of the given type. -#endif - public object GetInstance(Type serviceType) - { - return DoGetService(serviceType, _defaultKey); - } - -#if NETSTANDARD1_0 - /// - /// Provides a way to get an instance of a given type. This method - /// always returns a new instance and doesn't cache it in the IOC container. - /// - /// If the type serviceType has not - /// been registered before calling this method. - /// The class of which an instance - /// must be returned. - /// An instance of the given type. -#else - /// - /// Provides a way to get an instance of a given type. This method - /// always returns a new instance and doesn't cache it in the IOC container. - /// - /// If the type serviceType has not - /// been registered before calling this method. - /// The class of which an instance - /// must be returned. - /// An instance of the given type. -#endif - public object GetInstanceWithoutCaching(Type serviceType) - { - return DoGetService(serviceType, _defaultKey, false); - } - -#if NETSTANDARD1_0 - /// - /// Provides a way to get an instance of a given type corresponding - /// to a given key. If no instance had been instantiated with this - /// key before, a new instance will be created. If an instance had already - /// been created with the same key, that same instance will be returned. - /// - /// If the type serviceType has not - /// been registered before calling this method. - /// The class of which an instance must be returned. - /// The key uniquely identifying this instance. - /// An instance corresponding to the given type and key. -#else - /// - /// Provides a way to get an instance of a given type corresponding - /// to a given key. If no instance had been instantiated with this - /// key before, a new instance will be created. If an instance had already - /// been created with the same key, that same instance will be returned. - /// - /// If the type serviceType has not - /// been registered before calling this method. - /// The class of which an instance must be returned. - /// The key uniquely identifying this instance. - /// An instance corresponding to the given type and key. -#endif - public object GetInstance(Type serviceType, string key) - { - return DoGetService(serviceType, key); - } - -#if NETSTANDARD1_0 - /// - /// Provides a way to get an instance of a given type. This method - /// always returns a new instance and doesn't cache it in the IOC container. - /// - /// If the type serviceType has not - /// been registered before calling this method. - /// The class of which an instance must be returned. - /// The key uniquely identifying this instance. - /// An instance corresponding to the given type and key. -#else - /// - /// Provides a way to get an instance of a given type. This method - /// always returns a new instance and doesn't cache it in the IOC container. - /// - /// If the type serviceType has not - /// been registered before calling this method. - /// The class of which an instance must be returned. - /// The key uniquely identifying this instance. - /// An instance corresponding to the given type and key. -#endif - public object GetInstanceWithoutCaching(Type serviceType, string key) - { - return DoGetService(serviceType, key, false); - } - -#if NETSTANDARD1_0 - /// - /// Provides a way to get an instance of a given type. If no instance had been instantiated - /// before, a new instance will be created. If an instance had already - /// been created, that same instance will be returned. - /// - /// If the type TService has not - /// been registered before calling this method. - /// The class of which an instance - /// must be returned. - /// An instance of the given type. -#else - /// - /// Provides a way to get an instance of a given type. If no instance had been instantiated - /// before, a new instance will be created. If an instance had already - /// been created, that same instance will be returned. - /// - /// If the type TService has not - /// been registered before calling this method. - /// The class of which an instance - /// must be returned. - /// An instance of the given type. -#endif - public TService GetInstance() - { - return (TService)DoGetService(typeof(TService), _defaultKey); - } - -#if NETSTANDARD1_0 - /// - /// Provides a way to get an instance of a given type. This method - /// always returns a new instance and doesn't cache it in the IOC container. - /// - /// If the type TService has not - /// been registered before calling this method. - /// The class of which an instance - /// must be returned. - /// An instance of the given type. -#else - /// - /// 提供获取给定类型实例的方法。此方法总是返回一个新实例,并且不将其缓存到IOC容器中。 - /// - /// 如果类型TService在调用此方法之前没有注册 - /// 必须返回其实例的类。 - /// 给定类型的实例。 -#endif - public TService GetInstanceWithoutCaching() - { - return (TService)DoGetService(typeof(TService), _defaultKey, false); - } - -#if NETSTANDARD1_0 - /// - /// Provides a way to get an instance of a given type corresponding - /// to a given key. If no instance had been instantiated with this - /// key before, a new instance will be created. If an instance had already - /// been created with the same key, that same instance will be returned. - /// - /// If the type TService has not - /// been registered before calling this method. - /// The class of which an instance must be returned. - /// The key uniquely identifying this instance. - /// An instance corresponding to the given type and key. -#else - /// - /// Provides a way to get an instance of a given type corresponding - /// to a given key. If no instance had been instantiated with this - /// key before, a new instance will be created. If an instance had already - /// been created with the same key, that same instance will be returned. - /// - /// If the type TService has not - /// been registered before calling this method. - /// The class of which an instance must be returned. - /// The key uniquely identifying this instance. - /// An instance corresponding to the given type and key. -#endif - public TService GetInstance(string key) - { - return (TService)DoGetService(typeof(TService), key); - } - -#if NETSTANDARD1_0 - /// - /// Provides a way to get an instance of a given type. This method - /// always returns a new instance and doesn't cache it in the IOC container. - /// - /// If the type TService has not - /// been registered before calling this method. - /// The class of which an instance must be returned. - /// The key uniquely identifying this instance. - /// An instance corresponding to the given type and key. -#else - /// - /// Provides a way to get an instance of a given type. This method - /// always returns a new instance and doesn't cache it in the IOC container. - /// - /// If the type TService has not - /// been registered before calling this method. - /// The class of which an instance must be returned. - /// The key uniquely identifying this instance. - /// An instance corresponding to the given type and key. -#endif - public TService GetInstanceWithoutCaching(string key) - { - return (TService)DoGetService(typeof(TService), key, false); - } - - #endregion - } -} diff --git a/Vampirewal.Core/SimpleMVVM/DetailVM.cs b/Vampirewal.Core/SimpleMVVM/DetailVM.cs new file mode 100644 index 0000000000000000000000000000000000000000..688720fe12b7a8344d34f3e3e438a163fe829bc5 --- /dev/null +++ b/Vampirewal.Core/SimpleMVVM/DetailVM.cs @@ -0,0 +1,326 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:DetailVM +// 创 建 者:杨程 +// 创建时间:2022/2/18 9:46:29 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.SimpleMVVM; + +/// +/// 单独Detail的VM +/// +/// +public abstract partial class DetailVM : ViewModelBase where TDtlEntity : DetailBaseModel, new() +{ + #region 构造函数 + public DetailVM() : base() + { + if (DtlEntity == null) + { + var ctor = typeof(TDtlEntity).GetConstructor(Type.EmptyTypes); + DtlEntity = ctor.Invoke(null) as TDtlEntity; + } + + + DetailVmInitData(); + } + + public DetailVM(SqlSugarRepository rep) : base() + { + if (DtlEntity == null) + { + var ctor = typeof(TDtlEntity).GetConstructor(Type.EmptyTypes); + DtlEntity = ctor.Invoke(null) as TDtlEntity; + } + + Rep = rep; + DetailVmInitData(); + } + + + #endregion + + #region 属性 + + /// + /// 明细实体类 + /// + [ObservableProperty] + public TDtlEntity dtlEntity; + + /// + /// Dtl数据库 + /// + protected SqlSugarRepository Rep { get; set; } + #endregion + + #region 公共方法 + /// + /// 直连数据库的话需要通过调用该方法获取Entity + /// + /// + protected virtual void GetById(string DtlId) + { + DtlEntity = Rep.Single(w => w.DtlId == DtlId); + } + + /// + /// 通过HttpClient等方式获取的Entity可调用该方法赋值 + /// + /// + protected virtual void SetEntity(TDtlEntity t) + { + if (t != null) + DtlEntity = t; + } + #endregion + + #region 私有方法 + /// + /// 验证数据库连接 + /// + /// + /// + private void CheckClient(string DbName) + { + + if (string.IsNullOrEmpty(DtlEntity.BillId)) + { + throw new Exception("明细类的BillId不能为空!"); + } + + if (DbName != "default") + { + Rep.Context.ChangeDatabase(DbName); + } + + } + + + private void DoCRUD(string OperationCommand) + { + Rep.BeginTran(); + try + { + switch (OperationCommand) + { + case "add": + Rep.Insert(DtlEntity); + break; + case "update": + Rep.Update(DtlEntity, null, "DtlId"); + break; + case "delete": + { + Type type = typeof(TDtlEntity); + + var Interfaces = type.GetInterfaces(); + + foreach (var Interface in Interfaces) + { + if (Interface == typeof(IPersistModel)) + { + (DtlEntity as IPersistModel).IsDelete = true; + //Entity.UpdateBy = SystemDataContext.GetInstance().loginUserInfo?.ITCode; + //Entity.UpdateTime = DateTime.Now; + } + } + + Rep.Delete(DtlEntity); + } + + break; + } + + + Rep.CommitTran(); + } + catch + { + Rep.RollbackTran(); + } + finally + { + Rep.Context.ChangeDatabase("default"); + } + } + + private async Task DoCRUDasync(string OperationCommand) + { + Rep.BeginTran(); + try + { + switch (OperationCommand) + { + case "add": + await Rep.InsertAsync(DtlEntity); + break; + case "update": + await Rep.UpdateAsync(DtlEntity); + break; + case "delete": + { + Type type = typeof(TDtlEntity); + + var Interfaces = type.GetInterfaces(); + + foreach (var Interface in Interfaces) + { + if (Interface == typeof(IPersistModel)) + { + (DtlEntity as IPersistModel).IsDelete = true; + //Entity.UpdateBy = SystemDataContext.GetInstance().loginUserInfo?.ITCode; + //Entity.UpdateTime = DateTime.Now; + } + } + + await Rep.DeleteAsync(DtlEntity); + } + + break; + } + + + Rep.CommitTran(); + } + catch + { + Rep.RollbackTran(); + } + finally + { + Rep.Context.ChangeDatabase("default"); + } + } + #endregion + + #region 命令 + + #endregion + + #region 重写 + /// + /// BillVM的数据化方法 + /// + public virtual void DetailVmInitData() + { + + } + + /// + /// 执行entity的新增到数据库操作 + /// + /// + public virtual void DoAdd(string DbName = "default") + { + CheckClient(DbName); + + //Entity.CreateBy = SystemDataContext.GetInstance().loginUserInfo.ITCode; + + DoCRUD("add"); + } + + /// + /// 异步执行entity的新增到数据库操作 + /// + /// + public async virtual void DoAddAsync(string DbName = "default") + { + CheckClient(DbName); + + //Entity.CreateBy = SystemDataContext.GetInstance().loginUserInfo.ITCode; + + await DoCRUDasync("add"); + } + + /// + /// 执行entity的修改到数据库操作 + /// + /// + public virtual void DoUpdate(string DbName = "default") + { + CheckClient(DbName); + + //Entity.UpdateBy = SystemDataContext.GetInstance().loginUserInfo.ITCode; + + DoCRUD("update"); + } + + /// + /// 异步执行entity的修改到数据库操作 + /// + /// + public async virtual void DoUpdateAsync(string DbName = "default") + { + CheckClient(DbName); + + //Entity.UpdateBy = SystemDataContext.GetInstance().loginUserInfo.ITCode; + + await DoCRUDasync("update"); + } + + /// + /// 执行entity的删除到数据库操作 + /// + /// + public virtual void DoDelete(string DbName = "default") + { + CheckClient(DbName); + + DoCRUD("delete"); + } + + /// + /// 异步执行entity的删除到数据库操作 + /// + /// + public async virtual void DoDeleteAsync(string DbName = "default") + { + CheckClient(DbName); + + await DoCRUDasync("delete"); + } + + + #endregion +} + +/* + * 暂时没想到应该怎么写,TDto需在构建TDetail的时候传进去,才能监控到值的变化,如果通过下面的方式创建,那么额外的代码量也挺大的 + */ + +//public class DetailChange:ViewModelBase where TDetail : DetailItemChangeBaseModel, new() where TDto : TopModel, new() +//{ +// public DetailChange() +// { +// if (DtlEntity == null) +// { + +// var dto= typeof(TDto).GetConstructor(Type.EmptyTypes); +// var DTO= dto.Invoke(null) as TDto; + +// var ctor = typeof(TDetail).GetConstructor( new Type[]{ typeof(TDto)} ); +// DtlEntity = ctor.Invoke(new object[] { DTO }) as TDetail; +// } +// } + +// private TDetail _DtlEntity; +// /// +// /// 明细实体类 +// /// +// public TDetail DtlEntity +// { +// get { return _DtlEntity; } +// set { _DtlEntity = value; DoNotify(); } +// } +//} diff --git a/Vampirewal.Core/SimpleMVVM/Enum/ShowMode.cs b/Vampirewal.Core/SimpleMVVM/Enum/ShowMode.cs deleted file mode 100644 index dd50b7e06fe70efa8b7068b2505191c43e036309..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/SimpleMVVM/Enum/ShowMode.cs +++ /dev/null @@ -1,35 +0,0 @@ -/* 项目名称: ShowMode.cs - * 命名空间: Vampirewal.Core.SimpleMVVM - * 类 名 称: ShowMode - * 作 者 : 杨程 - * 概 述 : - * 创建时间 : 2021/2/20 18:22:16 - * 更新时间 : 2021/2/20 18:22:16 - * CLR版本 : 4.0.30319.42000 - * ****************************************************** - * Copyright@Administrator 2021 .All rights reserved. - * ****************************************************** - */ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Vampirewal.Core.SimpleMVVM -{ - public enum ShowMode - { - /// - /// 一般显示 - /// - Show, - - /// - /// 对话框显示 - /// - Dialog - - } -} diff --git a/Vampirewal.Core/SimpleMVVM/FileAttachmentVM.cs b/Vampirewal.Core/SimpleMVVM/FileAttachmentVM.cs deleted file mode 100644 index b01f446895c241300f2fb60a36318e9af5807c0b..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/SimpleMVVM/FileAttachmentVM.cs +++ /dev/null @@ -1,45 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:FileAttachmentVM -// 创 建 者:杨程 -// 创建时间:2021/9/16 11:15:29 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore; -using Vampirewal.Core.Models; - -namespace Vampirewal.Core.SimpleMVVM -{ - public class FileAttachmentVM: BaseCRUDVM - { - public override void DoDelete() - { - try - { - if (Entity.SaveFileMode == SaveFileModeEnum.Local && !string.IsNullOrEmpty(Entity.Path)) - { - Utils.DeleteFile(Entity.Path); - } - FileAttachment del = new FileAttachment { ID = Entity.ID }; - DC.Set().Attach(del); - DC.Set().Remove(del); - DC.SaveChanges(); - } - catch (DbUpdateException) - { - //MSD.AddModelError("", Program._localizer["DataCannotDelete"]); - } - } - } -} diff --git a/Vampirewal.Core/SimpleMVVM/IMessageManager.cs b/Vampirewal.Core/SimpleMVVM/IMessageManager.cs deleted file mode 100644 index 18b50626bf1a039047fba627978d1f305fe5e5a3..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/SimpleMVVM/IMessageManager.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Vampirewal.Core.SimpleMVVM -{ - public interface IMessageManager - { - - } -} diff --git a/Vampirewal.Core/SimpleMVVM/Messenger.cs b/Vampirewal.Core/SimpleMVVM/Messenger.cs deleted file mode 100644 index 1753e19383ab0df3b835c0d36d54ab441440f22e..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/SimpleMVVM/Messenger.cs +++ /dev/null @@ -1,323 +0,0 @@ -/* 项目名称: Messenger.cs - * 命名空间: Vampirewal.Core.SimpleMVVM - * 类 名 称: Messenger - * 作 者 : 杨程 - * 概 述 : - * 创建时间 : 2021/2/20 18:31:26 - * 更新时间 : 2021/2/20 18:31:26 - * CLR版本 : 4.0.30319.42000 - * ****************************************************** - * Copyright@Administrator 2021 .All rights reserved. - * ****************************************************** - */ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; - -namespace Vampirewal.Core.SimpleMVVM -{ - /// - /// 消息通知类 - /// - public class Messenger - { - private Messenger() - { - - } - - /// - /// 注册消息 - /// - public void RegistAll() - { - var types = AppDomain.CurrentDomain.GetAssemblies() - .SelectMany(a => a.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IMessageManager)))) - .ToArray(); - foreach (var v in types) - { - object obj = Activator.CreateInstance(v); - MethodInfo[] methods = obj.GetType().GetMethods(); - foreach (var item in methods) - { - RegistMethodAttribute attribute = item.GetCustomAttribute(); - if (attribute != null) - { - if (attribute.Token == null) - { - Messenger.Default.Register(obj, item.Name, item); - } - else - { - Messenger.Default.Register(obj, attribute.Token, item); - } - } - } - } - } - - public void RegistObject(object obj) - { - MethodInfo[] methods = obj.GetType().GetMethods(); - foreach (var item in methods) - { - RegistMethodAttribute attribute = item.GetCustomAttribute(); - if (attribute != null) - { - if (attribute.Token == null) - { - Messenger.Default.Register(obj, item.Name, item); - } - else - { - Messenger.Default.Register(obj, attribute.Token, item); - } - } - } - } - private static Messenger instance; - - /// - /// 默认单例实例 - /// - public static Messenger Default - { - get - { - if (instance == null) - { - instance = new Messenger(); - } - - return instance; - } - } - - Dictionary tokenAndInstance = new Dictionary(); - - /// - /// 获取已注册的Token - /// - /// - public List GetRegisterTokens() - { - List cur = new List(); - foreach (var item in tokenAndInstance) - { - cur.Add(item.Key); - } - - return cur; - } - - /// - /// 注册消息 - /// - /// - /// - /// - /// - public void Register(object register, string token, Action action) - { - TokenInstance tokenInstance = new TokenInstance(); - tokenInstance.Register = register; - tokenInstance.MethodInfo = action.Method; - try - { - tokenAndInstance.Add(token, tokenInstance); - } - catch (Exception) - { - - throw new MessageRegisteredException("该Token消息已注册"); - } - - } - - /// - /// 注册消息 - /// - /// - /// - /// - /// - public void Register(object register, string token, MethodInfo methodInfo) - { - TokenInstance tokenInstance = new TokenInstance(); - tokenInstance.Register = register; - tokenInstance.MethodInfo = methodInfo; - try - { - tokenAndInstance.Add(token, tokenInstance); - } - catch (Exception) - { - - throw new MessageRegisteredException("该Token消息已注册"); - } - - } - - /// - /// 注册消息 - /// - /// 参数类型 - /// - /// - /// - /// - public void Register(object register, string token, Action action) - { - TokenInstance tokenInstance = new TokenInstance(); - tokenInstance.Register = register; - tokenInstance.MethodInfo = action.Method; - try - { - tokenAndInstance.Add(token, tokenInstance); - } - catch (Exception) - { - - throw new MessageRegisteredException("该Token消息已注册"); - } - } - - /// - /// 注册 - /// - /// 参数类型 - /// 返回值类型 - /// - /// - /// - public void Register(object register, string token, Func action) - { - TokenInstance tokenInstance = new TokenInstance(); - tokenInstance.Register = register; - tokenInstance.MethodInfo = action.Method; - try - { - tokenAndInstance.Add(token, tokenInstance); - } - catch (Exception) - { - - throw new MessageRegisteredException("该Token消息已注册"); - } - } - - /// - /// 注册 - /// - /// 参数类型 - /// 传参类型 - /// 返回值类型 - /// - /// - /// - public void Register(object register,string token,Func action) - { - TokenInstance tokenInstance = new TokenInstance(); - tokenInstance.Register = register; - tokenInstance.MethodInfo = action.Method; - try - { - tokenAndInstance.Add(token, tokenInstance); - } - catch (Exception) - { - - throw new MessageRegisteredException("该Token消息已注册"); - } - } - - - /// - /// 注册 - /// - /// 返回值类型 - /// - /// - /// - public void Register(object register, string token, Func action) - { - TokenInstance tokenInstance = new TokenInstance(); - tokenInstance.Register = register; - tokenInstance.MethodInfo = action.Method; - try - { - tokenAndInstance.Add(token, tokenInstance); - } - catch (Exception) - { - - throw new MessageRegisteredException("该Token消息已注册"); - } - } - - /// - /// 卸载消息 - /// - /// - public void Unregister(object register) - { - List key = new List(); - - foreach (var item in tokenAndInstance.Keys) - { - if (register == tokenAndInstance[item].Register) - { - key.Add(item); - } - } - - foreach (var item in key) - { - tokenAndInstance.Remove(item); - } - } - - /// - /// 发送消息 - /// - /// - /// - /// - public void Send(string token, params object[] parameters) - { - try - { - tokenAndInstance[token].MethodInfo.Invoke(tokenAndInstance[token].Register, parameters); - } - catch (KeyNotFoundException) - { - throw new MessageNotFoundException("未找到该消息"); - } - - } - - /// - /// 发送消息 - /// - /// 返回值类型 - /// - /// - /// - /// - public T Send(string token, params object[] parameters) - { - try - { - return (T)tokenAndInstance[token].MethodInfo.Invoke(tokenAndInstance[token].Register, parameters); - } - catch (KeyNotFoundException) - { - throw new MessageNotFoundException("未找到该消息"); - } - } - } -} diff --git a/Vampirewal.Core/SimpleMVVM/SimpleIoc.cs b/Vampirewal.Core/SimpleMVVM/SimpleIoc.cs deleted file mode 100644 index 79bb38b3deb2ca0aa3144c15d8603d02db5575ec..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/SimpleMVVM/SimpleIoc.cs +++ /dev/null @@ -1,158 +0,0 @@ -/* 项目名称: SimpleIoc.cs - * 命名空间: Vampirewal.Core.SimpleMVVM - * 类 名 称: SimpleIoc - * 作 者 : 杨程 - * 概 述 : - * 创建时间 : 2021/2/20 18:34:26 - * 更新时间 : 2021/2/20 18:34:26 - * CLR版本 : 4.0.30319.42000 - * ****************************************************** - * Copyright@Administrator 2021 .All rights reserved. - * ****************************************************** - */ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; - -namespace Vampirewal.Core.SimpleMVVM -{ - /// - /// ViewModelLocator基类 - /// - public class SimpleIoc - { - private SimpleIoc() - { - - } - private static SimpleIoc instance; - - /// - /// 默认单例实例 - /// - public static SimpleIoc Default - { - get - { - if (instance == null) - { - instance = new SimpleIoc(); - } - - return instance; - } - } - - private List viewModelBases = new List(); - private Dictionary viewModelKey = new Dictionary(); - - /// - /// 注册 - /// - /// - /// - /// - public void Register(FrameworkElement element, ViewModelBase viewModel) - { - element.DataContext = viewModel; - viewModel.View = element; - viewModelBases.Add(viewModel); - } - - /// - /// 注册 - /// - /// - public void Register(ViewModelBase viewModel) - { - viewModelBases.Add(viewModel); - } - - - - /// - /// 注册 - /// - /// - /// - //public void Register(string key, ViewModelBase viewModel) - //{ - // viewModelBases.Add(viewModel); - //} - - /// - /// 注册 - /// - /// - /// - /// - /// - public void Register(string key, FrameworkElement element, ViewModelBase viewModel) - { - element.DataContext = viewModel; - viewModel.View = element; - viewModelKey.Add(key, viewModel); - } - - /// - /// 获取ViewModel - /// - /// - /// - public T GetViewModelInstance() - { - foreach (var item in viewModelBases) - { - if (item.GetType() == typeof(T)) - { - return (T)item; - } - } - return default; - } - - /// - /// 获取ViewModel - /// - /// - /// - /// - public T GetViewModelInstance(string key) - { - try - { - return (T)viewModelKey[key]; - } - catch (Exception) - { - return default; - } - - } - - /// - /// 获取ViewModel,并绑定View - /// - /// - /// - public T GetViewModelInstance(FrameworkElement window) where T:ViewModelBase - { - foreach (var item in viewModelBases) - { - if (item.GetType() == typeof(T)) - { - ((T)item).View = window; - return (T)item; - } - } - return default; - } - - } - - -} diff --git a/Vampirewal.Core/SimpleMVVM/TokenInstance.cs b/Vampirewal.Core/SimpleMVVM/TokenInstance.cs index 24c194af037468fc49333a04d022a66f21400053..c47fcce1b99924b86bd1cbd4d50051c55171a4ce 100644 --- a/Vampirewal.Core/SimpleMVVM/TokenInstance.cs +++ b/Vampirewal.Core/SimpleMVVM/TokenInstance.cs @@ -11,21 +11,16 @@ * ****************************************************** */ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -namespace Vampirewal.Core.SimpleMVVM + + +namespace Vampirewal.Core.SimpleMVVM; + +/// +/// +/// +internal class TokenInstance { - /// - /// - /// - internal class TokenInstance - { - public object Register { get; set; } - public MethodInfo MethodInfo { get; set; } - } + public object Register { get; set; } + public MethodInfo MethodInfo { get; set; } } diff --git a/Vampirewal.Core/SimpleMVVM/VampirewalApplication.cs b/Vampirewal.Core/SimpleMVVM/VampirewalApplication.cs deleted file mode 100644 index cacb82070618d16019d8a81b11b74c9a42ea4ef8..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/SimpleMVVM/VampirewalApplication.cs +++ /dev/null @@ -1,178 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:VampirewalApplication -// 创 建 者:杨程 -// 创建时间:2021/9/22 13:04:58 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using Vampirewal.Core.Components; -using Vampirewal.Core.Interface; - -namespace Vampirewal.Core.SimpleMVVM -{ - /// - /// - /// - public class VampirewalApplication: Application - { - /// - /// 在VampirewalApplication - /// - /// - protected override void OnStartup(StartupEventArgs e) - { - base.OnStartup(e); - - MessengerRegister(); - - this.DispatcherUnhandledException += GlobalExceptions; - } - - /// - /// 全局异常捕获(需重写) - /// 错误信息:e.Exception.Message - /// 最后需要写e.Handled = true;证明异常已处理 - /// - /// - /// - protected virtual void GlobalExceptions(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) - { - //IDialogMessage dialog = new VampirewalDialog(); - //dialog.ShowPopupWindow($"错误信息:{e.Exception.Message}",) - //e.Handled = true; - } - - /// - /// 设置当前程序集信息 - /// - /// 在重写的OnStartup中,base.OnStartup(e)前执行SetAssembly(Assembly.GetExecutingAssembly()); - /// - /// - /// - /// - protected void SetAssembly(Assembly ViewAssembly) - { - CurrentAssembly = ViewAssembly; - } - - private Assembly CurrentAssembly { get; set; } - - /// - /// 注册消息; - /// 在OnStartup中,已经注册了该方法,继承VampirewalApplication,只需要重写该方法即可; - /// 如果重写了OnStartup方法,未保留base.OnStartup(e)的话,该方法需在已重写的OnStartup方法中再调用一下; - /// 切记:重写该方法时,一定要保留这个方法中的Base; - /// 该方法包含:5个获取窗体的方法并注册; - /// - public virtual void MessengerRegister() - { - Messenger.Default.Register(this, "GetView", GetView); - Messenger.Default.Register(this, "OpenWinodw", OpenWinodw); - Messenger.Default.Register(this, "OpenDialogWindowGetResultByPassData", OpenDialogWindowGetResultByPassData); - Messenger.Default.Register(this, "OpenDialogWindowGetResult", OpenDialogWindowGetResult); - Messenger.Default.Register(this, "OpenShowDialogWindow", OpenShowDialogWindow); - } - - /// - /// 通过反射获取页面,并注册消息供ViewModel调用 - /// - /// 窗体完整的名称(命名空间+窗体名称) - /// - protected FrameworkElement GetView(string ViewName) - { - if (CurrentAssembly==null) - { - throw new Exception("未设置正确的Assembly!"); - } - - Type type = CurrentAssembly.GetType($"{ViewName}"); - //Type type = Type.GetType($"{ViewName}"); - ConstructorInfo cti = type.GetConstructor(System.Type.EmptyTypes); - var current = (FrameworkElement)cti.Invoke(null); - - //this.MainContent = current; - return current; - } - - - protected void OpenWinodw(string ViewName) - { - Window w = GetView(ViewName) as Window; - ViewModelBase vm = w.DataContext as ViewModelBase; - vm.View = w; - if (w != null) - { - //WindowsManager.CreateDialogWindowByViewModelResult(w,) - w.Show(); - } - } - - /// - /// 开启DialogWindow窗体,传入值并获取返回值 - /// - /// 窗体名称 - /// 传入参数 - /// 返回object - protected object OpenDialogWindowGetResultByPassData(string ViewName, object param) - { - Window w = GetView(ViewName) as Window; - ViewModelBase vm = w.DataContext as ViewModelBase; - vm.View = w; - - vm.PassData(param); - w.ShowDialog(); - - return vm.GetResult(); - } - - /// - /// 开启DialogWindow窗体,传入值并获取返回值 - /// - /// 窗体名称 - /// 传入参数 - /// 返回object - protected object OpenDialogWindowGetResult(string ViewName) - { - Window w = GetView(ViewName) as Window; - ViewModelBase vm = w.DataContext as ViewModelBase; - vm.View = w; - - w.ShowDialog(); - - return vm.GetResult(); - } - - /// - /// 开启DialogWindos窗体,返回true/false - /// - /// 窗体名称 - /// - protected bool OpenShowDialogWindow(string ViewName) - { - Window w = GetView(ViewName) as Window; - ViewModelBase vm = w.DataContext as ViewModelBase; - vm.View = w; - if (w.ShowDialog() == true) - { - return true; - } - else - { - return false; - } - } - } -} diff --git a/Vampirewal.Core/SimpleMVVM/ViewModelBase.cs b/Vampirewal.Core/SimpleMVVM/ViewModelBase.cs index 88f7542f2ac3d33a85f59e7a425401c989590091..efd3877eff4151c09585ad984d2be9507843b931 100644 --- a/Vampirewal.Core/SimpleMVVM/ViewModelBase.cs +++ b/Vampirewal.Core/SimpleMVVM/ViewModelBase.cs @@ -11,215 +11,140 @@ * ****************************************************** */ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Runtime.CompilerServices; -using System.Text.Json.Serialization; -using System.Windows; -using System.Windows.Input; -using Vampirewal.Core.Interface; -using Vampirewal.Core.Models; -using static Org.BouncyCastle.Math.EC.ECCurve; - -namespace Vampirewal.Core.SimpleMVVM + + + +namespace Vampirewal.Core.SimpleMVVM; + +/// +/// ViewModel基类 +/// +public partial class ViewModelBase : ObservableObject { /// - /// ViewModel基类 + /// VMId /// - public class ViewModelBase : NotifyBase, IBaseVM + public string VMId => Guid.NewGuid().ToString(); + + /// + /// 构造函数 + /// + public ViewModelBase() { - /// - /// VMId - /// - public string VMId => Guid.NewGuid().ToString(); - /// - /// 数据库操作使用,初始化必须在构造函数中,使用依赖注入 - /// - public IDataContext DC { get; set; } - - private IAppConfig _Config; - public IAppConfig Config - { - get { return _Config; } - set { _Config = value;DoNotify(); } - } - /// - /// 用于保存删除的附件ID - /// - [JsonIgnore] - public List DeletedFileIds { get; set; } - - /// - /// 构造函数 - /// - public ViewModelBase(IDataContext dc,IAppConfig config) - { - DC = dc; - Config = config; - InitData(); - MessengerRegister(); - } + InitData(); + MessengerRegister(); + } - /// - /// 构造函数 - /// - public ViewModelBase(IDataContext dc) - { - DC = dc; - InitData(); - MessengerRegister(); - } - /// - /// 构造函数 - /// - public ViewModelBase(IAppConfig config) - { - Config = config; - InitData(); - MessengerRegister(); - } + /// + /// 目标View + /// + [ObservableProperty] + public FrameworkElement view; - /// - /// 构造函数 - /// - public ViewModelBase() + /// + /// 用于存储DialogWindow传递过来的窗体ID + /// + [ObservableProperty] + public Guid viewId; + + /// + /// 通过VM关闭窗体 + /// + protected virtual void CloseView() + { + try { - - InitData(); - MessengerRegister(); + WindowsManager.GetInstance().CloseWindow(((Window)View)); } - /// - /// 判断是不是设计器模式 - /// - public bool IsInDesignMode + catch (Exception ex) { - get { return DesignerProperties.GetIsInDesignMode(new DependencyObject()); } + throw ex; } + } - /// - /// 目标View - /// - public FrameworkElement View { get; set; } - - /// - /// 当前登陆用户 - /// - public LoginUserInfo loginUserInfo { get; set; } - /// - /// UI线程调用 - /// - /// - public void UIInvoke(Action action) - { - this.View.Dispatcher.Invoke(action); - } + + /// + /// UI线程调用 + /// + /// + public void UIInvoke(Action action) + { + this.View?.Dispatcher.Invoke(action); + } - /// - /// 标题 - /// - public string Title { get; set; } = "未命名窗体"; - /// - /// 当窗体是DialogShow的方式打开的时候,可以通过重写这个方法,将值传回主窗体 - /// - /// - public virtual object GetResult() - { - return null; - } + /// + /// 标题 + /// + [ObservableProperty] + public string title = "未命名窗体"; - /// - /// 初始化页面数据,由ViewModelBase的构造函数调用,重写后不用再调用 - /// - public virtual void InitData() - { - //loginUserInfo = GlobalDataManager.loginUserInfo; - } - /// - /// 初始化页面数据,由创建时传递参数 - /// - /// 传入参数 - public virtual void PassData(object obj) - { + /// + /// 当窗体是DialogShow的方式打开的时候,可以通过重写这个方法,将值传回主窗体 + /// + /// + public virtual object GetResult() + { + return null; + } - } + /// + /// 初始化页面数据,由ViewModelBase的构造函数调用,重写后不用再调用 + /// + public virtual void InitData() + { - /// - /// 通用消息注册 - /// - public virtual void MessengerRegister() - { + } + /// + /// 初始化页面数据,由创建时传递参数 + /// + /// 传入参数 + public virtual void PassData(object obj) + { - } + } + + /// + /// 通用消息注册 + /// + public virtual void MessengerRegister() + { + + } + + ///// + ///// 拷贝VM内的信息 + ///// + ///// ViewModelBase + //[Obsolete("暂时未启用",true)] + //public void CopyVM(IBaseVM self) + //{ + // //loginUserInfo = self.loginUserInfo; + // DC = self.DC; + //} - /// - /// 拷贝VM内的信息 - /// - /// ViewModelBase - public void CopyVM(IBaseVM self) - { - loginUserInfo = self.loginUserInfo; - DC = self.DC; - } + #region 命令 + /// + /// 鼠标取消焦点命令 + /// Keyboard.ClearFocus(); + /// + [RelayCommand] + public void MouseDownCancelFocus() + { + Keyboard.ClearFocus(); + } + + /// + /// 关闭窗体执行的命令 + /// + [RelayCommand] + public virtual void CloseWindow() + { - #region 命令 - /// - /// 通用的窗体关闭命令,但是每个窗体的关闭可能需要做的事情不一样,故非DialogWindow窗体,重写这个命令。 - /// - //public virtual RelayCommand CloseWindowCommand => new RelayCommand(() => - //{ - // WindowsManager.CloseWindow(View as Window); - //}); - - ///// - ///// 最大化和恢复窗体命令 - ///// - //public virtual RelayCommand MaxWindowCommand => new RelayCommand((w) => - //{ - // if (w.WindowState == WindowState.Normal) - // { - // w.WindowState = WindowState.Maximized; - // } - // else - // { - // w.WindowState = WindowState.Normal; - // } - //}); - - ///// - ///// 最小化窗体命令 - ///// - //public virtual RelayCommand MinWindowCommand => new RelayCommand((w) => - //{ - // w.WindowState = WindowState.Minimized; - //}); - - ///// - ///// 窗体移动命令 - ///// - //public virtual RelayCommand WindowMoveCommand => new RelayCommand((w) => - //{ - // if (w != null) - // { - // w.DragMove(); - // } - //}); - - /// - /// 鼠标取消焦点命令 - /// - public virtual RelayCommand MouseDownCommand => new RelayCommand(() => - { - Keyboard.ClearFocus(); - }); - - - - #endregion } + #endregion } diff --git a/Vampirewal.Core/SimpleMVVM/WindowCollection.cs b/Vampirewal.Core/SimpleMVVM/WindowCollection.cs index cf60ecb8c4cc0741387ab16bd8ba774d3ddeb25b..72dce7896642f1be06d4a29b8c2758064d51fa0f 100644 --- a/Vampirewal.Core/SimpleMVVM/WindowCollection.cs +++ b/Vampirewal.Core/SimpleMVVM/WindowCollection.cs @@ -11,48 +11,43 @@ * ****************************************************** */ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -namespace Vampirewal.Core.SimpleMVVM + + +namespace Vampirewal.Core.SimpleMVVM; + +/// +/// 窗口集合 +/// +public class WindowCollection : List { /// - /// 窗口集合 + /// 添加 /// - public class WindowCollection : List + /// + public new void Add(Window window) { - /// - /// 添加 - /// - /// - public new void Add(Window window) - { - window.Closed += Window_Closed; - window.Activate(); - base.Add(window); - } + window.Closed += Window_Closed; + window.Activate(); + base.Add(window); + } - private void Window_Closed(object sender, EventArgs e) - { - base.Remove((Window)sender); - } + private void Window_Closed(object sender, EventArgs e) + { + base.Remove((Window)sender); + } - public Window this[string WindowName] + public Window this[string WindowName] + { + get { - get + if (!string.IsNullOrEmpty(WindowName)) + { + return this.FirstOrDefault(f => f.Name == WindowName); + } + else { - if (!string.IsNullOrEmpty(WindowName)) - { - return this.FirstOrDefault(f => f.Name == WindowName); - } - else - { - return null; - } + return null; } } } diff --git a/Vampirewal.Core/SimpleMVVM/WindowSetting.cs b/Vampirewal.Core/SimpleMVVM/WindowSetting.cs index 585f797a747f2644df0605703a14bf66a4eed3aa..695a3d8009abd3a656039a893667fef4128799a4 100644 --- a/Vampirewal.Core/SimpleMVVM/WindowSetting.cs +++ b/Vampirewal.Core/SimpleMVVM/WindowSetting.cs @@ -11,40 +11,49 @@ * ****************************************************** */ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; - -namespace Vampirewal.Core.SimpleMVVM + + + +namespace Vampirewal.Core.SimpleMVVM; + +/// +/// 显示窗口设置 +/// +public class WindowSetting +{ + /// + /// Window类型 + /// + public Type WindowType { get; set; } + + /// + /// 状态 + /// + public WindowState WindowState { get; set; } + + /// + /// 显示类型 + /// + public ShowMode ShowMode { get; set; } + + /// + /// 构造函数参数 + /// + public object[] Parameters { get; set; } + + +} + +public enum ShowMode { /// - /// 显示窗口设置 + /// 一般显示 + /// + Show, + + /// + /// 对话框显示 /// - public class WindowSetting - { - /// - /// Window类型 - /// - public Type WindowType { get; set; } - - /// - /// 状态 - /// - public WindowState WindowState { get; set; } - - /// - /// 显示类型 - /// - public ShowMode ShowMode { get; set; } - - /// - /// 构造函数参数 - /// - public object[] Parameters { get; set; } - - - } + Dialog + } diff --git a/Vampirewal.Core/SimpleMVVM/WindowsManager.cs b/Vampirewal.Core/SimpleMVVM/WindowsManager.cs index 03a2e42b516b6a9fd98ffc269ab7d0fc186d63bc..385c090fad4b63799c52d8752739617934560e9e 100644 --- a/Vampirewal.Core/SimpleMVVM/WindowsManager.cs +++ b/Vampirewal.Core/SimpleMVVM/WindowsManager.cs @@ -2,7 +2,7 @@ * 命名空间: Vampirewal.Core.SimpleMVVM * 类 名 称: WindowsManager * 作 者 : 杨程 - * 概 述 : + * 概 述 : * 创建时间 : 2021/2/20 18:47:33 * 更新时间 : 2021/2/20 18:47:33 * CLR版本 : 4.0.30319.42000 @@ -11,301 +11,286 @@ * ****************************************************** */ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; +namespace Vampirewal.Core.SimpleMVVM; -namespace Vampirewal.Core.SimpleMVVM +/// +/// 窗体管理 +/// +public sealed class WindowsManager : BaseSingleton { + private WindowCollection windows = new WindowCollection(); + /// - /// 窗口管理 + /// 主窗体(方便弹窗使用) /// - public static class WindowsManager + public Window MainWindow { get; set; } + + /// + /// 获取已创建的窗口 + /// + public WindowCollection Windows { + get { return windows; } + } + private Dictionary DialogWindowDic { get; set; } = new Dictionary(); - private static WindowCollection windows = new WindowCollection(); - /// - /// 获取已创建的窗口 - /// - public static WindowCollection Windows + /// + /// 关闭所有窗口 + /// + public void CloseAllWindow() + { + foreach (var window in windows) { - get { return windows; } + window.Close(); } + } - /// - /// 创建新窗体 - /// - /// - public static void CreatWindow(WindowSetting windowSetting) + /// + /// 关闭DialogWindow窗体 + /// + /// + public void CloseDialogWindow(Guid ViewId) + { + if (DialogWindowDic.TryGetValue(ViewId, out Window window)) { - Window window = Activator.CreateInstance(windowSetting.WindowType, windowSetting.Parameters) as Window; - window.WindowState = windowSetting.WindowState; - - windows.Add(window); - - switch (windowSetting.ShowMode) + try { - case ShowMode.Show: - window.Show(); - break; - case ShowMode.Dialog: - window.ShowDialog(); - break; + var DialogWindow = window as ShowDialogWindow; + var vm = DialogWindow.DataContext as ViewModelBase; + DialogWindow.CloseDialogWindowCallBackCommand?.Execute(vm.GetResult()); + } + catch (Exception ex) + { + throw ex; + } + finally + { + window.Close(); + DialogWindowDic.Remove(ViewId); } } + } - /// - /// 创建新窗体 - /// - /// - /// - public static void CreatWindow(Type windowType, params object[] parameters) - { - Window window = Activator.CreateInstance(windowType, parameters) as Window; - - windows.Add(window); - window.Show(); - } + /// + /// 关闭窗体 + /// + /// + public void CloseWindow(Window window) + { + windows.Remove(window); + window.Close(); + GC.Collect(); + } - /// - /// 创建对话框窗体 - /// - /// - /// - public static object CreatDialogWindow(Type windowType, params object[] parameters) + /// + /// 获取DialogWindow窗体 + /// + /// + /// + /// + public Window GetDialogWindow(Guid ViewId) + { + if (DialogWindowDic.TryGetValue(ViewId, out Window window)) { - Window window = Activator.CreateInstance(windowType, parameters) as Window; - - windows.Add(window); - return window.ShowDialog(); + return window; } - - /// - /// 创建对话框窗体 - /// - /// - public static object CreateDialogWindow(Window window) + else { - windows.Add(window); - return window.ShowDialog(); + throw new WindowsManagerException("未找到对应DialogWindow"); } + } - /// - /// 创建DialogWindow窗体并绑定ViewModel - /// - /// 窗体 - /// ViewModel - /// 在ViewModelBase中重写GetResult方法,获取返回值 - public static object CreateDialogWindowByViewModelResult(Window window, ViewModelBase vm) - { - windows.Add(window); - window.DataContext = vm; - vm.View = window; - window.ShowDialog(); - return vm.GetResult(); - } + /// + /// 获取窗体并指定VM和传参 + /// + /// + /// + /// + /// + public FrameworkElement GetView(string ViewToken, string ViewModelToken = "", object Param = null) + { + return GetViewBase(ViewToken, ViewModelToken, Param); + } - /// - /// 通过反射创建DialogWindow窗体并绑定ViewModel - /// - /// 窗体 - /// ViewModel - /// 在ViewModelBase中重写GetResult方法,获取返回值 - public static object CreateDialogWindowByViewModelResult(string windowType, ViewModelBase vm,object parmam=null) - { - var types = AppDomain.CurrentDomain.GetAssemblies() - .SelectMany(a => a.GetTypes().Where(t => t.Name == windowType)) - .ToArray(); - if (types.Length == 1) - { - Window window = Activator.CreateInstance(types[0]) as Window; - window.DataContext = vm; - if (parmam!=null) - { - vm.PassData(parmam); - } - vm.View = window; - windows.Add(window); - window.ShowDialog(); - return vm.GetResult(); - } - else - { - throw new Exception("没有找到该窗体类型或窗体类型不唯一"); - } - - - } + /// + /// Window窗体以Dialog方式打开并获取返回值 + /// + /// + /// + /// + /// 是否设置为主窗体 + /// + /// + public object OpenDialogWindow(string ViewToken, string ViewModelToken = "", object Param = null, bool IsMainWindow = false) + { + var w = GetWindowBase(ViewToken, ViewModelToken, Param, IsMainWindow); - /// - /// 创建模块窗体 - /// - /// - public static void CreateModulesWindow(string WindowName, ViewModelBase vm, object parmam) - { - if (parmam==null) - { - throw new Exception("创建该窗体必须传入参数!"); - } - var types = AppDomain.CurrentDomain.GetAssemblies() - .SelectMany(a => a.GetTypes().Where(t => t.Name == WindowName)) - .ToArray(); - if (types.Length == 1) - { - Window window = Activator.CreateInstance(types[0]) as Window; - window.DataContext = vm; - //var vm =(ViewModelBase) window.DataContext; - vm.PassData(parmam); - vm.View = window; - windows.Add(window); - window.ShowDialog(); - - } - else - { - throw new Exception("没有找到该窗体类型或窗体类型不唯一"); - } + w.ShowDialog(); - } + return w.DataSource.GetResult(); + } - public static bool CreateDialogWindowToBool(Window window) + /// + /// 打开Window窗体并传入参数到VM中 + /// + /// + /// + /// + /// 是否设置为主窗体 + public void OpenWindow(string ViewToken, string ViewModelPath = "", object Param = null, bool IsMainWindow = false) + { + GetWindowBase(ViewToken, ViewModelPath, Param, IsMainWindow).Show(); + } + + /// + /// 打开window窗体并获取返回值 + /// + /// 窗体Token + /// + /// + /// 是否设置为主窗体 + /// + public object OpenWindowGetResult(string ViewToken, string ViewModelPath = "", object Param = null, bool IsMainWindow = false) + { + var win = GetWindowBase(ViewToken, ViewModelPath, Param, IsMainWindow); + + win.Show(); + + return win.DataSource.GetResult(); + } + + /// + /// 注册DialogWindow窗体 + /// + /// + /// + public bool RegisterDialogWindow(Guid ViewId, Window window) + { + return DialogWindowDic.TryAdd(ViewId, window); + } + + /// + /// 注册存储window + /// + /// + public void RegisterWindow(Window w) + { + if (!Windows.Contains(w)) { - windows.Add(window); - if (window.ShowDialog() == true) - { - return true; - } - else - { - return false; - } + windows.Add(w); } - - - /// - /// 创建新窗体 - /// - /// - /// - public static void CreateWindow(string windowType, ShowMode showMode, ViewModelBase vm) + } + + private FrameworkElement GetViewBase(string ViewToken, string ViewModelToken, object Param = null) + { + if (string.IsNullOrEmpty(ViewToken)) + throw new WindowsManagerException("窗体Token不能为空!"); + + try { - var types = AppDomain.CurrentDomain.GetAssemblies() - .SelectMany(a => a.GetTypes().Where(t => t.Name == windowType)) - .ToArray(); - if (types.Length == 1) + var view = VampirewalCoreContext.GetInstance().GetView(ViewToken); + + if (view == null) + throw new WindowsManagerException("窗体找到!"); + + ViewModelBase VM = null; + + if (!string.IsNullOrEmpty(view.ViewModelKey)) { - Window window = Activator.CreateInstance(types[0]) as Window; - window.DataContext = vm; - vm.View = window; - windows.Add(window); - - switch (showMode) - { - case ShowMode.Show: - window.Show(); - break; - case ShowMode.Dialog: - window.ShowDialog(); - break; - } + VM = VampirewalCoreContext.GetInstance().GetViewModel(view.ViewModelKey); } - else + else if (!string.IsNullOrEmpty(ViewModelToken)) { - throw new Exception("没有找到该窗体类型或窗体类型不唯一"); + VM = VampirewalCoreContext.GetInstance().GetViewModel(ViewModelToken); } + if (VM == null) + throw new WindowsManagerException("对应ViewModelKey未找到!"); - } + if (Param != null) + VM.PassData(Param); + view.DataContext = VM; + view.DataSource = VM; - /// - /// 创建新窗体 - /// - /// - /// - public static void CreatWindow(Window window, ShowMode showMode) - { - windows.Add(window); - switch (showMode) - { - case ShowMode.Show: - window.Show(); - break; - case ShowMode.Dialog: - window.ShowDialog(); - break; - } + return view; } - - /// - /// 关闭窗体 - /// - /// - public static void CloseWindow(Window window) + catch (WindowsManagerException ex) { - windows.Remove(window); - window.Close(); - GC.Collect(); + throw ex; } + } + + /// + /// 获取窗体 + /// + /// + /// + /// + /// + /// + /// + private WindowBase GetWindowBase(string ViewToken, string ViewModelToken = "", object Param = null, bool IsMainWindow = false) + { + if (string.IsNullOrEmpty(ViewToken)) + throw new WindowsManagerException("窗体Token不能为空!"); - /// - /// 关闭查找到的第一个窗口 - /// - /// - public static void CloseSelectFirstWindow(Type windowType) + try { - foreach (var window in windows) + var window = VampirewalCoreContext.GetInstance().GetView(ViewToken); + + if (window == null) + throw new WindowsManagerException("窗体找到!"); + + ViewModelBase VM = null; + + if (!string.IsNullOrEmpty(window.ViewModelKey)) { - if (window.GetType().FullName == windowType.FullName) - { - windows.Remove(window); - window.Close(); - break; - } + VM = VampirewalCoreContext.GetInstance().GetViewModel(window.ViewModelKey); } - } - - /// - /// 关闭查找到的所有的窗口 - /// - /// - public static void CloseSelectAllWindow(Type windowType) - { - foreach (var window in windows) + else if (!string.IsNullOrEmpty(ViewModelToken)) { - if (window.GetType().FullName == windowType.FullName) - { - windows.Remove(window); - window.Close(); - } + VM = VampirewalCoreContext.GetInstance().GetViewModel(ViewModelToken); } - } - /// - /// 关闭所有窗口 - /// - public static void CloseAllWindow() - { - foreach (var window in windows) + if (VM == null) + throw new WindowsManagerException("对应ViewModelKey未找到!"); + + if (Param != null) + VM.PassData(Param); + + window.DataContext = VM; + window.DataSource = VM; + window.DataSource.view = window; + + windows.Add(window); + + if (IsMainWindow) { - window.Close(); + MainWindow = window; } - } - /// - /// 注册存储window - /// - /// - public static void RegisterWindow(Window w) + return window; + } + catch (WindowsManagerException ex) { - if (!Windows.Contains(w)) - { - windows.Add(w); - } + throw ex; } } } + +/// +/// +/// +[Serializable] +public class WindowsManagerException : Exception +{ + /// + /// + /// + /// + public WindowsManagerException(string mes) : base(mes) + { + } +} \ No newline at end of file diff --git a/Vampirewal.Core/SimpleMVVM/YcList.cs b/Vampirewal.Core/SimpleMVVM/YcList.cs deleted file mode 100644 index c3aece8d1c4067572ef896769fa3c8e29c27e363..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/SimpleMVVM/YcList.cs +++ /dev/null @@ -1,58 +0,0 @@ -/* 项目名称: YcList.cs - * 命名空间: Vampirewal.Core.SimpleMVVM - * 类 名 称: YcList - * 作 者 : 杨程 - * 概 述 : - * 创建时间 : 2021/2/20 18:45:00 - * 更新时间 : 2021/2/20 18:45:00 - * CLR版本 : 4.0.30319.42000 - * ****************************************************** - * Copyright@Administrator 2021 .All rights reserved. - * ****************************************************** - */ - -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Vampirewal.Core.SimpleMVVM -{ - /// - /// 继承ObservableCollection的集合 - /// - /// - public class YcList : ObservableCollection - { - public YcList() - { - //构造函数 - } - - /// - /// - /// - /// - public YcList(List list) - { - foreach (var item in list) - { - Add(item); - } - } - - /// - /// - /// - /// - public YcList(IEnumerable collection) - { - foreach (var item in collection) - { - Add(item); - } - } - } -} diff --git a/Vampirewal.Core/Support/DuplicateInfo.cs b/Vampirewal.Core/Support/DuplicateInfo.cs deleted file mode 100644 index 3d05cfb8024efe89f49a460c95cfd37addbffc2c..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/Support/DuplicateInfo.cs +++ /dev/null @@ -1,357 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:DuplicateInfo -// 创 建 者:杨程 -// 创建时间:2021/9/16 10:32:08 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using Vampirewal.Core.Extensions; -using Vampirewal.Core.Helper; - -namespace Vampirewal.Core -{ - /// - /// 重复数据组 - /// - /// 重复数据类 - public class DuplicatedGroup - { - public List> Fields { get; set; } - } - - /// - /// 重复数据信息 - /// - /// 数据类 - public class DuplicatedInfo - { - //重复数据分组 - public List> Groups { get; set; } - - public DuplicatedInfo() - { - Groups = new List>(); - } - - /// - /// 添加一组重复信息,一组中的多个字段必须同时重复才认为是重复数据 - /// - /// 一个或多个重复数据字段 - public DuplicatedInfo AddGroup(params DuplicatedField[] FieldExps) - { - DuplicatedGroup newGroup = new DuplicatedGroup() - { - Fields = new List>() - }; - foreach (var exp in FieldExps) - { - newGroup.Fields.Add(exp); - } - Groups.Add(newGroup); - return this; - } - } - - /// - /// 简单重复数据字段信息 - /// - /// 重复数据类 - public class DuplicatedField - { - //直接可顺序关联出的字段 - protected Expression> _directFieldExp { get; set; } - - public virtual List GetProperties() - { - List rv = new List - { - PropertyHelper.GetPropertyInfo(_directFieldExp) - }; - return rv; - } - - - /// - /// 根据设定的字段,生成查询重复数据的Lambda,最终返回类似 x=>x.property == val的lambda - /// - /// 要验证字段的实体类 - /// ParameterExpression - /// - public virtual Expression GetExpression(T Entity, ParameterExpression para) - { - var propName = PropertyHelper.GetPropertyName(_directFieldExp); - var prop = PropertyHelper.GetPropertyInfo(_directFieldExp); - var func = _directFieldExp.Compile(); - var val = func.Invoke(Entity); - - ////如果字段值为null则跳过,因为一般情况下null值不会被认为重复 - //if (val == null) - //{ - // return res; - //} - - //如果字段值是空字符串,则跳过 - if (val is string && val.ToString() == string.Empty) - { - var requiredAttrs = prop.GetCustomAttributes(typeof(RequiredAttribute), false).ToList(); - - if (requiredAttrs == null || requiredAttrs.Count == 0) - { - return null; - } - else - { - var requiredAtt = requiredAttrs[0] as RequiredAttribute; - if (requiredAtt.AllowEmptyStrings == true) - { - return null; - } - } - } - //生成一个表达式,类似于 x=>x.field == val - var splits = propName.Split('.'); - var idproperty = typeof(T).GetProperties().Where(x => x.Name == splits[0]).FirstOrDefault(); - - Expression left = Expression.Property(para, idproperty); - for (int i = 1; i < splits.Length; i++) - { - var tempproperty = typeof(T).GetProperties().Where(x => x.Name == splits[i]).FirstOrDefault(); - left = Expression.Property(left, tempproperty); - } - - if (val != null && left.Type.IsGeneric(typeof(Nullable<>))) - { - left = Expression.Property(left, "Value"); - } - if (left.Type == typeof(string)) - { - left = Expression.Call(left, typeof(String).GetMethod("Trim", Type.EmptyTypes)); - } - if (val is string) - { - val = val.ToString().Trim(); - } - var right = Expression.Constant(val); - var equal = Expression.Equal(left, right); - return equal; - } - - protected DuplicatedField() - { - - } - - /// - /// 创建一个包含可顺序关联出字段的简单重复字段信息 - /// - /// 字段 - /// 字段信息 - public DuplicatedField(Expression> FieldExp) - { - _directFieldExp = FieldExp; - } - - } - - /// - /// 复杂重复字段信息接口 - /// - public interface IComplexDuplicatedField - { - Type GetMiddleTableType(); - } - - - /// - /// 复杂重复数据字段信息 - /// - /// 重复数据类 - /// 重复数据关联的List中的类 - public class ComplexDuplicatedField : DuplicatedField, IComplexDuplicatedField - { - /// - /// 中间字段 - /// - private Expression>> _middleExp { get; set; } - /// - /// 最终字段 - /// - private List>> _subFieldExps { get; set; } - - protected ComplexDuplicatedField() - { - - } - - /// - /// 创建一个复杂字段 - /// - /// 中间字段类 - /// 最终字段类 - /// - public ComplexDuplicatedField(Expression>> MiddleExp, params Expression>[] FieldExps) - { - _middleExp = MiddleExp; - _subFieldExps = new List>>(); - _subFieldExps.AddRange(FieldExps); - } - - public Type GetMiddleTableType() - { - return typeof(V); - } - - /// - /// 生成验证复杂字段是否重复的Lambda - /// - /// 源数据 - /// 源数据类型 - /// Where语句 - public override Expression GetExpression(T Entity, ParameterExpression para) - { - ParameterExpression midPara = Expression.Parameter(typeof(V), "tm2"); - //获取中间表的List - var list = _middleExp.Compile().Invoke(Entity); - if (list == null) - { - return null; - } - List allExp = new List(); - Expression rv = null; - //循环中间表数据 - foreach (var li in list) - { - List innerExp = new List(); - bool needBreak = false; - //循环中间表要检查重复的字段 - foreach (var SubFieldExp in _subFieldExps) - { - //拼接字段表达式,使left等于类似 x.field 的形式 - Expression left = Expression.Property(midPara, SubFieldExp.GetPropertyName()); - //如果字段是nullable类型的,则拼接value,形成类似 x.field.Value的形式 - if (left.Type.IsGeneric(typeof(Nullable<>)) == true) - { - left = Expression.Property(left, "Value"); - } - //如果字段是string类型,则拼接trim,形成类似 x.field.Trim()的形式 - if (left.Type == typeof(string)) - { - left = Expression.Call(left, typeof(String).GetMethod("Trim", Type.EmptyTypes)); - } - //使用当前循环的中间表的数据获取字段的值 - object vv = SubFieldExp.Compile().Invoke(li); - //如果值为空则跳过 - if (vv == null) - { - needBreak = true; - continue; - } - //如果值为空字符串且没要求必填,则跳过 - if (vv is string && vv.ToString() == "") - { - var requiredAttrs = li.GetType().GetSingleProperty(SubFieldExp.GetPropertyName()).GetCustomAttributes(typeof(RequiredAttribute), false).ToList(); - - if (requiredAttrs == null || requiredAttrs.Count == 0) - { - needBreak = true; - continue; - } - else - { - var requiredAtt = requiredAttrs[0] as RequiredAttribute; - if (requiredAtt.AllowEmptyStrings == true) - { - needBreak = true; - continue; - } - } - } - //如果值为字符串,调用trim函数 - if (vv is string) - { - vv = vv.ToString().Trim(); - } - //拼接形成 x.field == value的形式 - ConstantExpression right = Expression.Constant(vv); - BinaryExpression equal = Expression.Equal(left, right); - innerExp.Add(equal); - } - if (needBreak) - { - continue; - } - //拼接多个 x.field==value,形成 x.field==value && x.field1==value1 .....的形式 - Expression exp = null; - if (innerExp.Count == 1) - { - exp = innerExp[0]; - } - if (innerExp.Count > 1) - { - exp = Expression.And(innerExp[0], innerExp[1]); - for (int i = 2; i < innerExp.Count; i++) - { - exp = Expression.And(exp, innerExp[i]); - } - } - //调用any函数,形成 .Any(x=> x.field==value && x.field1==value1....)的形式 - if (exp != null) - { - var any = Expression.Call( - typeof(Enumerable), - "Any", - new Type[] { typeof(V) }, - Expression.Property(para, _middleExp.GetPropertyName()), - Expression.Lambda>(exp, new ParameterExpression[] { midPara })); - allExp.Add(any); - } - } - //拼接多个any函数形成 .Any(x=> x.field==value && x.field1==value1....) || .Any(x=> x.field==value && x.field1==value1....)的形式并返回 - if (allExp.Count == 1) - { - rv = allExp[0]; - } - if (allExp.Count > 1) - { - rv = Expression.OrElse(allExp[0], allExp[1]); - for (int i = 2; i < allExp.Count; i++) - { - rv = Expression.OrElse(rv, allExp[i]); - } - } - return rv; - } - - /// - /// 获取字段属性 - /// - /// 字段属性列表 - public override List GetProperties() - { - List rv = new List(); - foreach (var subField in _subFieldExps) - { - var pro = subField.GetPropertyInfo(); - if (pro != null) - { - rv.Add(pro); - } - } - return rv; - } - } -} diff --git a/Vampirewal.Core/Support/DynamicData.cs b/Vampirewal.Core/Support/DynamicData.cs deleted file mode 100644 index feb362bf6517731ca52c7a5747eb94386e62728a..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/Support/DynamicData.cs +++ /dev/null @@ -1,76 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:DynamicData -// 创 建 者:杨程 -// 创建时间:2021/9/15 14:09:59 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.Dynamic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Vampirewal.Core.Support -{ - public class DynamicData : DynamicObject - { - public Dictionary Fields = new Dictionary(); - - public int Count { get { return Fields.Keys.Count; } } - - public void Add(string name, object val = null) - { - if (!Fields.ContainsKey(name)) - { - Fields.Add(name, val); - } - else - { - Fields[name] = val; - } - } - - public override bool TryGetMember(GetMemberBinder binder, out object result) - { - if (Fields.ContainsKey(binder.Name)) - { - result = Fields[binder.Name]; - return true; - } - return base.TryGetMember(binder, out result); - } - - public override bool TrySetMember(SetMemberBinder binder, object value) - { - if (!Fields.ContainsKey(binder.Name)) - { - Fields.Add(binder.Name, value); - } - else - { - Fields[binder.Name] = value; - } - return true; - } - - public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) - { - if (Fields.ContainsKey(binder.Name) && - Fields[binder.Name] is Delegate) - { - Delegate del = Fields[binder.Name] as Delegate; - result = del.DynamicInvoke(args); - return true; - } - return base.TryInvokeMember(binder, args, out result); - } - } -} diff --git a/Vampirewal.Core/Support/ExpressionVisitors.cs b/Vampirewal.Core/Support/ExpressionVisitors.cs deleted file mode 100644 index 0c53062d26bc70f09a76862bd8529198f4023686..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/Support/ExpressionVisitors.cs +++ /dev/null @@ -1,720 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:ExpressionVisitors -// 创 建 者:杨程 -// 创建时间:2021/9/16 10:51:30 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using Microsoft.EntityFrameworkCore.Query.Internal; -using Vampirewal.Core.Extensions; -using Vampirewal.Core.Helper; -using Vampirewal.Core.Models; - -namespace Vampirewal.Core -{ - /// - /// 分析x==y这种类型的表达式,并储存在Dictionary中 - /// - public class SetValuesParser : ExpressionVisitor - { - private Dictionary _rv = new Dictionary(); - - /// - /// 开始分析表达式 - /// - /// 源表达式 - /// 将x==y这种表达式变为Dictionary并返回 - public Dictionary Parse(Expression expression) - { - Visit(expression); - return _rv; - } - - /// - /// 处理所有二进制类型的表达式 - /// - /// 当前表达式节点 - /// 修改后的表达式 - protected override Expression VisitBinary(BinaryExpression node) - { - //如果表达式是x==y的类型,则获取y的值,并使用x最为key,y的值作为value添加到Dictionary中保存 - if (node.NodeType == ExpressionType.Equal) - { - var pi = PropertyHelper.GetPropertyName(node.Left.NodeType == ExpressionType.Convert ? ((UnaryExpression)node.Left).Operand : node.Left); - if (!_rv.ContainsKey(pi)) - { - _rv.Add(pi, Expression.Lambda(node.Right).Compile().DynamicInvoke()); - } - } - return base.VisitBinary(node); - } - } - - /// - /// 替换表达式中的OrderBy语句 - /// - public class OrderReplaceModifier : ExpressionVisitor - { - private bool _addMode = false; - private SortInfo _sortinfo; - - /// - /// 构造函数 - /// - /// sortinfo - public OrderReplaceModifier(SortInfo sortinfo) - { - _sortinfo = sortinfo; - } - - /// - /// 获取表达式的源数据类 - /// - /// 表达式 - /// 表达式的源数据类型 - private Type GetDCModel(Expression expression) - { - //如果表达式是方法调用的类型,则一直向上寻找,知道找到参数为ObjectQuery<>的表达式,它的类型就是整个表达式的源数据类型 - if (expression.NodeType == ExpressionType.Call) - { - var exp = (expression as MethodCallExpression).Arguments[0]; - if (exp.Type.IsGeneric(typeof(EntityQueryable<>))) - { - return exp.Type.GenericTypeArguments[0]; - } - else - { - return GetDCModel(exp); - } - } - else - { - return null; - } - } - - /// - /// 修改where - /// - /// 表达式 - /// 修改后的表达式 - public Expression Modify(Expression expression) - { - //先调用一次Visit,删除所有的where表达式 - var rv = Visit(expression); - if (rv.NodeType == ExpressionType.Constant) - { - if ((rv.Type.IsGeneric(typeof(EntityQueryable<>)) || rv.Type.IsGeneric(typeof(EnumerableQuery<>)))) - { - var modelType = rv.Type.GenericTypeArguments[0]; - ParameterExpression pe = Expression.Parameter(modelType, "x"); - Expression left1 = Expression.Constant(1); - Expression right1 = Expression.Constant(1); - Expression trueExp = Expression.Equal(left1, right1); - rv = Expression.Call( - typeof(Queryable), - "Where", - new Type[] { modelType }, - rv, - Expression.Lambda(trueExp, new ParameterExpression[] { pe })); - - } - } - //将模式设为addMode,再调用一次Visit来添加新的表达式 - _addMode = true; - rv = Visit(rv); - return rv; - } - - /// - /// 向表达式树上层寻找不是where的节点 - /// - /// 表达式 - /// 返回表达式上层第一个不是where的节点 - private Expression GetParentExpNotOrder(MethodCallExpression exp) - { - var parentNode = exp.Arguments[0] as MethodCallExpression; - if (parentNode == null || (parentNode.Method.Name.ToLower() != "orderby" && parentNode.Method.Name.ToLower() != "orderbydescending")) - { - if (parentNode == null) - { - return exp.Arguments[0]; - } - return parentNode; - } - else - { - return GetParentExpNotOrder(parentNode); - } - } - - /// - /// 检查方法调用类型的表达式 - /// - /// 表达式节点 - /// 修改后的表达式 - protected override Expression VisitMethodCall(MethodCallExpression node) - { - //如果不是添加模式,那么删除所有的order - if (_addMode == false) - { - var aType = node.Arguments[0].Type; - //如果节点是order - if (node != null && (node.Method.Name.ToLower() == "orderby" || node.Method.Name.ToLower() == "orderbydescending" || node.Method.Name.ToLower() == "thenby" || node.Method.Name.ToLower() == "thenbydescending") && aType.GetTypeInfo().IsGenericType) - { - //继续往上找到不是where的节点 - return GetParentExpNotOrder(node); - } - } - //如果是添加模式 - else - { - var modelType = node.Type.GenericTypeArguments[0]; - List info = new List() { _sortinfo }; - Expression rv = null; - foreach (var item in info) - { - var idproperty = modelType.GetProperties().Where(x => x.Name == item.Property).FirstOrDefault(); - if (idproperty == null) - { - return node; - } - var reftype = idproperty.DeclaringType; - ParameterExpression pe = Expression.Parameter(modelType, "x"); - Expression pro = Expression.Property(pe, reftype.GetProperties().Where(x => x.Name == item.Property).FirstOrDefault()); - Type proType = idproperty.PropertyType; - if (item.Direction == SortDir.Asc) - { - if (rv == null) - { - rv = Expression.Call( - typeof(Queryable), - "OrderBy", - new Type[] { modelType, proType }, - node, - Expression.Lambda(pro, new ParameterExpression[] { pe })); - } - else - { - rv = Expression.Call( - typeof(Queryable), - "ThenBy", - new Type[] { modelType, proType }, - rv, - Expression.Lambda(pro, new ParameterExpression[] { pe })); - } - } - if (item.Direction == SortDir.Desc) - { - if (rv == null) - { - rv = Expression.Call( - typeof(Queryable), - "OrderByDescending", - new Type[] { modelType, proType }, - node, - Expression.Lambda(pro, new ParameterExpression[] { pe })); - } - else - { - rv = Expression.Call( - typeof(Queryable), - "ThenByDescending", - new Type[] { modelType, proType }, - rv, - Expression.Lambda(pro, new ParameterExpression[] { pe })); - } - } - } - return rv; - - } - return base.VisitMethodCall(node); - } - } - - - /// - /// 替换表达式中的Where语句 - /// - public class WhereReplaceModifier : ExpressionVisitor where T : TopBaseModel - { - private Type _modelType; - private bool _addMode = false; - private Expression> _where; - - /// - /// 构造函数 - /// - /// 需要替换的新where语句 - public WhereReplaceModifier(Expression> where) - { - _where = where; - } - - /// - /// 获取表达式的源数据类 - /// - /// 表达式 - /// 表达式的源数据类型 - private Type GetDCModel(Expression expression) - { - //如果表达式是方法调用的类型,则一直向上寻找,知道找到参数为ObjectQuery<>的表达式,它的类型就是整个表达式的源数据类型 - if (expression.NodeType == ExpressionType.Call) - { - var exp = (expression as MethodCallExpression).Arguments[0]; - if (exp.Type.IsGeneric(typeof(EntityQueryable<>))) - { - return exp.Type.GenericTypeArguments[0]; - } - else - { - return GetDCModel(exp); - } - } - else if (expression.NodeType == ExpressionType.Constant) - { - if (expression.Type.IsGeneric(typeof(EnumerableQuery<>))) - { - return expression.Type.GenericTypeArguments[0]; - } - else - { - return null; - } - } - else - { - return null; - } - } - - /// - /// 修改where - /// - /// 表达式 - /// 修改后的表达式 - public Expression Modify(Expression expression) - { - //获取源类型 - var checkType = GetDCModel(expression); - - if (checkType != null) - { - _modelType = checkType; - //先调用一次Visit,删除所有的where表达式 - var rv = Visit(expression); - //将模式设为addMode,再调用一次Visit来添加新的表达式 - _addMode = true; - rv = Visit(rv); - return rv; - } - else - { - return expression; - } - } - - /// - /// 向表达式树上层寻找不是where的节点 - /// - /// 表达式 - /// 返回表达式上层第一个不是where的节点 - private Expression GetParentExpNotWhere(MethodCallExpression exp) - { - if (!(exp.Arguments[0] is MethodCallExpression parentNode)) - { - return exp.Arguments[0]; - } - else if (parentNode.Method.Name.ToLower() != "where") - { - return parentNode; - } - else - { - return GetParentExpNotWhere(parentNode); - } - } - - protected override Expression VisitConstant(ConstantExpression node) - { - if (_addMode == true) - { - if ((node.Type.IsGeneric(typeof(EntityQueryable<>)) || node.Type.IsGeneric(typeof(EnumerableQuery<>))) && node.Type.GenericTypeArguments[0] == _modelType) - { - ParameterExpression pe = Expression.Parameter(_modelType); - ChangePara cp = new ChangePara(); - //传递过来的where条件,其源类型不一定和表达式中原有的相符,所以先将新where条件的源类型修改成和query一样的 - //也就是说新的where条件可能是 x=>x.id==1, 而在表达式中不一定有x,所以要先统一 - var modifiedWhere = cp.Change(_where.Body, pe); - var rv = Expression.Call( - typeof(Queryable), - "Where", - new Type[] { _modelType }, - node, - Expression.Lambda(modifiedWhere, new ParameterExpression[] { pe })); - return rv; - } - } - return base.VisitConstant(node); - } - - /// - /// 检查方法调用类型的表达式 - /// - /// 表达式节点 - /// 修改后的表达式 - protected override Expression VisitMethodCall(MethodCallExpression node) - { - //如果不是添加模式,那么删除所有的where条件 - if (_addMode == false) - { - if (node.Arguments.Count == 0) - { - return base.VisitMethodCall(node); - } - var aType = node.Arguments[0].Type; - //如果节点的上一个节点是where - if (node.Arguments[0] is MethodCallExpression parentNode && parentNode.Method.Name.ToLower() == "where" && aType.GetTypeInfo().IsGenericType) - { - //继续往上找到不是where的节点 - var nowhereNode = GetParentExpNotWhere(parentNode); - Type gType = aType.GetGenericTypeDefinition(); - Type argType = aType.GenericTypeArguments[0]; - //使用上面不是where的节点直接拼接本节点,从而删除了中间的where - if ((gType == typeof(IQueryable<>) || gType == typeof(EntityQueryable<>)) && argType == _modelType) - { - var paras = new List - { - nowhereNode - }; - paras.AddRange(node.Arguments.Skip(1).ToList()); - var rv = Expression.Call( - node.Method, - paras); - return rv; - } - } - } - return base.VisitMethodCall(node); - } - } - - /// - /// 用于PersistPoco的搜索,检查查询语句中是否有IsValid的搜索条件,如果没有,默认加上IsValid=true - /// - public class IsValidModifier : ExpressionVisitor - { - private Type _modelType; - private bool _needAdd = true; - private int _mode = 0; //0是搜素模式,1是添加模式 - private Expression> _where; - - /// - /// 构造函数 - /// - public IsValidModifier() - { - _where = x => x.IsValid == true; - } - - /// - /// 获取表达式的源数据类 - /// - /// 表达式 - /// 表达式的源数据类型 - private Type GetDCModel(Expression expression) - { - //如果表达式是方法调用的类型,则一直向上寻找,知道找到参数为ObjectQuery<>的表达式,它的类型就是整个表达式的源数据类型 - if (expression.NodeType == ExpressionType.Call) - { - var exp = (expression as MethodCallExpression).Arguments[0]; - if (exp.Type.IsGeneric(typeof(EntityQueryable<>))) - { - return exp.Type.GenericTypeArguments[0]; - } - else - { - return GetDCModel(exp); - } - } - else if (expression.NodeType == ExpressionType.Constant) - { - if (expression.Type.IsGeneric(typeof(EntityQueryable<>)) || expression.Type.IsGeneric(typeof(EnumerableQuery<>))) - { - return expression.Type.GenericTypeArguments[0]; - } - else - { - return null; - } - } - else - { - return null; - } - } - - /// - /// 修改where - /// - /// 表达式 - /// 修改后的表达式 - public Expression Modify(Expression expression) - { - //获取源类型 - var checkType = GetDCModel(expression); - - if (checkType != null && checkType.IsSubclassOf(typeof(PersistModel))) - { - _modelType = checkType; - //先调用一次Visit,删除所有的where表达式 - var rv = Visit(expression); - //将模式设为addMode,再调用一次Visit来添加新的表达式 - if (_needAdd == true) - { - _mode = 1; - rv = Visit(rv); - } - return rv; - } - else - { - return expression; - } - } - - /// - /// 向表达式树上层寻找不是where的节点 - /// - /// 表达式 - /// 返回表达式上层第一个不是where的节点 - private Expression GetParentExpNotWhere(MethodCallExpression exp) - { - if (!(exp.Arguments[0] is MethodCallExpression parentNode)) - { - return exp.Arguments[0]; - } - else if (parentNode.Method.Name.ToLower() != "where") - { - return parentNode; - } - else - { - return GetParentExpNotWhere(parentNode); - } - } - - protected override Expression VisitConstant(ConstantExpression node) - { - if (_mode == 1) - { - if ((node.Type.IsGeneric(typeof(EntityQueryable<>)) || node.Type.IsGeneric(typeof(EnumerableQuery<>))) && node.Type.GenericTypeArguments[0] == _modelType) - { - ParameterExpression pe = Expression.Parameter(_modelType); - ChangePara cp = new ChangePara(); - //传递过来的where条件,其源类型不一定和表达式中原有的相符,所以先将新where条件的源类型修改成和query一样的 - //也就是说新的where条件可能是 x=>x.id==1, 而在表达式中不一定有x,所以要先统一 - var modifiedWhere = cp.Change(_where.Body, pe); - var rv = Expression.Call( - typeof(Queryable), - "Where", - new Type[] { _modelType }, - node, - Expression.Lambda(modifiedWhere, new ParameterExpression[] { pe })); - return rv; - } - } - return base.VisitConstant(node); - } - - /// - /// 查找where中是否出现过对于IsValid的判断 - /// - /// - /// - protected override Expression VisitBinary(BinaryExpression node) - { - //如果表达式是x==y的类型,则获取y的值,并使用x最为key,y的值作为value添加到Dictionary中保存 - if (_mode == 0) - { - if (node.NodeType == ExpressionType.Equal) - { - var pi = PropertyHelper.GetPropertyName(node.Left); - if (pi.ToLower() == "isvalid") - { - _needAdd = false; - } - } - } - return base.VisitBinary(node); - } - - } - - - /// - /// 修改表达式参数 - /// - public class ChangePara : ExpressionVisitor - { - ParameterExpression _pe; - - /// - /// 修改参数 - /// - /// 要修改的表达式 - /// 新的参数 - /// 修改后的表达式 - public Expression Change(Expression expression, ParameterExpression pe) - { - _pe = pe; - return Visit(expression); - } - - /// - /// 检查所有参数类型的表达式 - /// - /// 表达式节点 - /// 新的参数类型 - protected override Expression VisitParameter(ParameterExpression node) - { - return _pe; - } - - /// - /// 检查所有成员访问类型的表达式 - /// - /// 表达式节点 - /// 修改后的表达式 - protected override Expression VisitMember(MemberExpression node) - { - if (node.Expression.NodeType == ExpressionType.Parameter) - { - var rv = Expression.MakeMemberAccess(_pe, node.Member); - return rv; - } - else - { - return base.VisitMember(node); - } - } - } - - /// - /// 获取Select语句中选择的列的信息 - /// - public class SelectInfo : ExpressionVisitor - { - private List _columns; - private bool _found; - /// - /// 构造函数 - /// - public SelectInfo() - { - } - - /// - /// 获取Select语句中选择的列的名字 - /// - /// 表达式 - /// 列的名字 - public List GetColumns(Expression expression) - { - Visit(expression); - return _columns; - } - - - /// - /// 检查方法调用类型的表达式 - /// - /// 表达式节点 - /// 修改后的表达式 - protected override Expression VisitMethodCall(MethodCallExpression node) - { - if (_found == false) - { - if (node.Method.Name.ToLower() == "select") - { - if (node.Arguments[1] is UnaryExpression ue) - { - var inner = ue.Operand as LambdaExpression; - if (inner.Body is MemberInitExpression memberinit) - { - _columns = new List(); - foreach (var m in memberinit.Bindings) - { - _columns.Add(m.Member.Name); - } - _found = true; - } - } - } - } - return base.VisitMethodCall(node); - } - } - - public class ClearSelectMany : ExpressionVisitor - { - /// - /// 构造函数 - /// - public ClearSelectMany() - { - } - - /// - /// 获取Select语句中选择的列的名字 - /// - /// 表达式 - /// 列的名字 - public Expression Clear(Expression expression) - { - return Visit(expression); - } - - protected override Expression VisitMemberInit(MemberInitExpression node) - { - List newbinding = new List(); - for (int i = 0; i < node.Bindings.Count; i++) - { - bool islist = false; - if (node.Bindings[i] is MemberAssignment ma && ma.Expression.Type.GetTypeInfo().IsGenericType == true) - { - if (ma.Expression.Type.GetGenericTypeDefinition() != typeof(Nullable<>)) - { - islist = true; - } - } - if (islist == false) - { - newbinding.Add(node.Bindings[i]); - } - } - if (newbinding.Count < node.Bindings.Count) - { - return node.Update(node.NewExpression, newbinding); - } - else - { - return base.VisitMemberInit(node); - } - } - } -} diff --git a/Vampirewal.Core/Tools/AnimationHelper.cs b/Vampirewal.Core/Tools/AnimationHelper.cs new file mode 100644 index 0000000000000000000000000000000000000000..9a542575355549993c43a2f64eeaa9ae6ec13ee9 --- /dev/null +++ b/Vampirewal.Core/Tools/AnimationHelper.cs @@ -0,0 +1,145 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:AnimationHelper +// 创 建 者:杨程 +// 创建时间:2022/3/17 9:27:35 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.Tools; + +/// +/// 动画帮助类 +/// +public class AnimationHelper +{ + /// + /// 渐影动画 + /// + /// 控件对象 + /// 播放时间长度 + /// 延迟播放时间 + public static void CtrlDoubleAnimation(UIElement element, double seconds, double lateSeconds) + { + element.Visibility = Visibility.Collapsed; + DoubleAnimation doubleAnimation = new DoubleAnimation(); + doubleAnimation.From = 0; + doubleAnimation.To = 1; + doubleAnimation.Duration = TimeSpan.FromMilliseconds(seconds); + EventHandler handler; + doubleAnimation.Completed += handler = (s, e) => { + element.Visibility = Visibility.Visible; + }; + doubleAnimation.BeginTime = TimeSpan.FromMilliseconds(lateSeconds); + element.BeginAnimation(UIElement.OpacityProperty, doubleAnimation); + + } + + /// + /// 透明度动画 + /// + /// + /// + public static void FloatElement(UIElement elem, double to, double mseconds, double mlateSeconds) + { + lock (elem) + { + if (to == 1) + { + elem.Visibility = Visibility.Collapsed; + } + //else + //{ + // elem.Visibility = Visibility.Visible; + //} + DoubleAnimation opacity = new DoubleAnimation() + { + To = to, + Duration = TimeSpan.FromMilliseconds(mseconds), + BeginTime = TimeSpan.FromMilliseconds(mlateSeconds) + }; + EventHandler handler = null; + opacity.Completed += handler = (s, e) => + { + opacity.Completed -= handler; + if (to == 1) + { + elem.Visibility = Visibility.Visible; + } + //else + //{ + // elem.Visibility = Visibility.Visible; + //} + opacity = null; + }; + elem.BeginAnimation(UIElement.OpacityProperty, opacity); + } + } + + + /// + /// 支撑同时旋转和缩放的动画 + /// + /// 控件 + /// 元素开始的大小 + /// 元素到达的大小 + /// 动画世界 + /// 结束事件 + public static void ScaleRotateEasingAnimationShow(UIElement element, double from, double to, double mseconds, double mlateSeconds, EventHandler completed) + { + //旋转 + RotateTransform angle = new RotateTransform(); + + //缩放 + ScaleTransform scale = new ScaleTransform(); + TransformGroup group = new TransformGroup(); + group.Children.Add(scale); + group.Children.Add(angle); + element.RenderTransform = group; + + //定义圆心位置 + element.RenderTransformOrigin = new Point(0.5, 0.5); + EasingFunctionBase easeFunction = new PowerEase() + { + EasingMode = EasingMode.EaseInOut, + Power = 2 + }; + + // 动画参数 + DoubleAnimation scaleAnimation = new DoubleAnimation() + { + From = from, + To = to, + EasingFunction = easeFunction, + Duration = TimeSpan.FromMilliseconds(mseconds), + BeginTime = TimeSpan.FromMilliseconds(mlateSeconds), + FillBehavior = FillBehavior.Stop + }; + + // 动画参数 + DoubleAnimation angleAnimation = new DoubleAnimation() + { + From = 0, + To = 360, + EasingFunction = easeFunction, + Duration = TimeSpan.FromMilliseconds(mseconds), + BeginTime = TimeSpan.FromMilliseconds(mlateSeconds), + FillBehavior = FillBehavior.Stop, + + }; + angleAnimation.Completed += completed; + + // 执行动画 + scale.BeginAnimation(ScaleTransform.ScaleXProperty, scaleAnimation); + scale.BeginAnimation(ScaleTransform.ScaleYProperty, scaleAnimation); + angle.BeginAnimation(RotateTransform.AngleProperty, angleAnimation); + } +} diff --git a/Vampirewal.Core/Tools/BaseSingleton.cs b/Vampirewal.Core/Tools/BaseSingleton.cs index d0565d0d3d7b014cc94105fe15cfb75ba4721963..b2094fa5975541772e13f06c7f3e4cf8f8cb214d 100644 --- a/Vampirewal.Core/Tools/BaseSingleton.cs +++ b/Vampirewal.Core/Tools/BaseSingleton.cs @@ -11,35 +11,36 @@ //----------------------------------------------------------------*/ #endregion -using System; -using System.Collections.Generic; -using System.Text; -using Vampirewal.Core.SimpleMVVM; -namespace Vampirewal.Core + + +namespace Vampirewal.Core; + +/// +/// 所有使用单例模式的基类,需要被继承 +/// +/// 填写类的名称 +public class BaseSingleton : ObservableObject where T : new() { + private static T _instance; + private static object _objLock = new object(); /// - /// 所有使用单例模式的基类,需要被继承 + /// 获取单例实例 /// - /// 填写类的名称 - public class BaseSingleton : NotifyBase where T : new() + /// + public static T GetInstance() { - private static T _instance; - private static object _objLock = new object(); - public static T GetInstance() - { - if (_instance == null) + if (_instance == null) + { + lock (_objLock) { - lock (_objLock) + if (_instance == null) { - if (_instance == null) - { - _instance = new T(); - } + _instance = new T(); } } - return _instance; } + return _instance; } } diff --git a/Vampirewal.Core/Tools/DESHelper.cs b/Vampirewal.Core/Tools/DESHelper.cs index 566bcc9d781a924835e98096a36eac16198ec7fb..23f146933ed218754ea80d69925391523179e226 100644 --- a/Vampirewal.Core/Tools/DESHelper.cs +++ b/Vampirewal.Core/Tools/DESHelper.cs @@ -11,96 +11,90 @@ //----------------------------------------------------------------*/ #endregion -using System; -using System.Collections.Generic; -using System.IO; -using System.Security.Cryptography; -using System.Text; -namespace Vampirewal.Core + + +namespace Vampirewal.Core; + +public class DESHelper { - public class DESHelper - { - /// - /// 加密/解密 密钥 - /// - private const string DES_KEY = "AAAA"; + /// + /// 加密/解密 密钥 + /// + private const string DES_KEY = "AAAA"; - #region 3DES 加解密 - /// - /// 3DES加密 - /// - /// 需要加密的文本 - /// 密钥 - /// - public static string Encrypt3Des(string encryStr, string key = DES_KEY) + #region 3DES 加解密 + /// + /// 3DES加密 + /// + /// 需要加密的文本 + /// 密钥 + /// + public static string Encrypt3Des(string encryStr, string key = DES_KEY) + { + try { - try + var inputArry = Encoding.Default.GetBytes(encryStr); + var hashmd5 = new MD5CryptoServiceProvider(); + var byKey = hashmd5.ComputeHash(Encoding.Default.GetBytes(key)); + var byIv = byKey; + var ms = new MemoryStream(); + using (var tDescryptProvider = new TripleDESCryptoServiceProvider()) { - var inputArry = Encoding.Default.GetBytes(encryStr); - var hashmd5 = new MD5CryptoServiceProvider(); - var byKey = hashmd5.ComputeHash(Encoding.Default.GetBytes(key)); - var byIv = byKey; - var ms = new MemoryStream(); - using (var tDescryptProvider = new TripleDESCryptoServiceProvider()) + tDescryptProvider.Mode = CipherMode.ECB; + using (var cs = new CryptoStream(ms, tDescryptProvider.CreateEncryptor(byKey, byIv), CryptoStreamMode.Write)) { - tDescryptProvider.Mode = CipherMode.ECB; - using (var cs = new CryptoStream(ms, tDescryptProvider.CreateEncryptor(byKey, byIv), CryptoStreamMode.Write)) - { - cs.Write(inputArry, 0, inputArry.Length); - cs.FlushFinalBlock(); - cs.Close(); - } + cs.Write(inputArry, 0, inputArry.Length); + cs.FlushFinalBlock(); + cs.Close(); } - - var str = Convert.ToBase64String(ms.ToArray()); - ms.Close(); - return str; } - catch (Exception) - { - return encryStr; - } - + var str = Convert.ToBase64String(ms.ToArray()); + ms.Close(); + return str; + } + catch (Exception) + { + return encryStr; } - /// - /// 解密 - /// - /// 待解密的密码 - /// 密钥 - /// - public static string Decrypt3Des(string decryStr, string key = DES_KEY) + } + + /// + /// 解密 + /// + /// 待解密的密码 + /// 密钥 + /// + public static string Decrypt3Des(string decryStr, string key = DES_KEY) + { + try { - try + var inputArry = Convert.FromBase64String(decryStr); + var hashmd5 = new MD5CryptoServiceProvider(); + var byKey = hashmd5.ComputeHash(Encoding.Default.GetBytes(key)); + var byIv = byKey; + var ms = new MemoryStream(); + using (var tDescryptProvider = new TripleDESCryptoServiceProvider()) { - var inputArry = Convert.FromBase64String(decryStr); - var hashmd5 = new MD5CryptoServiceProvider(); - var byKey = hashmd5.ComputeHash(Encoding.Default.GetBytes(key)); - var byIv = byKey; - var ms = new MemoryStream(); - using (var tDescryptProvider = new TripleDESCryptoServiceProvider()) + tDescryptProvider.Mode = CipherMode.ECB; + using (var cs = new CryptoStream(ms, tDescryptProvider.CreateDecryptor(byKey, byIv), CryptoStreamMode.Write)) { - tDescryptProvider.Mode = CipherMode.ECB; - using (var cs = new CryptoStream(ms, tDescryptProvider.CreateDecryptor(byKey, byIv), CryptoStreamMode.Write)) - { - cs.Write(inputArry, 0, inputArry.Length); - cs.FlushFinalBlock(); - cs.Close(); - } + cs.Write(inputArry, 0, inputArry.Length); + cs.FlushFinalBlock(); + cs.Close(); } - - var str = Encoding.Default.GetString(ms.ToArray()); - ms.Close(); - return str; - } - catch (Exception) - { - return decryStr; } + var str = Encoding.Default.GetString(ms.ToArray()); + ms.Close(); + return str; + } + catch (Exception) + { + return decryStr; } + } - #endregion - } + #endregion } \ No newline at end of file diff --git a/Vampirewal.Core/Tools/DateTimeHelper.cs b/Vampirewal.Core/Tools/DateTimeHelper.cs new file mode 100644 index 0000000000000000000000000000000000000000..b0c75631de16924d78f8ae10ee3c5e5f48ec67ea --- /dev/null +++ b/Vampirewal.Core/Tools/DateTimeHelper.cs @@ -0,0 +1,94 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:DateTimeHelper +// 创 建 者:杨程 +// 创建时间:2021/9/15 11:31:19 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.Tools; + +/// +/// DateTime Helper +/// +public static class DateTimeHelper +{ + #region DateTime Helper + + public static int WeekOfYear(this DateTime self) + { + var startDayOfYear = new DateTime(self.Year, 1, 1); + var weekOffset = 7 - (startDayOfYear.DayOfWeek == DayOfWeek.Sunday ? 7 : (int)startDayOfYear.DayOfWeek) + 1; + var weekOfYear = (int)Math.Ceiling((self.DayOfYear - weekOffset) / 7.0 + (weekOffset == 0 ? 0 : 1)); + + return weekOfYear; + } + + /// + /// 获取 指定的一周所在年份 的开始及结束时间 + /// + /// 所在年份 + /// 周数 + /// 指定周开始时间 + /// 指定周结束时间 + public static void WeekDays(int yearNum, int weekOfYear, out DateTime startDay, out DateTime endDay) + { + var startDayOfYear = new DateTime(yearNum, 1, 1, 0, 0, 0); + + var weekOffset = 7 - (startDayOfYear.DayOfWeek == DayOfWeek.Sunday ? 7 : (int)startDayOfYear.DayOfWeek) + 1; + startDay = startDayOfYear.AddDays(7 * (weekOfYear - (weekOffset == 0 ? 0 : 1)) + weekOffset - 7); + endDay = startDay.AddDays(7); + } + + #endregion + + #region DateTime Extensions + + private static readonly DateTime _jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + /// + /// UTC 1970/01/01 00:00:00 + /// + public static DateTime Jan1st1970 => _jan1st1970; + + /// + /// 时间戳 ms + /// + /// + /// 返回标准时间戳 单位 毫秒 注:从 1970/01/01 00:00:00 开始 + public static long ToMilliseconds(this DateTime self) + { + return (long)(self.ToUniversalTime() - Jan1st1970).TotalMilliseconds; + } + + /// + /// 时间戳 microsecond + /// + /// + /// 返回标准时间戳 单位 微秒 注:从 1970/01/01 00:00:00 开始 + public static long ToMicroseconds(this DateTime self) + { + return (long)((self.ToUniversalTime() - Jan1st1970).TotalMilliseconds * 1000); + } + + /// + /// 获取当前时间所在周的开始及结束时间 + /// + /// + /// 指定周开始时间 + /// 指定周结束时间 + public static void WeekDays(this DateTime self, out DateTime startDay, out DateTime endDay) + { + WeekDays(self.Year, self.WeekOfYear(), out startDay, out endDay); + } + + #endregion +} diff --git a/Vampirewal.Core/Tools/DynamicData.cs b/Vampirewal.Core/Tools/DynamicData.cs new file mode 100644 index 0000000000000000000000000000000000000000..8cf830b06c6743649afdd50658477e7c6677391f --- /dev/null +++ b/Vampirewal.Core/Tools/DynamicData.cs @@ -0,0 +1,71 @@ +#region << 文 件 说 明 >> + +/*---------------------------------------------------------------- +// 文件名称:DynamicData +// 创 建 者:杨程 +// 创建时间:2021/9/15 14:09:59 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ + +#endregion + +namespace Vampirewal.Core.Tools; + +public class DynamicData : DynamicObject +{ + public Dictionary Fields = new Dictionary(); + + public int Count + { get { return Fields.Keys.Count; } } + + public void Add(string name, object val = null) + { + if (!Fields.ContainsKey(name)) + { + Fields.Add(name, val); + } + else + { + Fields[name] = val; + } + } + + public override bool TryGetMember(GetMemberBinder binder, out object result) + { + if (Fields.ContainsKey(binder.Name)) + { + result = Fields[binder.Name]; + return true; + } + return base.TryGetMember(binder, out result); + } + + public override bool TrySetMember(SetMemberBinder binder, object value) + { + if (!Fields.ContainsKey(binder.Name)) + { + Fields.Add(binder.Name, value); + } + else + { + Fields[binder.Name] = value; + } + return true; + } + + public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) + { + if (Fields.ContainsKey(binder.Name) && + Fields[binder.Name] is Delegate) + { + Delegate del = Fields[binder.Name] as Delegate; + result = del.DynamicInvoke(args); + return true; + } + return base.TryInvokeMember(binder, args, out result); + } +} \ No newline at end of file diff --git a/Vampirewal.Core/Tools/EntityHelper.cs b/Vampirewal.Core/Tools/EntityHelper.cs new file mode 100644 index 0000000000000000000000000000000000000000..c35e27d2b01d7f30ebb90576b3ebbb098ead0abc --- /dev/null +++ b/Vampirewal.Core/Tools/EntityHelper.cs @@ -0,0 +1,174 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:EntityHelper +// 创 建 者:杨程 +// 创建时间:2021/9/15 11:44:08 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.Tools; + +/// +/// DataTable和Entity之间转换的辅助类 +/// +public static class EntityHelper +{ + /// + /// 根据DataTable获取Entity列表 + /// + /// Entity类型 + /// DataTable + /// Entity列表 + public static IList GetEntityList(DataTable table) + { + IList entityList = new List(); + + if (typeof(T) == typeof(DynamicData)) + { + foreach (DataRow row in table.Rows) + { + //新建Entity + T entity = (T)Activator.CreateInstance(typeof(T)); + foreach (DataColumn col in table.Columns) + { + (entity as DynamicData).Add(col.ColumnName, row[col] == DBNull.Value ? null : row[col]); + } + entityList.Add(entity); + } + } + else + { + var properties = typeof(T).GetProperties().ToLookup(property => property.Name, property => property).ToDictionary(i => i.Key, i => i.First()).Values; + + //循环Datable中的每一行 + foreach (DataRow row in table.Rows) + { + //新建Entity + T entity = (T)Activator.CreateInstance(typeof(T)); + //循环Entity的每一个属性 + foreach (var item in properties) + { + //如果DataTable中有列名和属性名一致,则把单元格内容赋值给Entity的该属性 + if (row.Table.Columns.Contains(item.Name)) + { + //判断null值 + if (string.IsNullOrEmpty(row[item.Name].ToString())) + { + item.SetValue(entity, null); + } + else + { + var ptype = item.PropertyType; + //if (ptype.IsNullable()) + //{ + // ptype = ptype.GenericTypeArguments[0]; + //} + //如果是Guid或Guid?类型 + if (ptype == typeof(Guid)) + { + item.SetValue(entity, Guid.Parse(row[item.Name].ToString())); + } + //如果是enum或enum?类型 + else if (ptype.IsEnum) + { + item.SetValue(entity, Enum.ToObject(ptype, row[item.Name])); + } + else + { + item.SetValue(entity, Convert.ChangeType(row[item.Name], ptype)); + } + + } + } + } + entityList.Add(entity); + } + } + return entityList; + } + + #region 实体类转换成DataTable + + /// + /// 实体类转换成DataSet + /// + /// 实体类列表 + /// DataSet + public static DataSet ToDataSet(List modelList) where T : new() + { + if (modelList == null || modelList.Count == 0) + { + return null; + } + else + { + DataSet ds = new DataSet(); + ds.Tables.Add(ToDataTable(modelList)); + return ds; + } + } + + /// + /// 实体类转换成DataTable + /// + /// 实体类列表 + /// DataTable + public static DataTable ToDataTable(List modelList) where T : new() + { + if (modelList == null || modelList.Count == 0) + { + return null; + } + DataTable dt = CreateData(modelList[0]); + + foreach (T model in modelList) + { + DataRow dataRow = dt.NewRow(); + //循环实体类所有属性,给对应的DataTable字段赋值 + foreach (PropertyInfo propertyInfo in typeof(T).GetProperties()) + { + var res = propertyInfo.GetValue(model); + dataRow[propertyInfo.Name] = res ?? DBNull.Value; + } + dt.Rows.Add(dataRow); + } + return dt; + } + + /// + /// 根据实体类得到表结构 + /// + /// 实体类 + /// DataTable + private static DataTable CreateData(T model) where T : new() + { + DataTable dataTable = new DataTable(typeof(T).Name); + foreach (PropertyInfo propertyInfo in typeof(T).GetProperties()) + { + if (propertyInfo.PropertyType.IsGenericType) + { + if (propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>) && propertyInfo.PropertyType.GenericTypeArguments.Length > 0) + { + dataTable.Columns.Add(propertyInfo.Name, propertyInfo.PropertyType.GenericTypeArguments[0]); + continue; + } + else + { + continue; + } + } + dataTable.Columns.Add(propertyInfo.Name, propertyInfo.PropertyType); + } + return dataTable; + } + + #endregion +} diff --git a/Vampirewal.Core/Tools/EnumHelper.cs b/Vampirewal.Core/Tools/EnumHelper.cs index 63d916c3c8d4a2d6eb0f45fbd8ea2a7c75836e7c..e7dd471c5cffb807664a014a66e65b24e1d8c38e 100644 --- a/Vampirewal.Core/Tools/EnumHelper.cs +++ b/Vampirewal.Core/Tools/EnumHelper.cs @@ -11,77 +11,68 @@ //----------------------------------------------------------------*/ #endregion -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using Vampirewal.Core.Attributes; -using Vampirewal.Core.Models; -namespace Vampirewal.Core + + +namespace Vampirewal.Core; + +/// +/// 枚举扩展类 +/// +public static class EnumHelper { /// - /// 枚举扩展类 + /// 获取枚举的Display文本 /// - public static class EnumHelper + /// + /// + public static String GetDisplay(this Enum value) { - /// - /// 获取枚举的Display文本 - /// - /// - /// - public static String GetDisplay(this Enum value) - { - var type = value.GetType();//先获取这个枚举的类型 - var field = type.GetField(value.ToString());//通过这个类型获取到值 - var obj = (DisplayAttribute)field.GetCustomAttribute(typeof(DisplayAttribute));//得到特性 - return obj.Name ?? ""; - } + var type = value.GetType();//先获取这个枚举的类型 + var field = type.GetField(value.ToString());//通过这个类型获取到值 + var obj = (DisplayAttribute)field.GetCustomAttribute(typeof(DisplayAttribute));//得到特性 + return obj.Name ?? ""; + } - /// - /// 获取枚举列表 - /// - /// 枚举 - /// - public static List EnumToList() - { - List list = new List(); + /// + /// 获取枚举列表 + /// + /// 枚举 + /// + public static List EnumToList() + { + List list = new List(); - foreach (var e in Enum.GetValues(typeof(T))) + foreach (var e in Enum.GetValues(typeof(T))) + { + EnumberCreditType m = new EnumberCreditType(); + object[] objArr = e.GetType().GetField(e.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), true); + if (objArr != null && objArr.Length > 0) { - EnumberCreditType m = new EnumberCreditType(); - object[] objArr = e.GetType().GetField(e.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), true); - if (objArr != null && objArr.Length > 0) - { - DescriptionAttribute da = objArr[0] as DescriptionAttribute; - m.Desction = da.Description; - } - //SetClassification - object[] setClassificationArr = e.GetType().GetField(e.ToString()).GetCustomAttributes(typeof(SetClassificationAttribute), true); - if (setClassificationArr != null && setClassificationArr.Length > 0) - { - SetClassificationAttribute da = setClassificationArr[0] as SetClassificationAttribute; - m.Classification = da.Type; - } - //Display - object[] disArr = e.GetType().GetField(e.ToString()).GetCustomAttributes(typeof(DisplayAttribute), true); - if (disArr != null && disArr.Length > 0) - { - DisplayAttribute da = disArr[0] as DisplayAttribute; - m.Name = da.Name; - } - - m.Value = Convert.ToInt32(e); - m.Key = e.ToString(); - list.Add(m); + DescriptionAttribute da = objArr[0] as DescriptionAttribute; + m.Desction = da.Description; } - return list; + //SetClassification + object[] setClassificationArr = e.GetType().GetField(e.ToString()).GetCustomAttributes(typeof(SetClassificationAttribute), true); + if (setClassificationArr != null && setClassificationArr.Length > 0) + { + SetClassificationAttribute da = setClassificationArr[0] as SetClassificationAttribute; + m.Classification = da.Type; + } + //Display + object[] disArr = e.GetType().GetField(e.ToString()).GetCustomAttributes(typeof(DisplayAttribute), true); + if (disArr != null && disArr.Length > 0) + { + DisplayAttribute da = disArr[0] as DisplayAttribute; + m.Name = da.Name; + } + + m.Value = Convert.ToInt32(e); + m.Key = e.ToString(); + list.Add(m); } + return list; } +} -} diff --git a/Vampirewal.Core/Tools/ExtraClass.cs b/Vampirewal.Core/Tools/ExtraClass.cs new file mode 100644 index 0000000000000000000000000000000000000000..9038a868253bbeeeac3d0d76977ab71e6b194936 --- /dev/null +++ b/Vampirewal.Core/Tools/ExtraClass.cs @@ -0,0 +1,68 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:ExtraClass +// 创 建 者:杨程 +// 创建时间:2021/9/16 10:53:23 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.Tools; + +/// +/// 简单属性结构类 +/// +public class SimpleTreeTextAndValue +{ + + public object Id { get; set; } + public object Text { get; set; } + public object ParentId { get; set; } +} + +/// +/// 简单键值对类,用来存著生成下拉菜单的数据 +/// +public class SimpleTextAndValue +{ + public object Text { get; set; } + public object Value { get; set; } +} + +/// +/// 数据库排序类 +/// +public class SortInfo +{ + public string Property { get; set; } + public SortDir Direction { get; set; } +} + +public class ErrorObj +{ + public Dictionary Form { get; set; } + public List Message { get; set; } +} + +/// +/// 简单传值类 +/// +public class SimplePassData +{ + /// + /// 名称 + /// + public string Key { get; set; } + + /// + /// 值 + /// + public object Value { get; set; } +} diff --git a/Vampirewal.Core/Tools/FileHelper.cs b/Vampirewal.Core/Tools/FileHelper.cs index 5ac4cff6ec07578841ede78510aa0de05794bed6..452a23535dc731b966cb63f3095061da46055a5a 100644 --- a/Vampirewal.Core/Tools/FileHelper.cs +++ b/Vampirewal.Core/Tools/FileHelper.cs @@ -1,4 +1,5 @@ #region << 文 件 说 明 >> + /*---------------------------------------------------------------- // 文件名称:FileHelper // 创 建 者:杨程 @@ -6,45 +7,41 @@ // 文件版本:V1.0.0 // =============================================================== // 功能描述: -// +// // //----------------------------------------------------------------*/ + #endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace Vampirewal.Core.Tools; -namespace Vampirewal.Core.Tools +public class FileHelper { - public class FileHelper + #region 获取文件的大小 + + private static readonly string[] suffixes = new string[] { "B", "KB", "MB", "GB", "TB", "PB" }; + + /// + /// 获取文件的大小 + /// + /// 传入获取到的文件长度 + /// 字符串 + public static string GetFileSize(long number) { - #region 获取文件的大小 - private static readonly string[] suffixes = new string[] { "B", "KB", "MB", "GB", "TB", "PB" }; - - /// - /// 获取文件的大小 - /// - /// 传入获取到的文件长度 - /// 字符串 - public static string GetFileSize(long number) + double last = 1; + for (int i = 0; i < suffixes.Length; i++) { - double last = 1; - for (int i = 0; i < suffixes.Length; i++) + var current = Math.Pow(1024, i + 1); + var temp = number / current; + if (temp < 1) { - var current = Math.Pow(1024, i + 1); - var temp = number / current; - if (temp < 1) - { - return (number / last).ToString("n2") + suffixes[i]; - } - last = current; + return (number / last).ToString("n2") + suffixes[i]; } + last = current; + } - return number.ToString(); - } - #endregion + return number.ToString(); } -} + + #endregion +} \ No newline at end of file diff --git a/Vampirewal.Core/Tools/HttpClientHelper.cs b/Vampirewal.Core/Tools/HttpClientHelper.cs deleted file mode 100644 index dd223a35b33fae866d53ae4f807966c8b2e49b0f..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/Tools/HttpClientHelper.cs +++ /dev/null @@ -1,270 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:HttpClientHelper -// 创 建 者:杨程 -// 创建时间:2021/7/28 16:13:28 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net.Http.Headers; -using System.Net.Http; -using System.Text; -using System.Threading.Tasks; -using Microsoft.Extensions.DependencyInjection; -using Newtonsoft.Json; -using System.ComponentModel.DataAnnotations; - -namespace Vampirewal.Core.Tools -{ - /// - /// 使用IHttpClientFactory的帮助类 - /// - public class HttpClientHelper - { - public static Token token; - - - #region GET请求 - - /// - /// GET请求 - /// - /// - /// - public static string HttpGetAsync(string url) - { - string result = ""; - var serviceProvider = new ServiceCollection().AddHttpClient().BuildServiceProvider(); - IHttpClientFactory _httpClientFactory = serviceProvider.GetService(); - - var _httpClient = _httpClientFactory.CreateClient("Operational"); - - if (token != null) - { - //_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Authorization", $"{token.token_type} {token.access_token}"); - _httpClient.DefaultRequestHeaders.Add("Authorization", $"{token.token_type} {token.access_token}"); - } - - //_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Authorization", $"{token.token_type} {token.access_token}"); - var response = _httpClient.GetAsync(url).Result; - - if (response.IsSuccessStatusCode) - { - Task t = response.Content.ReadAsStringAsync(); - if (t != null) - { - result = t.Result; - } - } - return result; - } - - /// - /// GET请求(返回对象) - /// - /// - /// - public static T HttpGetAsync(string url) - { - var serviceProvider = new ServiceCollection().AddHttpClient().BuildServiceProvider(); - IHttpClientFactory _httpClientFactory = serviceProvider.GetService(); - - var _httpClient = _httpClientFactory.CreateClient("Operational"); - - if (token != null) - { - //_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Authorization", $"{token.token_type} {token.access_token}"); - _httpClient.DefaultRequestHeaders.Add("Authorization", $"{token.token_type} {token.access_token}"); - } - - //_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Authorization", $"{token.token_type} {token.access_token}"); - var response = _httpClient.GetAsync(url).Result; - - if (response.IsSuccessStatusCode) - { - Task t = response.Content.ReadAsStringAsync(); - if (t != null) - { - return JsonConvert.DeserializeObject(t.Result); - } - } - return default(T); - } - #endregion - - - - #region POST请求--异步方法 - - /// - /// POST请求 - /// - /// API地址 - /// 传递的参数 - /// application/xml、application/json、application/text、application/x-www-form-urlencoded - /// - /// Json文本 - public static string HttpPostAsync(string url, object obj, ContentType contentType , string charset = "UTF-8") - { - string result = ""; - - var serviceProvider = new ServiceCollection().AddHttpClient().BuildServiceProvider(); - IHttpClientFactory _httpClientFactory = serviceProvider.GetService(); - var _httpClient = _httpClientFactory.CreateClient("Operational"); - - _httpClient.DefaultRequestHeaders.Accept.Clear(); - _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(contentType.GetDisplay())); - - if (token != null) - { - //_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Authorization", $"{token.token_type} {token.access_token}"); - _httpClient.DefaultRequestHeaders.Add("Authorization", $"{token.token_type} {token.access_token}"); - } - - - string content = JsonConvert.SerializeObject(obj); - - var httpContent = new StringContent(content, Encoding.UTF8, contentType.GetDisplay()); - - var response = _httpClient.PostAsync(url, httpContent).Result; - if (response.IsSuccessStatusCode) - { - Task t = response.Content.ReadAsStringAsync(); - if (t != null) - { - result = t.Result; - } - } - return result; - } - - - /// - /// POST请求(返回对象) - /// - /// API地址 - /// 传递的参数 - /// application/xml、application/json、application/text、application/x-www-form-urlencoded - /// - /// 对象 - public static T HttpPostAsync(string url, object obj, ContentType contentType , string charset = "UTF-8") - { - var serviceProvider = new ServiceCollection().AddHttpClient().BuildServiceProvider(); - IHttpClientFactory _httpClientFactory = serviceProvider.GetService(); - var _httpClient = _httpClientFactory.CreateClient("Operational"); - - _httpClient.DefaultRequestHeaders.Accept.Clear(); - _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(contentType.GetDisplay())); - - if (token != null) - { - _httpClient.DefaultRequestHeaders.Add("Authorization", $"{token.token_type} {token.access_token}"); - } - - - string content = JsonConvert.SerializeObject(obj); - - var httpContent = new StringContent(content, Encoding.UTF8, contentType.GetDisplay()); - - var response = _httpClient.PostAsync(url, httpContent).Result; - if (response.IsSuccessStatusCode) - { - Task t = response.Content.ReadAsStringAsync(); - if (t != null) - { - return JsonConvert.DeserializeObject(t.Result); - } - else - { - return default(T); - } - } - else - { - return default(T); - } - - } - - - #endregion - - - /// - /// 刷新TOKEN - /// - /// 地址 - public static void Refresh_token(string url) - { - if (token != null) - { - //string url = AppConfig.Instance.BaseUrl + AppConfig.Instance.ApiConfigs["刷新TOKEN"] + token.refresh_token; - - var serviceProvider = new ServiceCollection().AddHttpClient().BuildServiceProvider(); - IHttpClientFactory _httpClientFactory = serviceProvider.GetService(); - var _httpClient = _httpClientFactory.CreateClient("Operational"); - - _httpClient.DefaultRequestHeaders.Accept.Clear(); - _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); - - _httpClient.DefaultRequestHeaders.Add("Authorization", $"{token.token_type} {token.access_token}"); - - var response = _httpClient.PostAsync(url, null).Result; - - if (response.IsSuccessStatusCode) - { - Task t = response.Content.ReadAsStringAsync(); - if (t != null) - { - token = JsonConvert.DeserializeObject(t.Result); - } - else - { - token = null; - } - } - else - { - token = null; - } - } - } - } - - /// - /// - /// - public class Token - { - public string access_token { get; set; } - - public int expires_in { get; set; } - - public string token_type { get; set; } - - public string refresh_token { get; set; } - } - - /// - /// 传输类型枚举 - /// - public enum ContentType - { - [Display(Name = "application/xml")] - application_xml=0, - [Display(Name = "application/json")] - application_json=1, - [Display(Name = "application/text")] - application_text=2, - [Display(Name = "application/x-www-form-urlencoded")] - application_x_www_form_urlencoded=3 - } -} diff --git a/Vampirewal.Core/Tools/JsonHelper.cs b/Vampirewal.Core/Tools/JsonHelper.cs index 34694c8e33a0f1e0817998663bffff1bea9a3a7c..6d9f9155f72b5e226ddf60e10e5a16abe5808047 100644 --- a/Vampirewal.Core/Tools/JsonHelper.cs +++ b/Vampirewal.Core/Tools/JsonHelper.cs @@ -11,99 +11,157 @@ //----------------------------------------------------------------*/ #endregion -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -namespace Vampirewal.Core + + +namespace Vampirewal.Core; + +public class JsonHelper { - public class JsonHelper + /// + /// json字符串格式化输出 + /// + /// + /// + public static string FormatJsonString(string sourceJsonStr) { - /// - /// json字符串格式化输出 - /// - /// - /// - public static string FormatJsonString(string sourceJsonStr) + //格式化json字符串 + JsonSerializer serializer = new JsonSerializer(); + TextReader tr = new StringReader(sourceJsonStr); + JsonTextReader jtr = new JsonTextReader(tr); + object obj = serializer.Deserialize(jtr); + if (obj != null) { - //格式化json字符串 - JsonSerializer serializer = new JsonSerializer(); - TextReader tr = new StringReader(sourceJsonStr); - JsonTextReader jtr = new JsonTextReader(tr); - object obj = serializer.Deserialize(jtr); - if (obj != null) - { - StringWriter textWriter = new StringWriter(); - JsonTextWriter jsonWriter = new JsonTextWriter(textWriter) - { - Formatting = Formatting.Indented, - Indentation = 4, - IndentChar = ' ' - }; - serializer.Serialize(jsonWriter, obj); - return textWriter.ToString(); - } - else + StringWriter textWriter = new StringWriter(); + JsonTextWriter jsonWriter = new JsonTextWriter(textWriter) { - return sourceJsonStr; - } + Formatting = Formatting.Indented, + Indentation = 4, + IndentChar = ' ' + }; + serializer.Serialize(jsonWriter, obj); + return textWriter.ToString(); } - - /// - /// 将object对象转换为实体对象 - /// - /// 实体对象类名 - /// object对象 - /// - public static T ConvertObject(object asObject) where T : new() + else { - //var serializer = new JavaScriptSerializer(); - string strJson = JsonConvert.SerializeObject(asObject); - //将object对象转换为json字符 - //var json = serializer.Serialize(asObject); - //将json字符转换为实体对象 - var t = JsonConvert.DeserializeObject(strJson); - return t; + return sourceJsonStr; } + } + + /// + /// 将object对象转换为实体对象 + /// + /// 实体对象类名 + /// object对象 + /// + public static T ConvertObject(object asObject) where T : new() + { + //var serializer = new JavaScriptSerializer(); + string strJson = JsonConvert.SerializeObject(asObject); + //将object对象转换为json字符 + //var json = serializer.Serialize(asObject); + //将json字符转换为实体对象 + var t = JsonConvert.DeserializeObject(strJson); + return t; + } - /// - /// 将实体类转化为json格式 - /// - /// 实体类 - /// 实体 - /// 是否格式化 - /// - public static string SerializeObjectToJson(T entity,bool IsFormat = false) + /// + /// 将实体类转化为json格式 + /// + /// 实体类 + /// 实体 + /// 是否格式化 + /// + public static string SerializeObjectToJson(T entity,bool IsFormat = false) { - string json = JsonConvert.SerializeObject(entity); + string json = JsonConvert.SerializeObject(entity); if (IsFormat) { - return FormatJsonString(json); - } + return FormatJsonString(json); + } else { - return json; + return json; } - + } - /// - /// 读取指定目录下的JSON文件 - /// - /// JSON文件中的value值 - public static string Readjson(string Url) - { + /// + /// 读取指定目录下的JSON文件 + /// + /// JSON文件中的value值 + public static string Readjson(string JsonPath) + { - using (System.IO.StreamReader sr = System.IO.File.OpenText(Url)) - { - string json = sr.ReadToEnd(); + using (System.IO.StreamReader sr = System.IO.File.OpenText(JsonPath)) + { + string json = sr.ReadToEnd(); - return json; - } + return json; } } + + /// + /// 获取相应子节点的值 + /// + public static string JSON_SeleteNode(JToken json, string ReName) + { + try + { + string result = ""; + //这里6.0版块可以用正则匹配 + var node = json.SelectToken("$.." + ReName); + if (node != null) + { + //判断节点类型 + if (node.Type == JTokenType.String || node.Type == JTokenType.Integer || node.Type == JTokenType.Float) + { + //返回string值 + result = node.Value().ToString(); + } + } + return result; + } + catch (Exception ex) + { + return ""; + } + } + + /// + /// 遍历所以节点,替换其中某个节点的值 + /// + /// json数据 + /// 节点名 + /// 新值 + public static void JSON_SetChildNodes(ref JToken jobj, string nodeName, string value) + { + try + { + JToken result = jobj as JToken;//转换为JToken + JToken result2 = result.DeepClone();//复制一个返回值,由于遍历的时候JToken的修改回终止遍历,因此需要复制一个新的返回json + //遍历 + var reader = result.CreateReader(); + while (reader.Read()) + { + if (reader.Value != null) + { + if (reader.TokenType == JsonToken.String || reader.TokenType == JsonToken.Integer || reader.TokenType == JsonToken.Float) + { + Regex reg = new Regex(@"" + nodeName + "$"); + //SelectToken(Path)方法可查找某路径下的节点,在Newtonsoft.Json 4.5 版本中不可使用正则匹配,在6.0版本中可用使用,会方便很多,6.0版本下替换值会更方便,这个需要特别注意的 + if (reg.IsMatch(reader.Path)) + { + result2.SelectToken(reader.Path).Replace(value); + } + } + } + } + jobj = result2; + } + catch (Exception ex) + { + } + } } \ No newline at end of file diff --git a/Vampirewal.Core/Tools/ListExtension.cs b/Vampirewal.Core/Tools/ListExtension.cs index 11692dbc43bdfc79fb2bf342e5299f427f457cc0..36f4171213b4e4dabb3cbd95f40e207ba0350e73 100644 --- a/Vampirewal.Core/Tools/ListExtension.cs +++ b/Vampirewal.Core/Tools/ListExtension.cs @@ -11,50 +11,263 @@ //----------------------------------------------------------------*/ #endregion -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Vampirewal.Core.Tools + + + +namespace Vampirewal.Core.Tools; + +public static class ListExtension { - public static class ListExtension + /// + /// List转ObservableCollection + /// + /// + /// + /// + /// + public static ObservableCollection ListToObservableCollection(this List Source,ObservableCollection OutSource) { - /// - /// List转ObservableCollection - /// - /// - /// - /// - /// - public static ObservableCollection ListToObservableCollection(this List Source,ObservableCollection OutSource) - { - - - foreach (var item in Source) + + + foreach (var item in Source) + { + OutSource.Add(item); + } + return OutSource; + } + + /// + /// ObservableCollection转List + /// + /// + /// + /// + /// + public static List ObservableCollectionToList(this ObservableCollection Source,List OutSource) + { + foreach (var item in Source) + { + OutSource.Add(item); + } + + return OutSource; + } + + ///// + ///// DataTable转List + ///// 仅适用于excel导入的数据,且对应实体类的属性上有特性 + ///// + ///// + ///// + ///// + ///// + //public static List ToList(this DataTable dt) + //{ + // var list = new List(); + // var plist = new List(typeof(T).GetProperties()); + // foreach (DataRow item in dt.Rows) + // { + // if (item.ItemArray[0] is DBNull) + // continue; + + // T s = Activator.CreateInstance(); + // for (int i = 0; i < dt.Columns.Count; i++) + // { + // //PropertyInfo info = plist.Find(p => p.Name == dt.Columns[i].ColumnName); + + // PropertyInfo info = null; + + // foreach (var Prop in plist) + // { + // var customAttributes = Prop.GetCustomAttributes(typeof(ExportExcelAttribute), false).ToList(); + + // foreach (var attribute in customAttributes) + // { + // if (attribute is ExportExcelAttribute export) + // { + // if (export.PropertyChineseName == dt.Columns[i].ColumnName) + // { + // info = Prop; + // continue; + // } + // } + // } + + // if (info != null) + // { + // continue; + // } + // } + + // if (info != null) + // { + // try + // { + // if (!Convert.IsDBNull(item[i])) + // { + // object v = null; + // if (info.PropertyType.ToString().Contains("System.Nullable")) + // { + // v = Convert.ChangeType(item[i], Nullable.GetUnderlyingType(info.PropertyType)); + // } + // else if (info.PropertyType.IsEnum) + // { + // //int enumInt = Convert.ToInt32(item[i]); + + // v = Enum.Parse(info.PropertyType, item[i].ToString()); + // } + // else + // { + // v = Convert.ChangeType(item[i], info.PropertyType); + // } + + // info.SetValue(s, v, null); + // } + // } + // catch (Exception ex) + // { + // throw new Exception("字段[" + info.Name + "]转换出错," + ex.Message); + // } + // } + // } + // list.Add(s); + // } + // return list; + //} + + /// + /// List转DataTable + /// 仅适用于导出excel的数据,且对应实体类的属性上有特性 + /// + //public static DataTable ToDataTable(this List items) + //{ + // var tb = new DataTable(typeof(T).Name); + + // PropertyInfo[] props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance); + + // var clone = props.Clone(); + // var cur = new List(); + + // foreach (var item in clone as PropertyInfo[]) + // { + // var export= item.GetCustomAttribute(); + + // if (export!=null&&export.IsCanExport) + // { + // tb.Columns.Add(export.PropertyChineseName, item.PropertyType); + // cur.Add(item); + // } + // } + + // foreach (T item in items) + // { + // var values = new object[cur.Count]; + + // for (int i = 0; i < cur.Count; i++) + // { + // values[i] = cur[i].GetValue(item, null); + // } + + // tb.Rows.Add(values); + // } + + // return tb; + //} + + /// + /// Determine of specified type is nullable + /// + public static bool IsNullable(Type t) + { + return !t.IsValueType || (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)); + } + + /// + /// Return underlying type if type is Nullable otherwise return the type + /// + public static Type GetCoreType(Type t) + { + if (t != null && IsNullable(t)) + { + if (!t.IsValueType) + { + return t; + } + else { - OutSource.Add(item); + return Nullable.GetUnderlyingType(t); } - return OutSource; } + else + { + return t; + } + } + + //************************************************* + /// + /// List转Datatable + /// + /// + /// + /// + public static IList ConvertTo(DataTable table) + { + if (table == null) + { + return null; + } + + List rows = new List(); + + foreach (DataRow row in table.Rows) + { + rows.Add(row); + } + + return ConvertTo(rows); + } - /// - /// ObservableCollection转List - /// - /// - /// - /// - /// - public static List ObservableCollectionToList(this ObservableCollection Source,List OutSource) + public static IList ConvertTo(IList rows) + { + IList list = null; + + if (rows != null) { - foreach (var item in Source) + list = new List(); + + foreach (DataRow row in rows) { - OutSource.Add(item); + T item = CreateItem(row); + list.Add(item); } + } - return OutSource; + return list; + } + + public static T CreateItem(DataRow row) + { + T obj = default(T); + if (row != null) + { + obj = Activator.CreateInstance(); + + foreach (DataColumn column in row.Table.Columns) + { + PropertyInfo prop = obj.GetType().GetProperty(column.ColumnName); + try + { + object value = row[column.ColumnName]; + prop.SetValue(obj, value, null); + } + catch + { //You can log something here + //throw; + } + } } + + return obj; } } diff --git a/Vampirewal.Core/Tools/PinYinHelper.cs b/Vampirewal.Core/Tools/PinYinHelper.cs deleted file mode 100644 index 27defc2439e03e1441fdd0a0036d885a3348d504..0000000000000000000000000000000000000000 --- a/Vampirewal.Core/Tools/PinYinHelper.cs +++ /dev/null @@ -1,875 +0,0 @@ -#region << 文 件 说 明 >> -/*---------------------------------------------------------------- -// 文件名称:PinYinHelper -// 创 建 者:杨程 -// 创建时间:2021/8/16 9:22:35 -// 文件版本:V1.0.0 -// =============================================================== -// 功能描述: -// -// -//----------------------------------------------------------------*/ -#endregion - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; -//using Microsoft.International.Converters.PinYinConverter; - -namespace Vampirewal.Core.Tools -{ - /// - /// 拼音帮助类 需先引用:CHSPinYinConv - /// - public class PinYinHelper - { - //public static PingYinModel GetTotalPingYin(string str) - //{ - // var chs = str.ToCharArray(); - // //记录每个汉字的全拼 - // Dictionary> totalPingYins = new Dictionary>(); - // for (int i = 0; i < chs.Length; i++) - // { - // var pinyins = new List(); - // var ch = chs[i]; - // //是否是有效的汉字 - // if (ChineseChar.IsValidChar(ch)) - // { - // ChineseChar cc = new ChineseChar(ch); - // pinyins = cc.Pinyins.Where(p => !string.IsNullOrWhiteSpace(p)).ToList(); - // } - // else - // { - // pinyins.Add(ch.ToString()); - // } - - // //去除声调,转小写 - // pinyins = pinyins.ConvertAll(p => Regex.Replace(p, @"\d", "").ToLower()); - // //去重 - // pinyins = pinyins.Where(p => !string.IsNullOrWhiteSpace(p)).Distinct().ToList(); - // if (pinyins.Any()) - // { - // totalPingYins[i] = pinyins; - // } - // } - // PingYinModel result = new PingYinModel(); - // foreach (var pinyins in totalPingYins) - // { - // var items = pinyins.Value; - // result.ListPinYin.Add(FirstCharToUpper(items[0].ToString())); - // if (result.TotalPingYin.Count <= 0) - // { - // result.TotalPingYin = items; - // result.FirstPingYin = items.ConvertAll(p => p.Substring(0, 1)).Distinct().ToList(); - // } - // else - // { - // //全拼循环匹配 - // var newTotalPingYins = new List(); - // foreach (var totalPingYin in result.TotalPingYin) - // { - // newTotalPingYins.AddRange(items.Select(item => totalPingYin + item)); - // } - // newTotalPingYins = newTotalPingYins.Distinct().ToList(); - // result.TotalPingYin = newTotalPingYins; - - // //首字母循环匹配 - // var newFirstPingYins = new List(); - // foreach (var firstPingYin in result.FirstPingYin) - // { - // newFirstPingYins.AddRange(items.Select(item => firstPingYin + item.Substring(0, 1))); - // } - // newFirstPingYins = newFirstPingYins.Distinct().ToList(); - // result.FirstPingYin = newFirstPingYins; - // } - // } - // return result; - //} - - //public static string FirstCharToUpper(string input) - //{ - // if (String.IsNullOrEmpty(input)) - // return null; - // return input.First().ToString().ToUpper() + input.ToLower().Substring(1); - //} - } - - //public class PingYinModel - //{ - // public PingYinModel() - // { - // TotalPingYin = new List(); - // FirstPingYin = new List(); - // ListPinYin = new List(); - // } - - // //全拼 - // public List TotalPingYin { get; set; } - - // //首拼 - // public List FirstPingYin { get; set; } - - // /// - // /// 列表拼音 - // /// - // public List ListPinYin { get; set; } - //} - - ///// - ///// 汉字拼音转换类 - ///// - //public class PinYinConverter - //{ - // #region 数组信息 - - // private static int[] pyValue = new int[] - - // { - // -20319, -20317, -20304, -20295, -20292, -20283, -20265, -20257, -20242, - - // -20230, -20051, -20036, -20032, -20026, -20002, -19990, -19986, -19982, - - // -19976, -19805, -19784, -19775, -19774, -19763, -19756, -19751, -19746, - - // -19741, -19739, -19728, -19725, -19715, -19540, -19531, -19525, -19515, - - // -19500, -19484, -19479, -19467, -19289, -19288, -19281, -19275, -19270, - - // -19263, -19261, -19249, -19243, -19242, -19238, -19235, -19227, -19224, - - // -19218, -19212, -19038, -19023, -19018, -19006, -19003, -18996, -18977, - - // -18961, -18952, -18783, -18774, -18773, -18763, -18756, -18741, -18735, - - // -18731, -18722, -18710, -18697, -18696, -18526, -18518, -18501, -18490, - - // -18478, -18463, -18448, -18447, -18446, -18239, -18237, -18231, -18220, - - // -18211, -18201, -18184, -18183, -18181, -18012, -17997, -17988, -17970, - - // -17964, -17961, -17950, -17947, -17931, -17928, -17922, -17759, -17752, - - // -17733, -17730, -17721, -17703, -17701, -17697, -17692, -17683, -17676, - - // -17496, -17487, -17482, -17468, -17454, -17433, -17427, -17417, -17202, - - // -17185, -16983, -16970, -16942, -16915, -16733, -16708, -16706, -16689, - - // -16664, -16657, -16647, -16474, -16470, -16465, -16459, -16452, -16448, - - // -16433, -16429, -16427, -16423, -16419, -16412, -16407, -16403, -16401, - - // -16393, -16220, -16216, -16212, -16205, -16202, -16187, -16180, -16171, - - // -16169, -16158, -16155, -15959, -15958, -15944, -15933, -15920, -15915, - - // -15903, -15889, -15878, -15707, -15701, -15681, -15667, -15661, -15659, - - // -15652, -15640, -15631, -15625, -15454, -15448, -15436, -15435, -15419, - - // -15416, -15408, -15394, -15385, -15377, -15375, -15369, -15363, -15362, - - // -15183, -15180, -15165, -15158, -15153, -15150, -15149, -15144, -15143, - - // -15141, -15140, -15139, -15128, -15121, -15119, -15117, -15110, -15109, - - // -14941, -14937, -14933, -14930, -14929, -14928, -14926, -14922, -14921, - - // -14914, -14908, -14902, -14894, -14889, -14882, -14873, -14871, -14857, - - // -14678, -14674, -14670, -14668, -14663, -14654, -14645, -14630, -14594, - - // -14429, -14407, -14399, -14384, -14379, -14368, -14355, -14353, -14345, - - // -14170, -14159, -14151, -14149, -14145, -14140, -14137, -14135, -14125, - - // -14123, -14122, -14112, -14109, -14099, -14097, -14094, -14092, -14090, - - // -14087, -14083, -13917, -13914, -13910, -13907, -13906, -13905, -13896, - - // -13894, -13878, -13870, -13859, -13847, -13831, -13658, -13611, -13601, - - // -13406, -13404, -13400, -13398, -13395, -13391, -13387, -13383, -13367, - - // -13359, -13356, -13343, -13340, -13329, -13326, -13318, -13147, -13138, - - // -13120, -13107, -13096, -13095, -13091, -13076, -13068, -13063, -13060, - - // -12888, -12875, -12871, -12860, -12858, -12852, -12849, -12838, -12831, - - // -12829, -12812, -12802, -12607, -12597, -12594, -12585, -12556, -12359, - - // -12346, -12320, -12300, -12120, -12099, -12089, -12074, -12067, -12058, - - // -12039, -11867, -11861, -11847, -11831, -11798, -11781, -11604, -11589, - - // -11536, -11358, -11340, -11339, -11324, -11303, -11097, -11077, -11067, - - // -11055, -11052, -11045, -11041, -11038, -11024, -11020, -11019, -11018, - - // -11014, -10838, -10832, -10815, -10800, -10790, -10780, -10764, -10587, - - // -10544, -10533, -10519, -10331, -10329, -10328, -10322, -10315, -10309, - - // -10307, -10296, -10281, -10274, -10270, -10262, -10260, -10256, -10254 - // }; - - // private static string[] pyName = new string[] - - // { - // "A", "Ai", "An", "Ang", "Ao", "Ba", "Bai", "Ban", "Bang", "Bao", "Bei", - - // "Ben", "Beng", "Bi", "Bian", "Biao", "Bie", "Bin", "Bing", "Bo", "Bu", - - // "Ba", "Cai", "Can", "Cang", "Cao", "Ce", "Ceng", "Cha", "Chai", "Chan", - - // "Chang", "Chao", "Che", "Chen", "Cheng", "Chi", "Chong", "Chou", "Chu", - - // "Chuai", "Chuan", "Chuang", "Chui", "Chun", "Chuo", "Ci", "Cong", "Cou", - - // "Cu", "Cuan", "Cui", "Cun", "Cuo", "Da", "Dai", "Dan", "Dang", "Dao", "De", - - // "Deng", "Di", "Dian", "Diao", "Die", "Ding", "Diu", "Dong", "Dou", "Du", - - // "Duan", "Dui", "Dun", "Duo", "E", "En", "Er", "Fa", "Fan", "Fang", "Fei", - - // "Fen", "Feng", "Fo", "Fou", "Fu", "Ga", "Gai", "Gan", "Gang", "Gao", "Ge", - - // "Gei", "Gen", "Geng", "Gong", "Gou", "Gu", "Gua", "Guai", "Guan", "Guang", - - // "Gui", "Gun", "Guo", "Ha", "Hai", "Han", "Hang", "Hao", "He", "Hei", "Hen", - - // "Heng", "Hong", "Hou", "Hu", "Hua", "Huai", "Huan", "Huang", "Hui", "Hun", - - // "Huo", "Ji", "Jia", "Jian", "Jiang", "Jiao", "Jie", "Jin", "Jing", "Jiong", - - // "Jiu", "Ju", "Juan", "Jue", "Jun", "Ka", "Kai", "Kan", "Kang", "Kao", "Ke", - - // "Ken", "Keng", "Kong", "Kou", "Ku", "Kua", "Kuai", "Kuan", "Kuang", "Kui", - - // "Kun", "Kuo", "La", "Lai", "Lan", "Lang", "Lao", "Le", "Lei", "Leng", "Li", - - // "Lia", "Lian", "Liang", "Liao", "Lie", "Lin", "Ling", "Liu", "Long", "Lou", - - // "Lu", "Lv", "Luan", "Lue", "Lun", "Luo", "Ma", "Mai", "Man", "Mang", "Mao", - - // "Me", "Mei", "Men", "Meng", "Mi", "Mian", "Miao", "Mie", "Min", "Ming", "Miu", - - // "Mo", "Mou", "Mu", "Na", "Nai", "Nan", "Nang", "Nao", "Ne", "Nei", "Nen", - - // "Neng", "Ni", "Nian", "Niang", "Niao", "Nie", "Nin", "Ning", "Niu", "Nong", - - // "Nu", "Nv", "Nuan", "Nue", "Nuo", "O", "Ou", "Pa", "Pai", "Pan", "Pang", - - // "Pao", "Pei", "Pen", "Peng", "Pi", "Pian", "Piao", "Pie", "Pin", "Ping", - - // "Po", "Pu", "Qi", "Qia", "Qian", "Qiang", "Qiao", "Qie", "Qin", "Qing", - - // "Qiong", "Qiu", "Qu", "Quan", "Que", "Qun", "Ran", "Rang", "Rao", "Re", - - // "Ren", "Reng", "Ri", "Rong", "Rou", "Ru", "Ruan", "Rui", "Run", "Ruo", - - // "Sa", "Sai", "San", "Sang", "Sao", "Se", "Sen", "Seng", "Sha", "Shai", - - // "Shan", "Shang", "Shao", "She", "Shen", "Sheng", "Shi", "Shou", "Shu", - - // "Shua", "Shuai", "Shuan", "Shuang", "Shui", "Shun", "Shuo", "Si", "Song", - - // "Sou", "Su", "Suan", "Sui", "Sun", "Suo", "Ta", "Tai", "Tan", "Tang", - - // "Tao", "Te", "Teng", "Ti", "Tian", "Tiao", "Tie", "Ting", "Tong", "Tou", - - // "Tu", "Tuan", "Tui", "Tun", "Tuo", "Wa", "Wai", "Wan", "Wang", "Wei", - - // "Wen", "Weng", "Wo", "Wu", "Xi", "Xia", "Xian", "Xiang", "Xiao", "Xie", - - // "Xin", "Xing", "Xiong", "Xiu", "Xu", "Xuan", "Xue", "Xun", "Ya", "Yan", - - // "Yang", "Yao", "Ye", "Yi", "Yin", "Ying", "Yo", "Yong", "You", "Yu", - - // "Yuan", "Yue", "Yun", "Za", "Zai", "Zan", "Zang", "Zao", "Ze", "Zei", - - // "Zen", "Zeng", "Zha", "Zhai", "Zhan", "Zhang", "Zhao", "Zhe", "Zhen", - - // "Zheng", "Zhi", "Zhong", "Zhou", "Zhu", "Zhua", "Zhuai", "Zhuan", - - // "Zhuang", "Zhui", "Zhun", "Zhuo", "Zi", "Zong", "Zou", "Zu", "Zuan", - - // "Zui", "Zun", "Zuo" - // }; - - // #region 二级汉字 - - // /// - // /// 二级汉字数组 - // /// - // private static string[] otherChinese = new string[] - // { - // "亍","丌","兀","丐","廿","卅","丕","亘","丞","鬲","孬","噩","丨","禺","丿" - // ,"匕","乇","夭","爻","卮","氐","囟","胤","馗","毓","睾","鼗","丶","亟","鼐","乜" - // ,"乩","亓","芈","孛","啬","嘏","仄","厍","厝","厣","厥","厮","靥","赝","匚","叵" - // ,"匦","匮","匾","赜","卦","卣","刂","刈","刎","刭","刳","刿","剀","剌","剞","剡" - // ,"剜","蒯","剽","劂","劁","劐","劓","冂","罔","亻","仃","仉","仂","仨","仡","仫" - // ,"仞","伛","仳","伢","佤","仵","伥","伧","伉","伫","佞","佧","攸","佚","佝" - // ,"佟","佗","伲","伽","佶","佴","侑","侉","侃","侏","佾","佻","侪","佼","侬" - // ,"侔","俦","俨","俪","俅","俚","俣","俜","俑","俟","俸","倩","偌","俳","倬","倏" - // ,"倮","倭","俾","倜","倌","倥","倨","偾","偃","偕","偈","偎","偬","偻","傥","傧" - // ,"傩","傺","僖","儆","僭","僬","僦","僮","儇","儋","仝","氽","佘","佥","俎","龠" - // ,"汆","籴","兮","巽","黉","馘","冁","夔","勹","匍","訇","匐","凫","夙","兕","亠" - // ,"兖","亳","衮","袤","亵","脔","裒","禀","嬴","蠃","羸","冫","冱","冽","冼" - // ,"凇","冖","冢","冥","讠","讦","讧","讪","讴","讵","讷","诂","诃","诋","诏" - // ,"诎","诒","诓","诔","诖","诘","诙","诜","诟","诠","诤","诨","诩","诮","诰","诳" - // ,"诶","诹","诼","诿","谀","谂","谄","谇","谌","谏","谑","谒","谔","谕","谖","谙" - // ,"谛","谘","谝","谟","谠","谡","谥","谧","谪","谫","谮","谯","谲","谳","谵","谶" - // ,"卩","卺","阝","阢","阡","阱","阪","阽","阼","陂","陉","陔","陟","陧","陬","陲" - // ,"陴","隈","隍","隗","隰","邗","邛","邝","邙","邬","邡","邴","邳","邶","邺" - // ,"邸","邰","郏","郅","邾","郐","郄","郇","郓","郦","郢","郜","郗","郛","郫" - // ,"郯","郾","鄄","鄢","鄞","鄣","鄱","鄯","鄹","酃","酆","刍","奂","劢","劬","劭" - // ,"劾","哿","勐","勖","勰","叟","燮","矍","廴","凵","凼","鬯","厶","弁","畚","巯" - // ,"坌","垩","垡","塾","墼","壅","壑","圩","圬","圪","圳","圹","圮","圯","坜","圻" - // ,"坂","坩","垅","坫","垆","坼","坻","坨","坭","坶","坳","垭","垤","垌","垲","埏" - // ,"垧","垴","垓","垠","埕","埘","埚","埙","埒","垸","埴","埯","埸","埤","埝" - // ,"堋","堍","埽","埭","堀","堞","堙","塄","堠","塥","塬","墁","墉","墚","墀" - // ,"馨","鼙","懿","艹","艽","艿","芏","芊","芨","芄","芎","芑","芗","芙","芫","芸" - // ,"芾","芰","苈","苊","苣","芘","芷","芮","苋","苌","苁","芩","芴","芡","芪","芟" - // ,"苄","苎","芤","苡","茉","苷","苤","茏","茇","苜","苴","苒","苘","茌","苻","苓" - // ,"茑","茚","茆","茔","茕","苠","苕","茜","荑","荛","荜","茈","莒","茼","茴","茱" - // ,"莛","荞","茯","荏","荇","荃","荟","荀","茗","荠","茭","茺","茳","荦","荥" - // ,"荨","茛","荩","荬","荪","荭","荮","莰","荸","莳","莴","莠","莪","莓","莜" - // ,"莅","荼","莶","莩","荽","莸","荻","莘","莞","莨","莺","莼","菁","萁","菥","菘" - // ,"堇","萘","萋","菝","菽","菖","萜","萸","萑","萆","菔","菟","萏","萃","菸","菹" - // ,"菪","菅","菀","萦","菰","菡","葜","葑","葚","葙","葳","蒇","蒈","葺","蒉","葸" - // ,"萼","葆","葩","葶","蒌","蒎","萱","葭","蓁","蓍","蓐","蓦","蒽","蓓","蓊","蒿" - // ,"蒺","蓠","蒡","蒹","蒴","蒗","蓥","蓣","蔌","甍","蔸","蓰","蔹","蔟","蔺" - // ,"蕖","蔻","蓿","蓼","蕙","蕈","蕨","蕤","蕞","蕺","瞢","蕃","蕲","蕻","薤" - // ,"薨","薇","薏","蕹","薮","薜","薅","薹","薷","薰","藓","藁","藜","藿","蘧","蘅" - // ,"蘩","蘖","蘼","廾","弈","夼","奁","耷","奕","奚","奘","匏","尢","尥","尬","尴" - // ,"扌","扪","抟","抻","拊","拚","拗","拮","挢","拶","挹","捋","捃","掭","揶","捱" - // ,"捺","掎","掴","捭","掬","掊","捩","掮","掼","揲","揸","揠","揿","揄","揞","揎" - // ,"摒","揆","掾","摅","摁","搋","搛","搠","搌","搦","搡","摞","撄","摭","撖" - // ,"摺","撷","撸","撙","撺","擀","擐","擗","擤","擢","攉","攥","攮","弋","忒" - // ,"甙","弑","卟","叱","叽","叩","叨","叻","吒","吖","吆","呋","呒","呓","呔","呖" - // ,"呃","吡","呗","呙","吣","吲","咂","咔","呷","呱","呤","咚","咛","咄","呶","呦" - // ,"咝","哐","咭","哂","咴","哒","咧","咦","哓","哔","呲","咣","哕","咻","咿","哌" - // ,"哙","哚","哜","咩","咪","咤","哝","哏","哞","唛","哧","唠","哽","唔","哳","唢" - // ,"唣","唏","唑","唧","唪","啧","喏","喵","啉","啭","啁","啕","唿","啐","唼" - // ,"唷","啖","啵","啶","啷","唳","唰","啜","喋","嗒","喃","喱","喹","喈","喁" - // ,"喟","啾","嗖","喑","啻","嗟","喽","喾","喔","喙","嗪","嗷","嗉","嘟","嗑","嗫" - // ,"嗬","嗔","嗦","嗝","嗄","嗯","嗥","嗲","嗳","嗌","嗍","嗨","嗵","嗤","辔","嘞" - // ,"嘈","嘌","嘁","嘤","嘣","嗾","嘀","嘧","嘭","噘","嘹","噗","嘬","噍","噢","噙" - // ,"噜","噌","噔","嚆","噤","噱","噫","噻","噼","嚅","嚓","嚯","囔","囗","囝","囡" - // ,"囵","囫","囹","囿","圄","圊","圉","圜","帏","帙","帔","帑","帱","帻","帼" - // ,"帷","幄","幔","幛","幞","幡","岌","屺","岍","岐","岖","岈","岘","岙","岑" - // ,"岚","岜","岵","岢","岽","岬","岫","岱","岣","峁","岷","峄","峒","峤","峋","峥" - // ,"崂","崃","崧","崦","崮","崤","崞","崆","崛","嵘","崾","崴","崽","嵬","嵛","嵯" - // ,"嵝","嵫","嵋","嵊","嵩","嵴","嶂","嶙","嶝","豳","嶷","巅","彳","彷","徂","徇" - // ,"徉","後","徕","徙","徜","徨","徭","徵","徼","衢","彡","犭","犰","犴","犷","犸" - // ,"狃","狁","狎","狍","狒","狨","狯","狩","狲","狴","狷","猁","狳","猃","狺" - // ,"狻","猗","猓","猡","猊","猞","猝","猕","猢","猹","猥","猬","猸","猱","獐" - // ,"獍","獗","獠","獬","獯","獾","舛","夥","飧","夤","夂","饣","饧","饨","饩","饪" - // ,"饫","饬","饴","饷","饽","馀","馄","馇","馊","馍","馐","馑","馓","馔","馕","庀" - // ,"庑","庋","庖","庥","庠","庹","庵","庾","庳","赓","廒","廑","廛","廨","廪","膺" - // ,"忄","忉","忖","忏","怃","忮","怄","忡","忤","忾","怅","怆","忪","忭","忸","怙" - // ,"怵","怦","怛","怏","怍","怩","怫","怊","怿","怡","恸","恹","恻","恺","恂" - // ,"恪","恽","悖","悚","悭","悝","悃","悒","悌","悛","惬","悻","悱","惝","惘" - // ,"惆","惚","悴","愠","愦","愕","愣","惴","愀","愎","愫","慊","慵","憬","憔","憧" - // ,"憷","懔","懵","忝","隳","闩","闫","闱","闳","闵","闶","闼","闾","阃","阄","阆" - // ,"阈","阊","阋","阌","阍","阏","阒","阕","阖","阗","阙","阚","丬","爿","戕","氵" - // ,"汔","汜","汊","沣","沅","沐","沔","沌","汨","汩","汴","汶","沆","沩","泐","泔" - // ,"沭","泷","泸","泱","泗","沲","泠","泖","泺","泫","泮","沱","泓","泯","泾" - // ,"洹","洧","洌","浃","浈","洇","洄","洙","洎","洫","浍","洮","洵","洚","浏" - // ,"浒","浔","洳","涑","浯","涞","涠","浞","涓","涔","浜","浠","浼","浣","渚","淇" - // ,"淅","淞","渎","涿","淠","渑","淦","淝","淙","渖","涫","渌","涮","渫","湮","湎" - // ,"湫","溲","湟","溆","湓","湔","渲","渥","湄","滟","溱","溘","滠","漭","滢","溥" - // ,"溧","溽","溻","溷","滗","溴","滏","溏","滂","溟","潢","潆","潇","漤","漕","滹" - // ,"漯","漶","潋","潴","漪","漉","漩","澉","澍","澌","潸","潲","潼","潺","濑" - // ,"濉","澧","澹","澶","濂","濡","濮","濞","濠","濯","瀚","瀣","瀛","瀹","瀵" - // ,"灏","灞","宀","宄","宕","宓","宥","宸","甯","骞","搴","寤","寮","褰","寰","蹇" - // ,"謇","辶","迓","迕","迥","迮","迤","迩","迦","迳","迨","逅","逄","逋","逦","逑" - // ,"逍","逖","逡","逵","逶","逭","逯","遄","遑","遒","遐","遨","遘","遢","遛","暹" - // ,"遴","遽","邂","邈","邃","邋","彐","彗","彖","彘","尻","咫","屐","屙","孱","屣" - // ,"屦","羼","弪","弩","弭","艴","弼","鬻","屮","妁","妃","妍","妩","妪","妣" - // ,"妗","姊","妫","妞","妤","姒","妲","妯","姗","妾","娅","娆","姝","娈","姣" - // ,"姘","姹","娌","娉","娲","娴","娑","娣","娓","婀","婧","婊","婕","娼","婢","婵" - // ,"胬","媪","媛","婷","婺","媾","嫫","媲","嫒","嫔","媸","嫠","嫣","嫱","嫖","嫦" - // ,"嫘","嫜","嬉","嬗","嬖","嬲","嬷","孀","尕","尜","孚","孥","孳","孑","孓","孢" - // ,"驵","驷","驸","驺","驿","驽","骀","骁","骅","骈","骊","骐","骒","骓","骖","骘" - // ,"骛","骜","骝","骟","骠","骢","骣","骥","骧","纟","纡","纣","纥","纨","纩" - // ,"纭","纰","纾","绀","绁","绂","绉","绋","绌","绐","绔","绗","绛","绠","绡" - // ,"绨","绫","绮","绯","绱","绲","缍","绶","绺","绻","绾","缁","缂","缃","缇","缈" - // ,"缋","缌","缏","缑","缒","缗","缙","缜","缛","缟","缡","缢","缣","缤","缥","缦" - // ,"缧","缪","缫","缬","缭","缯","缰","缱","缲","缳","缵","幺","畿","巛","甾","邕" - // ,"玎","玑","玮","玢","玟","珏","珂","珑","玷","玳","珀","珉","珈","珥","珙","顼" - // ,"琊","珩","珧","珞","玺","珲","琏","琪","瑛","琦","琥","琨","琰","琮","琬" - // ,"琛","琚","瑁","瑜","瑗","瑕","瑙","瑷","瑭","瑾","璜","璎","璀","璁","璇" - // ,"璋","璞","璨","璩","璐","璧","瓒","璺","韪","韫","韬","杌","杓","杞","杈","杩" - // ,"枥","枇","杪","杳","枘","枧","杵","枨","枞","枭","枋","杷","杼","柰","栉","柘" - // ,"栊","柩","枰","栌","柙","枵","柚","枳","柝","栀","柃","枸","柢","栎","柁","柽" - // ,"栲","栳","桠","桡","桎","桢","桄","桤","梃","栝","桕","桦","桁","桧","桀","栾" - // ,"桊","桉","栩","梵","梏","桴","桷","梓","桫","棂","楮","棼","椟","椠","棹" - // ,"椤","棰","椋","椁","楗","棣","椐","楱","椹","楠","楂","楝","榄","楫","榀" - // ,"榘","楸","椴","槌","榇","榈","槎","榉","楦","楣","楹","榛","榧","榻","榫","榭" - // ,"槔","榱","槁","槊","槟","榕","槠","榍","槿","樯","槭","樗","樘","橥","槲","橄" - // ,"樾","檠","橐","橛","樵","檎","橹","樽","樨","橘","橼","檑","檐","檩","檗","檫" - // ,"猷","獒","殁","殂","殇","殄","殒","殓","殍","殚","殛","殡","殪","轫","轭","轱" - // ,"轲","轳","轵","轶","轸","轷","轹","轺","轼","轾","辁","辂","辄","辇","辋" - // ,"辍","辎","辏","辘","辚","軎","戋","戗","戛","戟","戢","戡","戥","戤","戬" - // ,"臧","瓯","瓴","瓿","甏","甑","甓","攴","旮","旯","旰","昊","昙","杲","昃","昕" - // ,"昀","炅","曷","昝","昴","昱","昶","昵","耆","晟","晔","晁","晏","晖","晡","晗" - // ,"晷","暄","暌","暧","暝","暾","曛","曜","曦","曩","贲","贳","贶","贻","贽","赀" - // ,"赅","赆","赈","赉","赇","赍","赕","赙","觇","觊","觋","觌","觎","觏","觐","觑" - // ,"牮","犟","牝","牦","牯","牾","牿","犄","犋","犍","犏","犒","挈","挲","掰" - // ,"搿","擘","耄","毪","毳","毽","毵","毹","氅","氇","氆","氍","氕","氘","氙" - // ,"氚","氡","氩","氤","氪","氲","攵","敕","敫","牍","牒","牖","爰","虢","刖","肟" - // ,"肜","肓","肼","朊","肽","肱","肫","肭","肴","肷","胧","胨","胩","胪","胛","胂" - // ,"胄","胙","胍","胗","朐","胝","胫","胱","胴","胭","脍","脎","胲","胼","朕","脒" - // ,"豚","脶","脞","脬","脘","脲","腈","腌","腓","腴","腙","腚","腱","腠","腩","腼" - // ,"腽","腭","腧","塍","媵","膈","膂","膑","滕","膣","膪","臌","朦","臊","膻" - // ,"臁","膦","欤","欷","欹","歃","歆","歙","飑","飒","飓","飕","飙","飚","殳" - // ,"彀","毂","觳","斐","齑","斓","於","旆","旄","旃","旌","旎","旒","旖","炀","炜" - // ,"炖","炝","炻","烀","炷","炫","炱","烨","烊","焐","焓","焖","焯","焱","煳","煜" - // ,"煨","煅","煲","煊","煸","煺","熘","熳","熵","熨","熠","燠","燔","燧","燹","爝" - // ,"爨","灬","焘","煦","熹","戾","戽","扃","扈","扉","礻","祀","祆","祉","祛","祜" - // ,"祓","祚","祢","祗","祠","祯","祧","祺","禅","禊","禚","禧","禳","忑","忐" - // ,"怼","恝","恚","恧","恁","恙","恣","悫","愆","愍","慝","憩","憝","懋","懑" - // ,"戆","肀","聿","沓","泶","淼","矶","矸","砀","砉","砗","砘","砑","斫","砭","砜" - // ,"砝","砹","砺","砻","砟","砼","砥","砬","砣","砩","硎","硭","硖","硗","砦","硐" - // ,"硇","硌","硪","碛","碓","碚","碇","碜","碡","碣","碲","碹","碥","磔","磙","磉" - // ,"磬","磲","礅","磴","礓","礤","礞","礴","龛","黹","黻","黼","盱","眄","眍","盹" - // ,"眇","眈","眚","眢","眙","眭","眦","眵","眸","睐","睑","睇","睃","睚","睨" - // ,"睢","睥","睿","瞍","睽","瞀","瞌","瞑","瞟","瞠","瞰","瞵","瞽","町","畀" - // ,"畎","畋","畈","畛","畲","畹","疃","罘","罡","罟","詈","罨","罴","罱","罹","羁" - // ,"罾","盍","盥","蠲","钅","钆","钇","钋","钊","钌","钍","钏","钐","钔","钗","钕" - // ,"钚","钛","钜","钣","钤","钫","钪","钭","钬","钯","钰","钲","钴","钶","钷","钸" - // ,"钹","钺","钼","钽","钿","铄","铈","铉","铊","铋","铌","铍","铎","铐","铑","铒" - // ,"铕","铖","铗","铙","铘","铛","铞","铟","铠","铢","铤","铥","铧","铨","铪" - // ,"铩","铫","铮","铯","铳","铴","铵","铷","铹","铼","铽","铿","锃","锂","锆" - // ,"锇","锉","锊","锍","锎","锏","锒","锓","锔","锕","锖","锘","锛","锝","锞","锟" - // ,"锢","锪","锫","锩","锬","锱","锲","锴","锶","锷","锸","锼","锾","锿","镂","锵" - // ,"镄","镅","镆","镉","镌","镎","镏","镒","镓","镔","镖","镗","镘","镙","镛","镞" - // ,"镟","镝","镡","镢","镤","镥","镦","镧","镨","镩","镪","镫","镬","镯","镱","镲" - // ,"镳","锺","矧","矬","雉","秕","秭","秣","秫","稆","嵇","稃","稂","稞","稔" - // ,"稹","稷","穑","黏","馥","穰","皈","皎","皓","皙","皤","瓞","瓠","甬","鸠" - // ,"鸢","鸨","鸩","鸪","鸫","鸬","鸲","鸱","鸶","鸸","鸷","鸹","鸺","鸾","鹁","鹂" - // ,"鹄","鹆","鹇","鹈","鹉","鹋","鹌","鹎","鹑","鹕","鹗","鹚","鹛","鹜","鹞","鹣" - // ,"鹦","鹧","鹨","鹩","鹪","鹫","鹬","鹱","鹭","鹳","疒","疔","疖","疠","疝","疬" - // ,"疣","疳","疴","疸","痄","疱","疰","痃","痂","痖","痍","痣","痨","痦","痤","痫" - // ,"痧","瘃","痱","痼","痿","瘐","瘀","瘅","瘌","瘗","瘊","瘥","瘘","瘕","瘙" - // ,"瘛","瘼","瘢","瘠","癀","瘭","瘰","瘿","瘵","癃","瘾","瘳","癍","癞","癔" - // ,"癜","癖","癫","癯","翊","竦","穸","穹","窀","窆","窈","窕","窦","窠","窬","窨" - // ,"窭","窳","衤","衩","衲","衽","衿","袂","袢","裆","袷","袼","裉","裢","裎","裣" - // ,"裥","裱","褚","裼","裨","裾","裰","褡","褙","褓","褛","褊","褴","褫","褶","襁" - // ,"襦","襻","疋","胥","皲","皴","矜","耒","耔","耖","耜","耠","耢","耥","耦","耧" - // ,"耩","耨","耱","耋","耵","聃","聆","聍","聒","聩","聱","覃","顸","颀","颃" - // ,"颉","颌","颍","颏","颔","颚","颛","颞","颟","颡","颢","颥","颦","虍","虔" - // ,"虬","虮","虿","虺","虼","虻","蚨","蚍","蚋","蚬","蚝","蚧","蚣","蚪","蚓","蚩" - // ,"蚶","蛄","蚵","蛎","蚰","蚺","蚱","蚯","蛉","蛏","蚴","蛩","蛱","蛲","蛭","蛳" - // ,"蛐","蜓","蛞","蛴","蛟","蛘","蛑","蜃","蜇","蛸","蜈","蜊","蜍","蜉","蜣","蜻" - // ,"蜞","蜥","蜮","蜚","蜾","蝈","蜴","蜱","蜩","蜷","蜿","螂","蜢","蝽","蝾","蝻" - // ,"蝠","蝰","蝌","蝮","螋","蝓","蝣","蝼","蝤","蝙","蝥","螓","螯","螨","蟒" - // ,"蟆","螈","螅","螭","螗","螃","螫","蟥","螬","螵","螳","蟋","蟓","螽","蟑" - // ,"蟀","蟊","蟛","蟪","蟠","蟮","蠖","蠓","蟾","蠊","蠛","蠡","蠹","蠼","缶","罂" - // ,"罄","罅","舐","竺","竽","笈","笃","笄","笕","笊","笫","笏","筇","笸","笪","笙" - // ,"笮","笱","笠","笥","笤","笳","笾","笞","筘","筚","筅","筵","筌","筝","筠","筮" - // ,"筻","筢","筲","筱","箐","箦","箧","箸","箬","箝","箨","箅","箪","箜","箢","箫" - // ,"箴","篑","篁","篌","篝","篚","篥","篦","篪","簌","篾","篼","簏","簖","簋" - // ,"簟","簪","簦","簸","籁","籀","臾","舁","舂","舄","臬","衄","舡","舢","舣" - // ,"舭","舯","舨","舫","舸","舻","舳","舴","舾","艄","艉","艋","艏","艚","艟","艨" - // ,"衾","袅","袈","裘","裟","襞","羝","羟","羧","羯","羰","羲","籼","敉","粑","粝" - // ,"粜","粞","粢","粲","粼","粽","糁","糇","糌","糍","糈","糅","糗","糨","艮","暨" - // ,"羿","翎","翕","翥","翡","翦","翩","翮","翳","糸","絷","綦","綮","繇","纛","麸" - // ,"麴","赳","趄","趔","趑","趱","赧","赭","豇","豉","酊","酐","酎","酏","酤" - // ,"酢","酡","酰","酩","酯","酽","酾","酲","酴","酹","醌","醅","醐","醍","醑" - // ,"醢","醣","醪","醭","醮","醯","醵","醴","醺","豕","鹾","趸","跫","踅","蹙","蹩" - // ,"趵","趿","趼","趺","跄","跖","跗","跚","跞","跎","跏","跛","跆","跬","跷","跸" - // ,"跣","跹","跻","跤","踉","跽","踔","踝","踟","踬","踮","踣","踯","踺","蹀","踹" - // ,"踵","踽","踱","蹉","蹁","蹂","蹑","蹒","蹊","蹰","蹶","蹼","蹯","蹴","躅","躏" - // ,"躔","躐","躜","躞","豸","貂","貊","貅","貘","貔","斛","觖","觞","觚","觜" - // ,"觥","觫","觯","訾","謦","靓","雩","雳","雯","霆","霁","霈","霏","霎","霪" - // ,"霭","霰","霾","龀","龃","龅","龆","龇","龈","龉","龊","龌","黾","鼋","鼍","隹" - // ,"隼","隽","雎","雒","瞿","雠","銎","銮","鋈","錾","鍪","鏊","鎏","鐾","鑫","鱿" - // ,"鲂","鲅","鲆","鲇","鲈","稣","鲋","鲎","鲐","鲑","鲒","鲔","鲕","鲚","鲛","鲞" - // ,"鲟","鲠","鲡","鲢","鲣","鲥","鲦","鲧","鲨","鲩","鲫","鲭","鲮","鲰","鲱","鲲" - // ,"鲳","鲴","鲵","鲶","鲷","鲺","鲻","鲼","鲽","鳄","鳅","鳆","鳇","鳊","鳋" - // ,"鳌","鳍","鳎","鳏","鳐","鳓","鳔","鳕","鳗","鳘","鳙","鳜","鳝","鳟","鳢" - // ,"靼","鞅","鞑","鞒","鞔","鞯","鞫","鞣","鞲","鞴","骱","骰","骷","鹘","骶","骺" - // ,"骼","髁","髀","髅","髂","髋","髌","髑","魅","魃","魇","魉","魈","魍","魑","飨" - // ,"餍","餮","饕","饔","髟","髡","髦","髯","髫","髻","髭","髹","鬈","鬏","鬓","鬟" - // ,"鬣","麽","麾","縻","麂","麇","麈","麋","麒","鏖","麝","麟","黛","黜","黝","黠" - // ,"黟","黢","黩","黧","黥","黪","黯","鼢","鼬","鼯","鼹","鼷","鼽","鼾","齄" - // }; - - // /// - // /// 二级汉字对应拼音数组 - // /// - // private static string[] otherPinYin = new string[] - // { - // "Chu","Ji","Wu","Gai","Nian","Sa","Pi","Gen","Cheng","Ge","Nao","E","Shu","Yu","Pie","Bi", - // "Tuo","Yao","Yao","Zhi","Di","Xin","Yin","Kui","Yu","Gao","Tao","Dian","Ji","Nai","Nie","Ji", - // "Qi","Mi","Bei","Se","Gu","Ze","She","Cuo","Yan","Jue","Si","Ye","Yan","Fang","Po","Gui", - // "Kui","Bian","Ze","Gua","You","Ce","Yi","Wen","Jing","Ku","Gui","Kai","La","Ji","Yan","Wan", - // "Kuai","Piao","Jue","Qiao","Huo","Yi","Tong","Wang","Dan","Ding","Zhang","Le","Sa","Yi","Mu","Ren", - // "Yu","Pi","Ya","Wa","Wu","Chang","Cang","Kang","Zhu","Ning","Ka","You","Yi","Gou","Tong","Tuo", - // "Ni","Ga","Ji","Er","You","Kua","Kan","Zhu","Yi","Tiao","Chai","Jiao","Nong","Mou","Chou","Yan", - // "Li","Qiu","Li","Yu","Ping","Yong","Si","Feng","Qian","Ruo","Pai","Zhuo","Shu","Luo","Wo","Bi", - // "Ti","Guan","Kong","Ju","Fen","Yan","Xie","Ji","Wei","Zong","Lou","Tang","Bin","Nuo","Chi","Xi", - // "Jing","Jian","Jiao","Jiu","Tong","Xuan","Dan","Tong","Tun","She","Qian","Zu","Yue","Cuan","Di","Xi", - // "Xun","Hong","Guo","Chan","Kui","Bao","Pu","Hong","Fu","Fu","Su","Si","Wen","Yan","Bo","Gun", - // "Mao","Xie","Luan","Pou","Bing","Ying","Luo","Lei","Liang","Hu","Lie","Xian","Song","Ping","Zhong","Ming", - // "Yan","Jie","Hong","Shan","Ou","Ju","Ne","Gu","He","Di","Zhao","Qu","Dai","Kuang","Lei","Gua", - // "Jie","Hui","Shen","Gou","Quan","Zheng","Hun","Xu","Qiao","Gao","Kuang","Ei","Zou","Zhuo","Wei","Yu", - // "Shen","Chan","Sui","Chen","Jian","Xue","Ye","E","Yu","Xuan","An","Di","Zi","Pian","Mo","Dang", - // "Su","Shi","Mi","Zhe","Jian","Zen","Qiao","Jue","Yan","Zhan","Chen","Dan","Jin","Zuo","Wu","Qian", - // "Jing","Ban","Yan","Zuo","Bei","Jing","Gai","Zhi","Nie","Zou","Chui","Pi","Wei","Huang","Wei","Xi", - // "Han","Qiong","Kuang","Mang","Wu","Fang","Bing","Pi","Bei","Ye","Di","Tai","Jia","Zhi","Zhu","Kuai", - // "Qie","Xun","Yun","Li","Ying","Gao","Xi","Fu","Pi","Tan","Yan","Juan","Yan","Yin","Zhang","Po", - // "Shan","Zou","Ling","Feng","Chu","Huan","Mai","Qu","Shao","He","Ge","Meng","Xu","Xie","Sou","Xie", - // "Jue","Jian","Qian","Dang","Chang","Si","Bian","Ben","Qiu","Ben","E","Fa","Shu","Ji","Yong","He", - // "Wei","Wu","Ge","Zhen","Kuang","Pi","Yi","Li","Qi","Ban","Gan","Long","Dian","Lu","Che","Di", - // "Tuo","Ni","Mu","Ao","Ya","Die","Dong","Kai","Shan","Shang","Nao","Gai","Yin","Cheng","Shi","Guo", - // "Xun","Lie","Yuan","Zhi","An","Yi","Pi","Nian","Peng","Tu","Sao","Dai","Ku","Die","Yin","Leng", - // "Hou","Ge","Yuan","Man","Yong","Liang","Chi","Xin","Pi","Yi","Cao","Jiao","Nai","Du","Qian","Ji", - // "Wan","Xiong","Qi","Xiang","Fu","Yuan","Yun","Fei","Ji","Li","E","Ju","Pi","Zhi","Rui","Xian", - // "Chang","Cong","Qin","Wu","Qian","Qi","Shan","Bian","Zhu","Kou","Yi","Mo","Gan","Pie","Long","Ba", - // "Mu","Ju","Ran","Qing","Chi","Fu","Ling","Niao","Yin","Mao","Ying","Qiong","Min","Tiao","Qian","Yi", - // "Rao","Bi","Zi","Ju","Tong","Hui","Zhu","Ting","Qiao","Fu","Ren","Xing","Quan","Hui","Xun","Ming", - // "Qi","Jiao","Chong","Jiang","Luo","Ying","Qian","Gen","Jin","Mai","Sun","Hong","Zhou","Kan","Bi","Shi", - // "Wo","You","E","Mei","You","Li","Tu","Xian","Fu","Sui","You","Di","Shen","Guan","Lang","Ying", - // "Chun","Jing","Qi","Xi","Song","Jin","Nai","Qi","Ba","Shu","Chang","Tie","Yu","Huan","Bi","Fu", - // "Tu","Dan","Cui","Yan","Zu","Dang","Jian","Wan","Ying","Gu","Han","Qia","Feng","Shen","Xiang","Wei", - // "Chan","Kai","Qi","Kui","Xi","E","Bao","Pa","Ting","Lou","Pai","Xuan","Jia","Zhen","Shi","Ru", - // "Mo","En","Bei","Weng","Hao","Ji","Li","Bang","Jian","Shuo","Lang","Ying","Yu","Su","Meng","Dou", - // "Xi","Lian","Cu","Lin","Qu","Kou","Xu","Liao","Hui","Xun","Jue","Rui","Zui","Ji","Meng","Fan", - // "Qi","Hong","Xie","Hong","Wei","Yi","Weng","Sou","Bi","Hao","Tai","Ru","Xun","Xian","Gao","Li", - // "Huo","Qu","Heng","Fan","Nie","Mi","Gong","Yi","Kuang","Lian","Da","Yi","Xi","Zang","Pao","You", - // "Liao","Ga","Gan","Ti","Men","Tuan","Chen","Fu","Pin","Niu","Jie","Jiao","Za","Yi","Lv","Jun", - // "Tian","Ye","Ai","Na","Ji","Guo","Bai","Ju","Pou","Lie","Qian","Guan","Die","Zha","Ya","Qin", - // "Yu","An","Xuan","Bing","Kui","Yuan","Shu","En","Chuai","Jian","Shuo","Zhan","Nuo","Sang","Luo","Ying", - // "Zhi","Han","Zhe","Xie","Lu","Zun","Cuan","Gan","Huan","Pi","Xing","Zhuo","Huo","Zuan","Nang","Yi", - // "Te","Dai","Shi","Bu","Chi","Ji","Kou","Dao","Le","Zha","A","Yao","Fu","Mu","Yi","Tai", - // "Li","E","Bi","Bei","Guo","Qin","Yin","Za","Ka","Ga","Gua","Ling","Dong","Ning","Duo","Nao", - // "You","Si","Kuang","Ji","Shen","Hui","Da","Lie","Yi","Xiao","Bi","Ci","Guang","Yue","Xiu","Yi", - // "Pai","Kuai","Duo","Ji","Mie","Mi","Zha","Nong","Gen","Mou","Mai","Chi","Lao","Geng","En","Zha", - // "Suo","Zao","Xi","Zuo","Ji","Feng","Ze","Nuo","Miao","Lin","Zhuan","Zhou","Tao","Hu","Cui","Sha", - // "Yo","Dan","Bo","Ding","Lang","Li","Shua","Chuo","Die","Da","Nan","Li","Kui","Jie","Yong","Kui", - // "Jiu","Sou","Yin","Chi","Jie","Lou","Ku","Wo","Hui","Qin","Ao","Su","Du","Ke","Nie","He", - // "Chen","Suo","Ge","A","En","Hao","Dia","Ai","Ai","Suo","Hei","Tong","Chi","Pei","Lei","Cao", - // "Piao","Qi","Ying","Beng","Sou","Di","Mi","Peng","Jue","Liao","Pu","Chuai","Jiao","O","Qin","Lu", - // "Ceng","Deng","Hao","Jin","Jue","Yi","Sai","Pi","Ru","Cha","Huo","Nang","Wei","Jian","Nan","Lun", - // "Hu","Ling","You","Yu","Qing","Yu","Huan","Wei","Zhi","Pei","Tang","Dao","Ze","Guo","Wei","Wo", - // "Man","Zhang","Fu","Fan","Ji","Qi","Qian","Qi","Qu","Ya","Xian","Ao","Cen","Lan","Ba","Hu", - // "Ke","Dong","Jia","Xiu","Dai","Gou","Mao","Min","Yi","Dong","Qiao","Xun","Zheng","Lao","Lai","Song", - // "Yan","Gu","Xiao","Guo","Kong","Jue","Rong","Yao","Wai","Zai","Wei","Yu","Cuo","Lou","Zi","Mei", - // "Sheng","Song","Ji","Zhang","Lin","Deng","Bin","Yi","Dian","Chi","Pang","Cu","Xun","Yang","Hou","Lai", - // "Xi","Chang","Huang","Yao","Zheng","Jiao","Qu","San","Fan","Qiu","An","Guang","Ma","Niu","Yun","Xia", - // "Pao","Fei","Rong","Kuai","Shou","Sun","Bi","Juan","Li","Yu","Xian","Yin","Suan","Yi","Guo","Luo", - // "Ni","She","Cu","Mi","Hu","Cha","Wei","Wei","Mei","Nao","Zhang","Jing","Jue","Liao","Xie","Xun", - // "Huan","Chuan","Huo","Sun","Yin","Dong","Shi","Tang","Tun","Xi","Ren","Yu","Chi","Yi","Xiang","Bo", - // "Yu","Hun","Zha","Sou","Mo","Xiu","Jin","San","Zhuan","Nang","Pi","Wu","Gui","Pao","Xiu","Xiang", - // "Tuo","An","Yu","Bi","Geng","Ao","Jin","Chan","Xie","Lin","Ying","Shu","Dao","Cun","Chan","Wu", - // "Zhi","Ou","Chong","Wu","Kai","Chang","Chuang","Song","Bian","Niu","Hu","Chu","Peng","Da","Yang","Zuo", - // "Ni","Fu","Chao","Yi","Yi","Tong","Yan","Ce","Kai","Xun","Ke","Yun","Bei","Song","Qian","Kui", - // "Kun","Yi","Ti","Quan","Qie","Xing","Fei","Chang","Wang","Chou","Hu","Cui","Yun","Kui","E","Leng", - // "Zhui","Qiao","Bi","Su","Qie","Yong","Jing","Qiao","Chong","Chu","Lin","Meng","Tian","Hui","Shuan","Yan", - // "Wei","Hong","Min","Kang","Ta","Lv","Kun","Jiu","Lang","Yu","Chang","Xi","Wen","Hun","E","Qu", - // "Que","He","Tian","Que","Kan","Jiang","Pan","Qiang","San","Qi","Si","Cha","Feng","Yuan","Mu","Mian", - // "Dun","Mi","Gu","Bian","Wen","Hang","Wei","Le","Gan","Shu","Long","Lu","Yang","Si","Duo","Ling", - // "Mao","Luo","Xuan","Pan","Duo","Hong","Min","Jing","Huan","Wei","Lie","Jia","Zhen","Yin","Hui","Zhu", - // "Ji","Xu","Hui","Tao","Xun","Jiang","Liu","Hu","Xun","Ru","Su","Wu","Lai","Wei","Zhuo","Juan", - // "Cen","Bang","Xi","Mei","Huan","Zhu","Qi","Xi","Song","Du","Zhuo","Pei","Mian","Gan","Fei","Cong", - // "Shen","Guan","Lu","Shuan","Xie","Yan","Mian","Qiu","Sou","Huang","Xu","Pen","Jian","Xuan","Wo","Mei", - // "Yan","Qin","Ke","She","Mang","Ying","Pu","Li","Ru","Ta","Hun","Bi","Xiu","Fu","Tang","Pang", - // "Ming","Huang","Ying","Xiao","Lan","Cao","Hu","Luo","Huan","Lian","Zhu","Yi","Lu","Xuan","Gan","Shu", - // "Si","Shan","Shao","Tong","Chan","Lai","Sui","Li","Dan","Chan","Lian","Ru","Pu","Bi","Hao","Zhuo", - // "Han","Xie","Ying","Yue","Fen","Hao","Ba","Bao","Gui","Dang","Mi","You","Chen","Ning","Jian","Qian", - // "Wu","Liao","Qian","Huan","Jian","Jian","Zou","Ya","Wu","Jiong","Ze","Yi","Er","Jia","Jing","Dai", - // "Hou","Pang","Bu","Li","Qiu","Xiao","Ti","Qun","Kui","Wei","Huan","Lu","Chuan","Huang","Qiu","Xia", - // "Ao","Gou","Ta","Liu","Xian","Lin","Ju","Xie","Miao","Sui","La","Ji","Hui","Tuan","Zhi","Kao", - // "Zhi","Ji","E","Chan","Xi","Ju","Chan","Jing","Nu","Mi","Fu","Bi","Yu","Che","Shuo","Fei", - // "Yan","Wu","Yu","Bi","Jin","Zi","Gui","Niu","Yu","Si","Da","Zhou","Shan","Qie","Ya","Rao", - // "Shu","Luan","Jiao","Pin","Cha","Li","Ping","Wa","Xian","Suo","Di","Wei","E","Jing","Biao","Jie", - // "Chang","Bi","Chan","Nu","Ao","Yuan","Ting","Wu","Gou","Mo","Pi","Ai","Pin","Chi","Li","Yan", - // "Qiang","Piao","Chang","Lei","Zhang","Xi","Shan","Bi","Niao","Mo","Shuang","Ga","Ga","Fu","Nu","Zi", - // "Jie","Jue","Bao","Zang","Si","Fu","Zou","Yi","Nu","Dai","Xiao","Hua","Pian","Li","Qi","Ke", - // "Zhui","Can","Zhi","Wu","Ao","Liu","Shan","Biao","Cong","Chan","Ji","Xiang","Jiao","Yu","Zhou","Ge", - // "Wan","Kuang","Yun","Pi","Shu","Gan","Xie","Fu","Zhou","Fu","Chu","Dai","Ku","Hang","Jiang","Geng", - // "Xiao","Ti","Ling","Qi","Fei","Shang","Gun","Duo","Shou","Liu","Quan","Wan","Zi","Ke","Xiang","Ti", - // "Miao","Hui","Si","Bian","Gou","Zhui","Min","Jin","Zhen","Ru","Gao","Li","Yi","Jian","Bin","Piao", - // "Man","Lei","Miao","Sao","Xie","Liao","Zeng","Jiang","Qian","Qiao","Huan","Zuan","Yao","Ji","Chuan","Zai", - // "Yong","Ding","Ji","Wei","Bin","Min","Jue","Ke","Long","Dian","Dai","Po","Min","Jia","Er","Gong", - // "Xu","Ya","Heng","Yao","Luo","Xi","Hui","Lian","Qi","Ying","Qi","Hu","Kun","Yan","Cong","Wan", - // "Chen","Ju","Mao","Yu","Yuan","Xia","Nao","Ai","Tang","Jin","Huang","Ying","Cui","Cong","Xuan","Zhang", - // "Pu","Can","Qu","Lu","Bi","Zan","Wen","Wei","Yun","Tao","Wu","Shao","Qi","Cha","Ma","Li", - // "Pi","Miao","Yao","Rui","Jian","Chu","Cheng","Cong","Xiao","Fang","Pa","Zhu","Nai","Zhi","Zhe","Long", - // "Jiu","Ping","Lu","Xia","Xiao","You","Zhi","Tuo","Zhi","Ling","Gou","Di","Li","Tuo","Cheng","Kao", - // "Lao","Ya","Rao","Zhi","Zhen","Guang","Qi","Ting","Gua","Jiu","Hua","Heng","Gui","Jie","Luan","Juan", - // "An","Xu","Fan","Gu","Fu","Jue","Zi","Suo","Ling","Chu","Fen","Du","Qian","Zhao","Luo","Chui", - // "Liang","Guo","Jian","Di","Ju","Cou","Zhen","Nan","Zha","Lian","Lan","Ji","Pin","Ju","Qiu","Duan", - // "Chui","Chen","Lv","Cha","Ju","Xuan","Mei","Ying","Zhen","Fei","Ta","Sun","Xie","Gao","Cui","Gao", - // "Shuo","Bin","Rong","Zhu","Xie","Jin","Qiang","Qi","Chu","Tang","Zhu","Hu","Gan","Yue","Qing","Tuo", - // "Jue","Qiao","Qin","Lu","Zun","Xi","Ju","Yuan","Lei","Yan","Lin","Bo","Cha","You","Ao","Mo", - // "Cu","Shang","Tian","Yun","Lian","Piao","Dan","Ji","Bin","Yi","Ren","E","Gu","Ke","Lu","Zhi", - // "Yi","Zhen","Hu","Li","Yao","Shi","Zhi","Quan","Lu","Zhe","Nian","Wang","Chuo","Zi","Cou","Lu", - // "Lin","Wei","Jian","Qiang","Jia","Ji","Ji","Kan","Deng","Gai","Jian","Zang","Ou","Ling","Bu","Beng", - // "Zeng","Pi","Po","Ga","La","Gan","Hao","Tan","Gao","Ze","Xin","Yun","Gui","He","Zan","Mao", - // "Yu","Chang","Ni","Qi","Sheng","Ye","Chao","Yan","Hui","Bu","Han","Gui","Xuan","Kui","Ai","Ming", - // "Tun","Xun","Yao","Xi","Nang","Ben","Shi","Kuang","Yi","Zhi","Zi","Gai","Jin","Zhen","Lai","Qiu", - // "Ji","Dan","Fu","Chan","Ji","Xi","Di","Yu","Gou","Jin","Qu","Jian","Jiang","Pin","Mao","Gu", - // "Wu","Gu","Ji","Ju","Jian","Pian","Kao","Qie","Suo","Bai","Ge","Bo","Mao","Mu","Cui","Jian", - // "San","Shu","Chang","Lu","Pu","Qu","Pie","Dao","Xian","Chuan","Dong","Ya","Yin","Ke","Yun","Fan", - // "Chi","Jiao","Du","Die","You","Yuan","Guo","Yue","Wo","Rong","Huang","Jing","Ruan","Tai","Gong","Zhun", - // "Na","Yao","Qian","Long","Dong","Ka","Lu","Jia","Shen","Zhou","Zuo","Gua","Zhen","Qu","Zhi","Jing", - // "Guang","Dong","Yan","Kuai","Sa","Hai","Pian","Zhen","Mi","Tun","Luo","Cuo","Pao","Wan","Niao","Jing", - // "Yan","Fei","Yu","Zong","Ding","Jian","Cou","Nan","Mian","Wa","E","Shu","Cheng","Ying","Ge","Lv", - // "Bin","Teng","Zhi","Chuai","Gu","Meng","Sao","Shan","Lian","Lin","Yu","Xi","Qi","Sha","Xin","Xi", - // "Biao","Sa","Ju","Sou","Biao","Biao","Shu","Gou","Gu","Hu","Fei","Ji","Lan","Yu","Pei","Mao", - // "Zhan","Jing","Ni","Liu","Yi","Yang","Wei","Dun","Qiang","Shi","Hu","Zhu","Xuan","Tai","Ye","Yang", - // "Wu","Han","Men","Chao","Yan","Hu","Yu","Wei","Duan","Bao","Xuan","Bian","Tui","Liu","Man","Shang", - // "Yun","Yi","Yu","Fan","Sui","Xian","Jue","Cuan","Huo","Tao","Xu","Xi","Li","Hu","Jiong","Hu", - // "Fei","Shi","Si","Xian","Zhi","Qu","Hu","Fu","Zuo","Mi","Zhi","Ci","Zhen","Tiao","Qi","Chan", - // "Xi","Zhuo","Xi","Rang","Te","Tan","Dui","Jia","Hui","Nv","Nin","Yang","Zi","Que","Qian","Min", - // "Te","Qi","Dui","Mao","Men","Gang","Yu","Yu","Ta","Xue","Miao","Ji","Gan","Dang","Hua","Che", - // "Dun","Ya","Zhuo","Bian","Feng","Fa","Ai","Li","Long","Zha","Tong","Di","La","Tuo","Fu","Xing", - // "Mang","Xia","Qiao","Zhai","Dong","Nao","Ge","Wo","Qi","Dui","Bei","Ding","Chen","Zhou","Jie","Di", - // "Xuan","Bian","Zhe","Gun","Sang","Qing","Qu","Dun","Deng","Jiang","Ca","Meng","Bo","Kan","Zhi","Fu", - // "Fu","Xu","Mian","Kou","Dun","Miao","Dan","Sheng","Yuan","Yi","Sui","Zi","Chi","Mou","Lai","Jian", - // "Di","Suo","Ya","Ni","Sui","Pi","Rui","Sou","Kui","Mao","Ke","Ming","Piao","Cheng","Kan","Lin", - // "Gu","Ding","Bi","Quan","Tian","Fan","Zhen","She","Wan","Tuan","Fu","Gang","Gu","Li","Yan","Pi", - // "Lan","Li","Ji","Zeng","He","Guan","Juan","Jin","Ga","Yi","Po","Zhao","Liao","Tu","Chuan","Shan", - // "Men","Chai","Nv","Bu","Tai","Ju","Ban","Qian","Fang","Kang","Dou","Huo","Ba","Yu","Zheng","Gu", - // "Ke","Po","Bu","Bo","Yue","Mu","Tan","Dian","Shuo","Shi","Xuan","Ta","Bi","Ni","Pi","Duo", - // "Kao","Lao","Er","You","Cheng","Jia","Nao","Ye","Cheng","Diao","Yin","Kai","Zhu","Ding","Diu","Hua", - // "Quan","Ha","Sha","Diao","Zheng","Se","Chong","Tang","An","Ru","Lao","Lai","Te","Keng","Zeng","Li", - // "Gao","E","Cuo","Lve","Liu","Kai","Jian","Lang","Qin","Ju","A","Qiang","Nuo","Ben","De","Ke", - // "Kun","Gu","Huo","Pei","Juan","Tan","Zi","Qie","Kai","Si","E","Cha","Sou","Huan","Ai","Lou", - // "Qiang","Fei","Mei","Mo","Ge","Juan","Na","Liu","Yi","Jia","Bin","Biao","Tang","Man","Luo","Yong", - // "Chuo","Xuan","Di","Tan","Jue","Pu","Lu","Dui","Lan","Pu","Cuan","Qiang","Deng","Huo","Zhuo","Yi", - // "Cha","Biao","Zhong","Shen","Cuo","Zhi","Bi","Zi","Mo","Shu","Lv","Ji","Fu","Lang","Ke","Ren", - // "Zhen","Ji","Se","Nian","Fu","Rang","Gui","Jiao","Hao","Xi","Po","Die","Hu","Yong","Jiu","Yuan", - // "Bao","Zhen","Gu","Dong","Lu","Qu","Chi","Si","Er","Zhi","Gua","Xiu","Luan","Bo","Li","Hu", - // "Yu","Xian","Ti","Wu","Miao","An","Bei","Chun","Hu","E","Ci","Mei","Wu","Yao","Jian","Ying", - // "Zhe","Liu","Liao","Jiao","Jiu","Yu","Hu","Lu","Guan","Bing","Ding","Jie","Li","Shan","Li","You", - // "Gan","Ke","Da","Zha","Pao","Zhu","Xuan","Jia","Ya","Yi","Zhi","Lao","Wu","Cuo","Xian","Sha", - // "Zhu","Fei","Gu","Wei","Yu","Yu","Dan","La","Yi","Hou","Chai","Lou","Jia","Sao","Chi","Mo", - // "Ban","Ji","Huang","Biao","Luo","Ying","Zhai","Long","Yin","Chou","Ban","Lai","Yi","Dian","Pi","Dian", - // "Qu","Yi","Song","Xi","Qiong","Zhun","Bian","Yao","Tiao","Dou","Ke","Yu","Xun","Ju","Yu","Yi", - // "Cha","Na","Ren","Jin","Mei","Pan","Dang","Jia","Ge","Ken","Lian","Cheng","Lian","Jian","Biao","Chu", - // "Ti","Bi","Ju","Duo","Da","Bei","Bao","Lv","Bian","Lan","Chi","Zhe","Qiang","Ru","Pan","Ya", - // "Xu","Jun","Cun","Jin","Lei","Zi","Chao","Si","Huo","Lao","Tang","Ou","Lou","Jiang","Nou","Mo", - // "Die","Ding","Dan","Ling","Ning","Guo","Kui","Ao","Qin","Han","Qi","Hang","Jie","He","Ying","Ke", - // "Han","E","Zhuan","Nie","Man","Sang","Hao","Ru","Pin","Hu","Qian","Qiu","Ji","Chai","Hui","Ge", - // "Meng","Fu","Pi","Rui","Xian","Hao","Jie","Gong","Dou","Yin","Chi","Han","Gu","Ke","Li","You", - // "Ran","Zha","Qiu","Ling","Cheng","You","Qiong","Jia","Nao","Zhi","Si","Qu","Ting","Kuo","Qi","Jiao", - // "Yang","Mou","Shen","Zhe","Shao","Wu","Li","Chu","Fu","Qiang","Qing","Qi","Xi","Yu","Fei","Guo", - // "Guo","Yi","Pi","Tiao","Quan","Wan","Lang","Meng","Chun","Rong","Nan","Fu","Kui","Ke","Fu","Sou", - // "Yu","You","Lou","You","Bian","Mou","Qin","Ao","Man","Mang","Ma","Yuan","Xi","Chi","Tang","Pang", - // "Shi","Huang","Cao","Piao","Tang","Xi","Xiang","Zhong","Zhang","Shuai","Mao","Peng","Hui","Pan","Shan","Huo", - // "Meng","Chan","Lian","Mie","Li","Du","Qu","Fou","Ying","Qing","Xia","Shi","Zhu","Yu","Ji","Du", - // "Ji","Jian","Zhao","Zi","Hu","Qiong","Po","Da","Sheng","Ze","Gou","Li","Si","Tiao","Jia","Bian", - // "Chi","Kou","Bi","Xian","Yan","Quan","Zheng","Jun","Shi","Gang","Pa","Shao","Xiao","Qing","Ze","Qie", - // "Zhu","Ruo","Qian","Tuo","Bi","Dan","Kong","Wan","Xiao","Zhen","Kui","Huang","Hou","Gou","Fei","Li", - // "Bi","Chi","Su","Mie","Dou","Lu","Duan","Gui","Dian","Zan","Deng","Bo","Lai","Zhou","Yu","Yu", - // "Chong","Xi","Nie","Nv","Chuan","Shan","Yi","Bi","Zhong","Ban","Fang","Ge","Lu","Zhu","Ze","Xi", - // "Shao","Wei","Meng","Shou","Cao","Chong","Meng","Qin","Niao","Jia","Qiu","Sha","Bi","Di","Qiang","Suo", - // "Jie","Tang","Xi","Xian","Mi","Ba","Li","Tiao","Xi","Zi","Can","Lin","Zong","San","Hou","Zan", - // "Ci","Xu","Rou","Qiu","Jiang","Gen","Ji","Yi","Ling","Xi","Zhu","Fei","Jian","Pian","He","Yi", - // "Jiao","Zhi","Qi","Qi","Yao","Dao","Fu","Qu","Jiu","Ju","Lie","Zi","Zan","Nan","Zhe","Jiang", - // "Chi","Ding","Gan","Zhou","Yi","Gu","Zuo","Tuo","Xian","Ming","Zhi","Yan","Shai","Cheng","Tu","Lei", - // "Kun","Pei","Hu","Ti","Xu","Hai","Tang","Lao","Bu","Jiao","Xi","Ju","Li","Xun","Shi","Cuo", - // "Dun","Qiong","Xue","Cu","Bie","Bo","Ta","Jian","Fu","Qiang","Zhi","Fu","Shan","Li","Tuo","Jia", - // "Bo","Tai","Kui","Qiao","Bi","Xian","Xian","Ji","Jiao","Liang","Ji","Chuo","Huai","Chi","Zhi","Dian", - // "Bo","Zhi","Jian","Die","Chuai","Zhong","Ju","Duo","Cuo","Pian","Rou","Nie","Pan","Qi","Chu","Jue", - // "Pu","Fan","Cu","Zhu","Lin","Chan","Lie","Zuan","Xie","Zhi","Diao","Mo","Xiu","Mo","Pi","Hu", - // "Jue","Shang","Gu","Zi","Gong","Su","Zhi","Zi","Qing","Liang","Yu","Li","Wen","Ting","Ji","Pei", - // "Fei","Sha","Yin","Ai","Xian","Mai","Chen","Ju","Bao","Tiao","Zi","Yin","Yu","Chuo","Wo","Mian", - // "Yuan","Tuo","Zhui","Sun","Jun","Ju","Luo","Qu","Chou","Qiong","Luan","Wu","Zan","Mou","Ao","Liu", - // "Bei","Xin","You","Fang","Ba","Ping","Nian","Lu","Su","Fu","Hou","Tai","Gui","Jie","Wei","Er", - // "Ji","Jiao","Xiang","Xun","Geng","Li","Lian","Jian","Shi","Tiao","Gun","Sha","Huan","Ji","Qing","Ling", - // "Zou","Fei","Kun","Chang","Gu","Ni","Nian","Diao","Shi","Zi","Fen","Die","E","Qiu","Fu","Huang", - // "Bian","Sao","Ao","Qi","Ta","Guan","Yao","Le","Biao","Xue","Man","Min","Yong","Gui","Shan","Zun", - // "Li","Da","Yang","Da","Qiao","Man","Jian","Ju","Rou","Gou","Bei","Jie","Tou","Ku","Gu","Di", - // "Hou","Ge","Ke","Bi","Lou","Qia","Kuan","Bin","Du","Mei","Ba","Yan","Liang","Xiao","Wang","Chi", - // "Xiang","Yan","Tie","Tao","Yong","Biao","Kun","Mao","Ran","Tiao","Ji","Zi","Xiu","Quan","Jiu","Bin", - // "Huan","Lie","Me","Hui","Mi","Ji","Jun","Zhu","Mi","Qi","Ao","She","Lin","Dai","Chu","You", - // "Xia","Yi","Qu","Du","Li","Qing","Can","An","Fen","You","Wu","Yan","Xi","Qiu","Han","Zha" - // }; - - // #endregion 二级汉字 - - // #region 变量定义 - - // // GB2312-80 标准规范中第一个汉字的机内码.即"啊"的机内码 - // private const int firstChCode = -20319; - - // // GB2312-80 标准规范中最后一个汉字的机内码.即"齄"的机内码 - // private const int lastChCode = -2050; - - // // GB2312-80 标准规范中最后一个一级汉字的机内码.即"座"的机内码 - // private const int lastOfOneLevelChCode = -10247; - - // // 配置中文字符 - // //static Regex regex = new Regex("[\u4e00-\u9fa5]$"); - - // #endregion 变量定义 - - // #region 自定义汉字 - - // private static readonly string[] CustomChinese = { - // "行" - // }; - - // private static readonly string[] CustomPinYin = { - // "Hang" - // }; - - // #endregion 自定义汉字 - - // #endregion 数组信息 - - // /// - // /// 取拼音第一个字段 - // /// - // /// - // /// - // public static String GetFirst(Char ch) - // { - // var rs = Get(ch); - // if (!String.IsNullOrEmpty(rs)) rs = rs.Substring(0, 1); - - // return rs; - // } - - // /// - // /// 取拼音第一个字段 - // /// - // /// - // /// - // public static String GetFirst(String str) - // { - // if (String.IsNullOrEmpty(str)) return String.Empty; - - // var sb = new StringBuilder(str.Length + 1); - // var chs = str.ToCharArray(); - - // for (var i = 0; i < chs.Length; i++) - // { - // sb.Append(GetFirst(chs[i])); - // } - - // return sb.ToString(); - // } - - // /// - // /// 获取单字拼音 - // /// - // /// - // /// - // public static String Get(Char ch) - // { - // #region xjh:优先匹配自定义的汉字 - - // int index = Array.IndexOf(CustomChinese, ch.ToString()); - // if (index != decimal.MinusOne) - // { - // return CustomPinYin[index]; - // } - - // #endregion xjh:优先匹配自定义的汉字 - - // // 拉丁字符 - // if (ch <= '\x00FF') return ch.ToString(); - - // // 标点符号、分隔符 - // if (Char.IsPunctuation(ch) || Char.IsSeparator(ch)) return ch.ToString(); - - // // 非中文字符 - // if (ch < '\x4E00' || ch > '\x9FA5') return ch.ToString(); - - // var arr = Encoding.GetEncoding("gb2312").GetBytes(ch.ToString()); - // //Encoding.Default默认在中文环境里虽是GB2312,但在多变的环境可能是其它 - // //var arr = Encoding.Default.GetBytes(ch.ToString()); - // var chr = (Int16)arr[0] * 256 + (Int16)arr[1] - 65536; - - // //***// 单字符--英文或半角字符 - // if (chr > 0 && chr < 160) return ch.ToString(); - - // #region 中文字符处理 - - // // 判断是否超过GB2312-80标准中的汉字范围 - // if (chr > lastChCode || chr < firstChCode) - // { - // return ch.ToString(); ; - // } - // // 如果是在一级汉字中 - // else if (chr <= lastOfOneLevelChCode) - // { - // // 将一级汉字分为12块,每块33个汉字. - // for (int aPos = 11; aPos >= 0; aPos--) - // { - // int aboutPos = aPos * 33; - // // 从最后的块开始扫描,如果机内码大于块的第一个机内码,说明在此块中 - // if (chr >= pyValue[aboutPos]) - // { - // // Console.WriteLine("存在于第 " + aPos.ToString() + " 块,此块的第一个机内码是: " + pyValue[aPos * 33].ToString()); - // // 遍历块中的每个音节机内码,从最后的音节机内码开始扫描, - // // 如果音节内码小于机内码,则取此音节 - // for (int i = aboutPos + 32; i >= aboutPos; i--) - // { - // if (pyValue[i] <= chr) - // { - // // Console.WriteLine("找到第一个小于要查找机内码的机内码: " + pyValue[i].ToString()); - // return pyName[i]; - // } - // } - // break; - // } - // } - // } - // // 如果是在二级汉字中 - // else - // { - // int pos = Array.IndexOf(otherChinese, ch.ToString()); - // if (pos != decimal.MinusOne) - // { - // return otherPinYin[pos]; - // } - // } - - // #endregion 中文字符处理 - - // //if (chr < -20319 || chr > -10247) { // 不知道的字符 - // // return null; - - // //for (var i = pyValue.Length - 1; i >= 0; i--) - // //{ - // // if (pyValue[i] <= chr) return pyName[i];//这只能对应数组已经定义的 - // //} - - // return String.Empty; - // } - - // /// - // /// 把汉字转换成拼音(全拼) - // /// - // /// 汉字字符串 - // /// 转换后的拼音(全拼)字符串 - // public static String Get(String str) - // { - // if (String.IsNullOrEmpty(str)) return String.Empty; - - // var sb = new StringBuilder(str.Length * 10); - // var chs = str.ToCharArray(); - - // for (var j = 0; j < chs.Length; j++) - // { - // sb.Append(Get(chs[j])); - // //sb.Append(" "); - // } - - // return sb.ToString(); - // } - //} -} diff --git a/Vampirewal.Core/Tools/RandomHelper.cs b/Vampirewal.Core/Tools/RandomHelper.cs index 7c86f322dc5038e2e318d662625ba4e768a3bba6..488d2e7a22dcb1d3ae18622c6a5d342eb3d0310c 100644 --- a/Vampirewal.Core/Tools/RandomHelper.cs +++ b/Vampirewal.Core/Tools/RandomHelper.cs @@ -13,153 +13,152 @@ using System; using System.Collections.Generic; -using System.Globalization; + using System.Linq; using System.Text; using System.Threading.Tasks; -namespace Vampirewal.Core.Tools +namespace Vampirewal.Core.Tools; + +/// +/// 随机数帮助类 +/// +public class RandomHelper { - /// - /// 随机数帮助类 - /// - public class RandomHelper - { - private static readonly char[] RandChar = - { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', - 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', - 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; - private static int seed = 1; + private static readonly char[] RandChar = + { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', + 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', + 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' }; + private static int seed = 1; - /// - /// 根据规则随机生成字符串 - /// - /// 样式:"?"代表一个字符,"#"代表一个一位数字,"*"代表一个字符串或一个一位数字 - /// 随机字符串 - public static string GetRandStringByPattern(string pattern) + /// + /// 根据规则随机生成字符串 + /// + /// 样式:"?"代表一个字符,"#"代表一个一位数字,"*"代表一个字符串或一个一位数字 + /// 随机字符串 + public static string GetRandStringByPattern(string pattern) + { + Random rand = new Random(unchecked((int)DateTime.Now.Ticks)); + if (!pattern.Contains("#") && !pattern.Contains("?") && !pattern.Contains("*")) { - Random rand = new Random(unchecked((int)DateTime.Now.Ticks)); - if (!pattern.Contains("#") && !pattern.Contains("?") && !pattern.Contains("*")) - { - return pattern; - } + return pattern; + } - char[] nums = pattern.ToCharArray(); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < nums.Length; i++) + char[] nums = pattern.ToCharArray(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < nums.Length; i++) + { + switch (nums[i]) { - switch (nums[i]) - { - case '?': - nums[i] = RandChar[rand.Next(10, 62)]; - break; - case '#': - nums[i] = RandChar[rand.Next(0, 10)]; - break; - case '*': - nums[i] = RandChar[rand.Next(62)]; - break; - default: - break; - } - - sb.Append(nums[i]); + case '?': + nums[i] = RandChar[rand.Next(10, 62)]; + break; + case '#': + nums[i] = RandChar[rand.Next(0, 10)]; + break; + case '*': + nums[i] = RandChar[rand.Next(62)]; + break; + default: + break; } - return sb.ToString(); - } - - /// - /// 生成随机的数值 - /// - /// 随机数可取该下界值 - /// 随机数的上界 - /// 随机的数值 - public static int GetFormatedNumeric(int min, int max) - { - int num = 0; - Random ro = new Random(unchecked(seed * (int)DateTime.Now.Ticks)); - num = ro.Next(min, max); - seed++; - return num; + sb.Append(nums[i]); } - /// - /// 获取指定长度和字符的随机字符串 - /// 通过调用 Random 类的 Next() 方法,先获得一个大于或等于 0 而小于 pwdchars 长度的整数 - /// 以该数作为索引值,从可用字符串中随机取字符,以指定的密码长度为循环次数 - /// 依次连接取得的字符,最后即得到所需的随机密码串了。 - /// - /// 随机字符串里包含的字符 - /// 随机字符串的长度 - /// 随机产生的字符串 - public static string GetRandomString(string pwdchars, int pwdlen) - { - Random rand = new Random(unchecked((int)DateTime.Now.Ticks)); - StringBuilder tmpstr = new StringBuilder(); - int randNum; + return sb.ToString(); + } - for (int i = 0; i < pwdlen; i++) - { - randNum = rand.Next(pwdchars.Length); - tmpstr.Append(pwdchars[randNum]); - } + /// + /// 生成随机的数值 + /// + /// 随机数可取该下界值 + /// 随机数的上界 + /// 随机的数值 + public static int GetFormatedNumeric(int min, int max) + { + int num = 0; + Random ro = new Random(unchecked(seed * (int)DateTime.Now.Ticks)); + num = ro.Next(min, max); + seed++; + return num; + } - return tmpstr.ToString(); - } + /// + /// 获取指定长度和字符的随机字符串 + /// 通过调用 Random 类的 Next() 方法,先获得一个大于或等于 0 而小于 pwdchars 长度的整数 + /// 以该数作为索引值,从可用字符串中随机取字符,以指定的密码长度为循环次数 + /// 依次连接取得的字符,最后即得到所需的随机密码串了。 + /// + /// 随机字符串里包含的字符 + /// 随机字符串的长度 + /// 随机产生的字符串 + public static string GetRandomString(string pwdchars, int pwdlen) + { + Random rand = new Random(unchecked((int)DateTime.Now.Ticks)); + StringBuilder tmpstr = new StringBuilder(); + int randNum; - /// - /// 获取指定长度的随机字符串 - /// - /// 随机字符串的长度 - /// 随机产生的字符串 - public static string GetRandomString(int pwdlen) + for (int i = 0; i < pwdlen; i++) { - return GetRandomString("abcdefghijklmnoaspqrstuvwxyzABCDEFGHIJKLMNasdfOPQRSTUVWXYZ0123456789_*", pwdlen); + randNum = rand.Next(pwdchars.Length); + tmpstr.Append(pwdchars[randNum]); } - /// - /// 获取指定长度的纯字母随机字符串 - /// - /// 数字串长度 - /// 纯字母随机字符串 - public static string GetRandWord(int pwdlen) - { - return GetRandomString("abcdefghijklmnopqrstuvwxyzdafasfaABCDEFGHIJKLMNOPQRSTUVWXYZ", pwdlen); - } + return tmpstr.ToString(); + } - /// - /// 获取指定长度的纯数字随机数字串 - /// - /// 数字串长度 - /// 纯数字随机数字串 - public static string GetRandomNum(int intlong) - { - Random rand = new Random(unchecked((int)DateTime.Now.Ticks)); - StringBuilder w = new StringBuilder(string.Empty); + /// + /// 获取指定长度的随机字符串 + /// + /// 随机字符串的长度 + /// 随机产生的字符串 + public static string GetRandomString(int pwdlen) + { + return GetRandomString("abcdefghijklmnoaspqrstuvwxyzABCDEFGHIJKLMNasdfOPQRSTUVWXYZ0123456789_*", pwdlen); + } - for (int i = 0; i < intlong; i++) - { - w.Append(rand.Next(10)); - } + /// + /// 获取指定长度的纯字母随机字符串 + /// + /// 数字串长度 + /// 纯字母随机字符串 + public static string GetRandWord(int pwdlen) + { + return GetRandomString("abcdefghijklmnopqrstuvwxyzdafasfaABCDEFGHIJKLMNOPQRSTUVWXYZ", pwdlen); + } - return w.ToString(); - } + /// + /// 获取指定长度的纯数字随机数字串 + /// + /// 数字串长度 + /// 纯数字随机数字串 + public static string GetRandomNum(int intlong) + { + Random rand = new Random(unchecked((int)DateTime.Now.Ticks)); + StringBuilder w = new StringBuilder(string.Empty); - /// - /// 获取按照年月时分秒随机数生成的文件名 - /// - /// 随机文件名 - public static string GetFileRndName() + for (int i = 0; i < intlong; i++) { - return DateTime.Now.ToString("yyyyMMddHHmmss", CultureInfo.CurrentCulture) + GetRandomString("0123456789", 4); + w.Append(rand.Next(10)); } + + return w.ToString(); + } + + /// + /// 获取按照年月时分秒随机数生成的文件名 + /// + /// 随机文件名 + public static string GetFileRndName() + { + return DateTime.Now.ToString("yyyyMMddHHmmss", CultureInfo.CurrentCulture) + GetRandomString("0123456789", 4); } } diff --git a/Vampirewal.Core/Tools/SetAppStart.cs b/Vampirewal.Core/Tools/SetAppStart.cs index 24deebf70f94709921bf315728e4cfd8ef44a21a..97f68cd844f55fef0ebe449da5dd38907abf20f6 100644 --- a/Vampirewal.Core/Tools/SetAppStart.cs +++ b/Vampirewal.Core/Tools/SetAppStart.cs @@ -11,142 +11,136 @@ //----------------------------------------------------------------*/ #endregion -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Microsoft.Win32; -namespace Vampirewal.Core.Tools + + +namespace Vampirewal.Core.Tools; + +/// +/// 设置应用程序开机启动/取消开机启动 +/// appName = Process.GetCurrentProcess().MainModule.ModuleName; +/// appPath = Process.GetCurrentProcess().MainModule.FileName; +/// +public class SetAppStart { /// - /// 设置应用程序开机启动/取消开机启动 - /// appName = Process.GetCurrentProcess().MainModule.ModuleName; - /// appPath = Process.GetCurrentProcess().MainModule.FileName; + /// 将本程序设为开启自启 /// - public class SetAppStart + /// 自启开关 + /// + public static bool SetMeStart(bool onOff) { - /// - /// 将本程序设为开启自启 - /// - /// 自启开关 - /// - public static bool SetMeStart(bool onOff) + bool isOk = false; + string appName = Process.GetCurrentProcess().MainModule.ModuleName; + string appPath = Process.GetCurrentProcess().MainModule.FileName; + isOk = SetAutoStart(onOff, appName, appPath); + return isOk; + } + + /// + /// 将应用程序设为或不设为开机启动 + /// + /// 自启开关 + /// 应用程序名 + /// 应用程序完全路径 + public static bool SetAutoStart(bool onOff, string appName, string appPath) + { + bool isOk = true; + //如果从没有设为开机启动设置到要设为开机启动 + if (!IsExistKey(appName) && onOff) { - bool isOk = false; - string appName = Process.GetCurrentProcess().MainModule.ModuleName; - string appPath = Process.GetCurrentProcess().MainModule.FileName; - isOk = SetAutoStart(onOff, appName, appPath); - return isOk; + isOk = SelfRunning(onOff, appName, @appPath); } + //如果从设为开机启动设置到不要设为开机启动 + else if (IsExistKey(appName) && !onOff) + { + isOk = SelfRunning(onOff, appName, @appPath); + } + return isOk; + } - /// - /// 将应用程序设为或不设为开机启动 - /// - /// 自启开关 - /// 应用程序名 - /// 应用程序完全路径 - public static bool SetAutoStart(bool onOff, string appName, string appPath) + /// + /// 判断注册键值对是否存在,即是否处于开机启动状态 + /// + /// 键值名 + /// + private static bool IsExistKey(string appName) + { + try { - bool isOk = true; - //如果从没有设为开机启动设置到要设为开机启动 - if (!IsExistKey(appName) && onOff) + bool _exist = false; + RegistryKey local = Registry.LocalMachine; + RegistryKey runs = local.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true); + if (runs == null) { - isOk = SelfRunning(onOff, appName, @appPath); + RegistryKey key2 = local.CreateSubKey("SOFTWARE"); + RegistryKey key3 = key2.CreateSubKey("Microsoft"); + RegistryKey key4 = key3.CreateSubKey("Windows"); + RegistryKey key5 = key4.CreateSubKey("CurrentVersion"); + RegistryKey key6 = key5.CreateSubKey("Run"); + runs = key6; } - //如果从设为开机启动设置到不要设为开机启动 - else if (IsExistKey(appName) && !onOff) + string[] runsName = runs.GetValueNames(); + foreach (string strName in runsName) { - isOk = SelfRunning(onOff, appName, @appPath); + if (strName.ToUpper() == appName.ToUpper()) + { + _exist = true; + return _exist; + } } - return isOk; + return _exist; + } + catch + { + return false; + } + } - /// - /// 判断注册键值对是否存在,即是否处于开机启动状态 - /// - /// 键值名 - /// - private static bool IsExistKey(string appName) + /// + /// 写入或删除注册表键值对,即设为开机启动或开机不启动 + /// + /// 是否开机启动 + /// 应用程序名 + /// 应用程序路径带程序名 + /// + private static bool SelfRunning(bool isStart, string exeName, string path) + { + try { - try + RegistryKey local = Registry.LocalMachine; + RegistryKey key = local.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true); + if (key == null) { - bool _exist = false; - RegistryKey local = Registry.LocalMachine; - RegistryKey runs = local.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true); - if (runs == null) - { - RegistryKey key2 = local.CreateSubKey("SOFTWARE"); - RegistryKey key3 = key2.CreateSubKey("Microsoft"); - RegistryKey key4 = key3.CreateSubKey("Windows"); - RegistryKey key5 = key4.CreateSubKey("CurrentVersion"); - RegistryKey key6 = key5.CreateSubKey("Run"); - runs = key6; - } - string[] runsName = runs.GetValueNames(); - foreach (string strName in runsName) - { - if (strName.ToUpper() == appName.ToUpper()) - { - _exist = true; - return _exist; - } - } - return _exist; - + local.CreateSubKey("SOFTWARE//Microsoft//Windows//CurrentVersion//Run"); } - catch + //若开机自启动则添加键值对 + if (isStart) { - return false; + key.SetValue(exeName, path); + key.Close(); } - } - - /// - /// 写入或删除注册表键值对,即设为开机启动或开机不启动 - /// - /// 是否开机启动 - /// 应用程序名 - /// 应用程序路径带程序名 - /// - private static bool SelfRunning(bool isStart, string exeName, string path) - { - try + else//否则删除键值对 { - RegistryKey local = Registry.LocalMachine; - RegistryKey key = local.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true); - if (key == null) + string[] keyNames = key.GetValueNames(); + foreach (string keyName in keyNames) { - local.CreateSubKey("SOFTWARE//Microsoft//Windows//CurrentVersion//Run"); - } - //若开机自启动则添加键值对 - if (isStart) - { - key.SetValue(exeName, path); - key.Close(); - } - else//否则删除键值对 - { - string[] keyNames = key.GetValueNames(); - foreach (string keyName in keyNames) + if (keyName.ToUpper() == exeName.ToUpper()) { - if (keyName.ToUpper() == exeName.ToUpper()) - { - key.DeleteValue(exeName); - key.Close(); - } + key.DeleteValue(exeName); + key.Close(); } } } - catch (Exception ex) - { - string ss = ex.Message; - return false; - //throw; - } - - return true; } + catch (Exception ex) + { + string ss = ex.Message; + return false; + //throw; + } + + return true; } } diff --git a/Vampirewal.Core/Tools/TuoMinHelper.cs b/Vampirewal.Core/Tools/TuoMinHelper.cs new file mode 100644 index 0000000000000000000000000000000000000000..e132e25381bfb908eef5e76ac04b6478c730b5bb --- /dev/null +++ b/Vampirewal.Core/Tools/TuoMinHelper.cs @@ -0,0 +1,169 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:TuoMinHelper +// 创 建 人:YangCheng +// 创建时间:2022/8/4 17:49:20 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + + + +namespace Vampirewal.Core.Tools; + +/// +/// 文本脱敏助手 +/// +public class TuoMinHelper +{ + /// + /// 隐藏敏感信息 + /// + /// 信息实体 + /// 左边保留的字符数 + /// 右边保留的字符数 + /// 当长度异常时,是否显示左边 + /// true显示左边,false显示右边 + /// + /// + public static string HideSensitiveInfo(string info, int left, int right, bool basedOnLeft = true) + { + if (String.IsNullOrEmpty(info)) + { + return ""; + } + StringBuilder sbText = new StringBuilder(); + int hiddenCharCount = info.Length - left - right; + if (hiddenCharCount > 0) + { + string prefix = info.Substring(0, left), suffix = info.Substring(info.Length - right); + sbText.Append(prefix); + for (int i = 0; i < hiddenCharCount; i++) + { + sbText.Append("*"); + } + sbText.Append(suffix); + } + else + { + if (basedOnLeft) + { + if (info.Length > left && left > 0) + { + sbText.Append(info.Substring(0, left) + "****"); + } + else + { + sbText.Append(info.Substring(0, 1) + "****"); + } + } + else + { + if (info.Length > right && right > 0) + { + sbText.Append("****" + info.Substring(info.Length - right)); + } + else + { + sbText.Append("****" + info.Substring(info.Length - 1)); + } + } + } + return sbText.ToString(); + } + + /// + /// 隐藏敏感信息 + /// + /// 信息实体 + /// 左边保留的字符数 + /// 右边保留的字符数 + /// 当长度异常时,是否显示左边 + /// true显示左边,false显示右边 + /// + public static string HideSensitiveInfo1(string info, int left, int right, bool basedOnLeft = true) + { + if (String.IsNullOrEmpty(info)) + { + return ""; + } + StringBuilder sbText = new StringBuilder(); + int hiddenCharCount = info.Length - left - right; + if (hiddenCharCount > 0) + { + string prefix = info.Substring(0, left), suffix = info.Substring(info.Length - right); + sbText.Append(prefix); + sbText.Append("****"); + sbText.Append(suffix); + } + else + { + if (basedOnLeft) + { + if (info.Length > left && left > 0) + { + sbText.Append(info.Substring(0, left) + "****"); + } + else + { + sbText.Append(info.Substring(0, 1) + "****"); + } + } + else + { + if (info.Length > right && right > 0) + { + sbText.Append("****" + info.Substring(info.Length - right)); + } + else + { + sbText.Append("****" + info.Substring(info.Length - 1)); + } + } + } + return sbText.ToString(); + } + + /// + /// 隐藏敏感信息 + /// + /// 信息 + /// 信息总长与左子串(或右子串)的比例 + /// 当长度异常时,是否显示左边,默认true,默认显示左边 + /// true显示左边,false显示右边 + /// + public static string HideSensitiveInfo(string info, int sublen = 3, bool basedOnLeft = true) + { + if (String.IsNullOrEmpty(info)) + { + return ""; + } + if (sublen <= 1) + { + sublen = 3; + } + int subLength = info.Length / sublen; + if (subLength > 0 && info.Length > (subLength * 2)) + { + string prefix = info.Substring(0, subLength), suffix = info.Substring(info.Length - subLength); + return prefix + "****" + suffix; + } + else + { + if (basedOnLeft) + { + string prefix = subLength > 0 ? info.Substring(0, subLength) : info.Substring(0, 1); + return prefix + "****"; + } + else + { + string suffix = subLength > 0 ? info.Substring(info.Length - subLength) : info.Substring(info.Length - 1); + return "****" + suffix; + } + } + } +} diff --git a/Vampirewal.Core/Tools/Utils.cs b/Vampirewal.Core/Tools/Utils.cs index d44e574601ddd294e0073f3b050777d0b4dd9ce1..908565f8a4c7da5f7f91364f60fa19f33656361f 100644 --- a/Vampirewal.Core/Tools/Utils.cs +++ b/Vampirewal.Core/Tools/Utils.cs @@ -23,10 +23,11 @@ using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; -using Microsoft.Extensions.Caching.Distributed; +//using Microsoft.Extensions.Caching.Distributed; using Vampirewal.Core.Interface; using Vampirewal.Core.Models; -using NPOI.HSSF.Util; +using System.Text.Json; +//using NPOI.HSSF.Util; namespace Vampirewal.Core { @@ -49,7 +50,7 @@ namespace Vampirewal.Core { var rv = new List(); var path = Assembly.GetEntryAssembly().Location; - var dir = new DirectoryInfo(Path.GetDirectoryName(path)); + var dir = new DirectoryInfo(System.IO.Path.GetDirectoryName(path)); var dlls = dir.GetFiles("*.dll", SearchOption.AllDirectories); string[] systemdll = new string[] @@ -124,7 +125,16 @@ namespace Vampirewal.Core return fieldName == null ? "" : fieldName.Replace(".", "_").Replace("[", "_").Replace("]", "_"); } - public static void CheckDifference(IEnumerable oldList, IEnumerable newList, out IEnumerable ToRemove, out IEnumerable ToAdd) where T : TopBaseModel + + /// + /// 验证不同项 + /// + /// + /// 旧列表 + /// 新列表 + /// 需移除的 + /// 需新增的 + public static void CheckDifference(IEnumerable oldList, IEnumerable newList, out IEnumerable ToRemove, out IEnumerable ToAdd) where T : TopModel { List tempToRemove = new List(); List tempToAdd = new List(); @@ -135,7 +145,7 @@ namespace Vampirewal.Core bool exist = false; foreach (var newItem in newList) { - if (oldItem.GetID().ToString() == newItem.GetID().ToString()) + if (oldItem.GetBillID().ToString() == newItem.GetBillID().ToString()) { exist = true; break; @@ -151,7 +161,7 @@ namespace Vampirewal.Core bool exist = false; foreach (var oldItem in oldList) { - if (newItem.GetID().ToString() == oldItem.GetID().ToString()) + if (newItem.GetBillID().ToString() == oldItem.GetBillID().ToString()) { exist = true; break; @@ -166,49 +176,49 @@ namespace Vampirewal.Core ToAdd = tempToAdd.AsEnumerable(); } - public static short GetExcelColor(string color) - { - var colors = typeof(HSSFColor).GetNestedTypes().ToList(); - foreach (var col in colors) - { - var pro = col.GetField("hexString"); - if (pro == null) - { - continue; - } - var hex = pro.GetValue(null); - var rgb = hex.ToString().Split(':'); - for (int i = 0; i < rgb.Length; i++) - { - if (rgb[i].Length > 2) - { - rgb[i] = rgb[i].Substring(0, 2); - } - } - int r = Convert.ToInt16(rgb[0], 16); - int g = Convert.ToInt16(rgb[1], 16); - int b = Convert.ToInt16(rgb[2], 16); + //public static short GetExcelColor(string color) + //{ + // var colors = typeof(HSSFColor).GetNestedTypes().ToList(); + // foreach (var col in colors) + // { + // var pro = col.GetField("hexString"); + // if (pro == null) + // { + // continue; + // } + // var hex = pro.GetValue(null); + // var rgb = hex.ToString().Split(':'); + // for (int i = 0; i < rgb.Length; i++) + // { + // if (rgb[i].Length > 2) + // { + // rgb[i] = rgb[i].Substring(0, 2); + // } + // } + // int r = Convert.ToInt16(rgb[0], 16); + // int g = Convert.ToInt16(rgb[1], 16); + // int b = Convert.ToInt16(rgb[2], 16); - if (color.Length == 8) - { - color = color.Substring(2); - } - string c1 = color.Substring(0, 2); - string c2 = color.Substring(2, 2); - string c3 = color.Substring(4, 2); + // if (color.Length == 8) + // { + // color = color.Substring(2); + // } + // string c1 = color.Substring(0, 2); + // string c2 = color.Substring(2, 2); + // string c3 = color.Substring(4, 2); - int r1 = Convert.ToInt16(c1, 16); - int g1 = Convert.ToInt16(c2, 16); - int b1 = Convert.ToInt16(c3, 16); + // int r1 = Convert.ToInt16(c1, 16); + // int g1 = Convert.ToInt16(c2, 16); + // int b1 = Convert.ToInt16(c3, 16); - if (r == r1 && g == g1 && b == b1) - { - return (short)col.GetField("index").GetValue(null); - } - } - return HSSFColor.COLOR_NORMAL; - } + // if (r == r1 && g == g1 && b == b1) + // { + // return (short)col.GetField("index").GetValue(null); + // } + // } + // return HSSFColor.COLOR_NORMAL; + //} ///// ///// 获取Bool类型的下拉框 @@ -327,7 +337,7 @@ namespace Vampirewal.Core } /// - /// + /// 删除文件 /// /// public static void DeleteFile(string path) @@ -339,7 +349,7 @@ namespace Vampirewal.Core catch { } } - #region 格式化文本 add by wuwh 2014.6.12 + #region 格式化文本 /// /// 格式化文本 /// @@ -397,7 +407,7 @@ namespace Vampirewal.Core } #endregion - #region 格式化代码 edit by wuwh + #region 格式化代码 /// /// 格式化代码 /// @@ -547,17 +557,17 @@ namespace Vampirewal.Core // return cs; //} - public static string GetUrlByFileAttachmentId(IDataContext dc, Guid? fileAttachmentId, bool isIntranetUrl = false, string urlHeader = null) - { - string url = string.Empty; - var fileAttachment = dc.Set().Where(x => x.ID == fileAttachmentId.Value.ToString()).FirstOrDefault(); - if (fileAttachment != null) - { - url = "/_Framework/GetFile/" + fileAttachmentId.ToString(); + //public static string GetUrlByFileAttachmentId(IDataContext dc, Guid? fileAttachmentId, bool isIntranetUrl = false, string urlHeader = null) + //{ + // string url = string.Empty; + // var fileAttachment = dc.Set().Where(x => x.ID == fileAttachmentId.Value.ToString()).FirstOrDefault(); + // if (fileAttachment != null) + // { + // url = "/_Framework/GetFile/" + fileAttachmentId.ToString(); - } - return url; - } + // } + // return url; + //} #region 加解密 /// @@ -790,5 +800,68 @@ namespace Vampirewal.Core return false; } } + + #region model转换 + + /// + /// 模型转换 + /// + /// 转换成的类型 + /// 被转换的model + /// + public OutT ModelConverter(InT model) + { + Type InType = typeof(InT); + InT inTModel = model; + + Type OutType = typeof(OutT); + OutT outTModel = (OutT)Activator.CreateInstance(OutType); + + //通过反射去遍历属性 + foreach (PropertyInfo inProperty in InType.GetProperties()) + { + foreach (PropertyInfo OutProperty in OutType.GetProperties()) + { + if (inProperty.Name == OutProperty.Name && inProperty.PropertyType == OutProperty.PropertyType) + { + OutProperty.SetValue(outTModel, inProperty.GetValue(inTModel)); + } + } + } + + return outTModel; + } + + /// + /// 模型转换 + /// + /// 被转换的类型 + /// 转换成的类型 + /// 需要转换的json + /// + public static OutT ModelConverter(string json) + { + Type InType = typeof(InT); + InT inTModel = System.Text.Json.JsonSerializer.Deserialize(json); + + Type OutType = typeof(OutT); + OutT outTModel = (OutT)Activator.CreateInstance(OutType); + + //通过反射去遍历属性 + foreach (PropertyInfo inProperty in InType.GetProperties()) + { + foreach (PropertyInfo OutProperty in OutType.GetProperties()) + { + if (inProperty.Name == OutProperty.Name && inProperty.PropertyType == OutProperty.PropertyType) + { + OutProperty.SetValue(outTModel, inProperty.GetValue(inTModel)); + } + } + } + + return outTModel; + } + + #endregion } } diff --git a/Vampirewal.Core/Vampirewal.Core.csproj b/Vampirewal.Core/Vampirewal.Core.csproj index 2a2325848abb4eb0906e8fd1423958e18ca29f90..226b7fcc21011c7488ff91051abf43d7d6f35161 100644 --- a/Vampirewal.Core/Vampirewal.Core.csproj +++ b/Vampirewal.Core/Vampirewal.Core.csproj @@ -1,62 +1,106 @@ - net5.0-windows + net6.0-windows true vampirewal - 该Core类库详细介绍请查看:https://blog.csdn.net/weixin_42806176/article/details/120705323 + 该Core类库详细介绍请查看:https://blog.csdn.net/weixin_42806176/article/details/120705323 +(3.X使用较多外部nuget,2.X开始的ORM使用SqlSugar,1.X使用的EFCore) true - 1.0.1.3 + 3.1.31 true https://blog.csdn.net/weixin_42806176/article/details/120705323 Vampirewal-Logo.png + + LICENSE + True + + + + embedded + + + + embedded - + + + - - - True - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Always - + + + - + - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - + + + + + - - + + - - $(DefaultXamlRuntime) - Designer - - - $(DefaultXamlRuntime) - Designer - - - $(DefaultXamlRuntime) - Designer - + + True + \ + diff --git a/Vampirewal.Core/VampirewalCoreContext.cs b/Vampirewal.Core/VampirewalCoreContext.cs new file mode 100644 index 0000000000000000000000000000000000000000..1a6a8156be3a58fd0fd9ba0fd0e91c8c950a1170 --- /dev/null +++ b/Vampirewal.Core/VampirewalCoreContext.cs @@ -0,0 +1,314 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: AppContext +// 创建者: 杨程 +// 创建日期: 2022/11/25 14:17:13 + +//----------------------------------------------------------------*/ +#endregion + +global using Castle.DynamicProxy; +global using CommunityToolkit.Mvvm.ComponentModel; +global using CommunityToolkit.Mvvm.Input; +global using Microsoft.Extensions.DependencyInjection.Extensions; +global using Microsoft.Extensions.DependencyInjection; +global using Microsoft.Win32; +global using Microsoft.Xaml.Behaviors; +global using Newtonsoft.Json.Linq; +global using Newtonsoft.Json; +global using SqlSugar; +global using System.Collections.Generic; +global using System.Collections.Immutable; +global using System.Collections.ObjectModel; +global using System.Collections.Specialized; +global using System.Collections; +global using System.ComponentModel.DataAnnotations.Schema; +global using System.ComponentModel.DataAnnotations; +global using System.ComponentModel; +global using System.Data; +global using System.Diagnostics; +global using System.Dynamic; +global using System.Globalization; +global using System.IO; +global using System.Linq.Expressions; +global using System.Linq; +global using System.Reflection; +global using System.Runtime.CompilerServices; +global using System.Security.Cryptography; +global using System.Text.RegularExpressions; +global using System.Text; +global using System.Threading.Tasks; +global using System.Windows.Controls.Primitives; +global using System.Windows.Controls; +global using System.Windows.Data; +global using System.Windows.Input; +global using System.Windows.Media.Animation; +global using System.Windows.Media.Imaging; +global using System.Windows.Media; +global using System.Windows.Shapes; +global using System.Windows.Shell; +global using System.Windows.Threading; +global using System.Windows; +global using System; +global using Vampirewal.Core.AppConfig; +global using Vampirewal.Core.Attributes; +global using Vampirewal.Core.Components; +global using Vampirewal.Core.ConfigOptions; +global using Vampirewal.Core.Interface; +global using Vampirewal.Core.Models; +global using Vampirewal.Core.SimpleMVVM; +global using Vampirewal.Core.WpfTheme.Converter; +global using Vampirewal.Core.WpfTheme.CustomControl; +global using Vampirewal.Core.WpfTheme.UcView; +global using Vampirewal.Core.WpfTheme.WindowStyle; + +namespace Vampirewal.Core; + +/// +/// 程序上下文 +/// +[DebuggerStepThrough] +public class VampirewalCoreContext : BaseSingleton +{ + #region [ 全局上下文数据 ] + /// + /// 全局上下文字典 + /// + private Dictionary GlobalContext { get; set; } + + /// + /// 添加上下文数据 + /// + /// + /// + /// + public bool AddContext(string key, object value) + { + if (GlobalContext == null) + { + GlobalContext = new Dictionary(); + } + + return GlobalContext.TryAdd(key, value); + } + + /// + /// 获取上下文数据 + /// + /// + /// + /// + public bool GetContext(string Key, out object value) + { + if (GlobalContext == null) + { + GlobalContext = new Dictionary(); + } + + return GlobalContext.TryGetValue(Key, out value); + } + + /// + /// 移除上下文数据 + /// + /// + /// + public bool RemoveContext(string Key) + { + if (GlobalContext == null) + { + GlobalContext = new Dictionary(); + } + + return GlobalContext.Remove(Key); + } + + /// + /// 获取上下文数据 + /// + /// + /// + /// + public T GetContext(string key) + { + if (GlobalContext == null) + { + GlobalContext = new Dictionary(); + } + + if (GlobalContext.TryGetValue(key, out object value)) + { + return (T)value; + } + + return default(T); + } + + /// + /// 获取全部上下文 + /// + /// + public Dictionary GetAllContext() + { + return GlobalContext; + } + + #endregion + + #region [ IoC容器 ] + /// + /// IOC容器 + /// + internal IServiceProvider Services { get; private set; } + + /// + /// 设置容器到程序上下文中 + /// + /// + internal void SetService(IServiceProvider serviceProvider) + { + if (Services == null) + { + Services = serviceProvider; + } + } + + /// + /// 获取服务 + /// + /// + /// + public T GetService() + { + return Services.GetService(); + } + + /// + /// 获取服务 + /// + /// + /// + /// + public T GetService(Type type) + { + return (T)Services.GetService(type); + } + #endregion + + #region [ View和ViewModel ] + + /// + /// 储存View和ViewModel的Token与Type字典 + /// + private Dictionary ViewAndVMDic { get; set; } = new Dictionary(); + + /// + /// 添加View或ViewModel进字典 + /// + /// + /// + /// + internal bool AddViewAndVMDic(string key,Type ViewOrViewModelType) + { + return ViewAndVMDic.TryAdd(key, ViewOrViewModelType); + } + + /// + /// 获取View或ViewModel类型 + /// + /// + /// + /// + internal bool GetViewOrViewModel(string key,out Type type) + { + return ViewAndVMDic.TryGetValue(key, out type); + } + + + /// + /// 获取页面 + /// + /// + /// + /// + /// + internal T GetView(string ViewKey) + { + if (ViewAndVMDic.TryGetValue(ViewKey, out Type view)) + { + return GetService(view); + } + + + throw new Exception("未注册该Key值的窗体!"); + } + + /// + /// 获取ViewModel + /// + /// + /// + /// + /// + internal T GetViewModel(string ViewModelKey) + { + if (ViewAndVMDic.TryGetValue(ViewModelKey, out Type viewmodel)) + { + return GetService(viewmodel); + } + + + throw new Exception("未注册该key值的ViewModel!"); + } + #endregion + + #region [ 获取/保存配置 ] + + /// + /// 获取配置项 + /// + /// + /// + public T GetOptions() where T:IOptions + { + return GetService().GetOptions(); + } + + /// + /// 保存配置项 + /// + /// + /// + public void SetOptions(T options) where T : IOptions + { + GetService().SaveOptions(options); + } + + /// + /// 完整保存配置文件 + /// + public void SaveConfig() + { + GetService().SaveConfig(); + } + + /// + /// 根据A:B:C这样的来获取数据 + /// + /// + /// + public T GetOptionsValue(string key) + { + return GetService().GetOptionsValue(key); + } + #endregion +} + + + diff --git a/Vampirewal.Core/WpfTheme/Attach/TextBoxAttach.cs b/Vampirewal.Core/WpfTheme/Attach/TextBoxAttach.cs index bdaa9c7a5de790bc07a716a1e04b1576ce92baa8..a1b55d7f697ebf0711081182ce90de6fdbde194d 100644 --- a/Vampirewal.Core/WpfTheme/Attach/TextBoxAttach.cs +++ b/Vampirewal.Core/WpfTheme/Attach/TextBoxAttach.cs @@ -11,158 +11,151 @@ //----------------------------------------------------------------*/ #endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; - -namespace Vampirewal.Core.WpfTheme.Attach + + + +namespace Vampirewal.Core.WpfTheme.Attach; + +/// +/// 文本框附加属性 +/// +public class TextBoxAttach : DependencyObject { + #region FocusBorderBrush 焦点边框色,输入控件 + + public static readonly DependencyProperty FocusBorderBrushProperty = DependencyProperty.RegisterAttached( + "FocusBorderBrush", typeof(Brush), typeof(TextBoxAttach), new FrameworkPropertyMetadata(null)); + public static void SetFocusBorderBrush(DependencyObject element, Brush value) + { + element.SetValue(FocusBorderBrushProperty, value); + } + public static Brush GetFocusBorderBrush(DependencyObject element) + { + return (Brush)element.GetValue(FocusBorderBrushProperty); + } + + #endregion + + #region MouseOverBorderBrush 鼠标进入边框色,输入控件 + + public static readonly DependencyProperty MouseOverBorderBrushProperty = + DependencyProperty.RegisterAttached("MouseOverBorderBrush", typeof(Brush), typeof(TextBoxAttach), + new FrameworkPropertyMetadata(Brushes.Transparent, + FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits)); + + /// + /// Sets the brush used to draw the mouse over brush. + /// + public static void SetMouseOverBorderBrush(DependencyObject obj, Brush value) + { + obj.SetValue(MouseOverBorderBrushProperty, value); + } + + /// + /// Gets the brush used to draw the mouse over brush. + /// + [AttachedPropertyBrowsableForType(typeof(TextBox))] + [AttachedPropertyBrowsableForType(typeof(CheckBox))] + [AttachedPropertyBrowsableForType(typeof(RadioButton))] + [AttachedPropertyBrowsableForType(typeof(DatePicker))] + [AttachedPropertyBrowsableForType(typeof(ComboBox))] + [AttachedPropertyBrowsableForType(typeof(RichTextBox))] + public static Brush GetMouseOverBorderBrush(DependencyObject obj) + { + return (Brush)obj.GetValue(MouseOverBorderBrushProperty); + } + + #endregion + + #region AttachContentProperty 附加组件模板 + /// + /// 附加组件模板 + /// + public static readonly DependencyProperty AttachContentProperty = DependencyProperty.RegisterAttached( + "AttachContent", typeof(ControlTemplate), typeof(TextBoxAttach), new FrameworkPropertyMetadata(null)); + + public static ControlTemplate GetAttachContent(DependencyObject d) + { + return (ControlTemplate)d.GetValue(AttachContentProperty); + } + + public static void SetAttachContent(DependencyObject obj, ControlTemplate value) + { + obj.SetValue(AttachContentProperty, value); + } + #endregion + + #region WatermarkProperty 水印 + /// + /// 水印 + /// + public static readonly DependencyProperty WatermarkProperty = DependencyProperty.RegisterAttached( + "Watermark", typeof(string), typeof(TextBoxAttach), new FrameworkPropertyMetadata("")); + + public static string GetWatermark(DependencyObject d) + { + return (string)d.GetValue(WatermarkProperty); + } + + public static void SetWatermark(DependencyObject obj, string value) + { + obj.SetValue(WatermarkProperty, value); + } + #endregion + + #region CornerRadiusProperty Border圆角 + /// + /// Border圆角 + /// + public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.RegisterAttached( + "CornerRadius", typeof(CornerRadius), typeof(TextBoxAttach), new FrameworkPropertyMetadata(null)); + + public static CornerRadius GetCornerRadius(DependencyObject d) + { + return (CornerRadius)d.GetValue(CornerRadiusProperty); + } + + public static void SetCornerRadius(DependencyObject obj, CornerRadius value) + { + obj.SetValue(CornerRadiusProperty, value); + } + #endregion + + #region LabelProperty TextBox的头部Label + /// + /// TextBox的头部Label + /// + public static readonly DependencyProperty LabelProperty = DependencyProperty.RegisterAttached( + "Label", typeof(string), typeof(TextBoxAttach), new FrameworkPropertyMetadata(null)); + + [AttachedPropertyBrowsableForType(typeof(TextBox))] + public static string GetLabel(DependencyObject d) + { + return (string)d.GetValue(LabelProperty); + } + + public static void SetLabel(DependencyObject obj, string value) + { + obj.SetValue(LabelProperty, value); + } + #endregion + + #region LabelTemplateProperty TextBox的头部Label模板 /// - /// 文本框附加属性 + /// TextBox的头部Label模板 /// - public class TextBoxAttach : DependencyObject + public static readonly DependencyProperty LabelTemplateProperty = DependencyProperty.RegisterAttached( + "LabelTemplate", typeof(ControlTemplate), typeof(TextBoxAttach), new FrameworkPropertyMetadata(null)); + + [AttachedPropertyBrowsableForType(typeof(TextBox))] + public static ControlTemplate GetLabelTemplate(DependencyObject d) + { + return (ControlTemplate)d.GetValue(LabelTemplateProperty); + } + + public static void SetLabelTemplate(DependencyObject obj, ControlTemplate value) { - #region FocusBorderBrush 焦点边框色,输入控件 - - public static readonly DependencyProperty FocusBorderBrushProperty = DependencyProperty.RegisterAttached( - "FocusBorderBrush", typeof(Brush), typeof(TextBoxAttach), new FrameworkPropertyMetadata(null)); - public static void SetFocusBorderBrush(DependencyObject element, Brush value) - { - element.SetValue(FocusBorderBrushProperty, value); - } - public static Brush GetFocusBorderBrush(DependencyObject element) - { - return (Brush)element.GetValue(FocusBorderBrushProperty); - } - - #endregion - - #region MouseOverBorderBrush 鼠标进入边框色,输入控件 - - public static readonly DependencyProperty MouseOverBorderBrushProperty = - DependencyProperty.RegisterAttached("MouseOverBorderBrush", typeof(Brush), typeof(TextBoxAttach), - new FrameworkPropertyMetadata(Brushes.Transparent, - FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.Inherits)); - - /// - /// Sets the brush used to draw the mouse over brush. - /// - public static void SetMouseOverBorderBrush(DependencyObject obj, Brush value) - { - obj.SetValue(MouseOverBorderBrushProperty, value); - } - - /// - /// Gets the brush used to draw the mouse over brush. - /// - [AttachedPropertyBrowsableForType(typeof(TextBox))] - [AttachedPropertyBrowsableForType(typeof(CheckBox))] - [AttachedPropertyBrowsableForType(typeof(RadioButton))] - [AttachedPropertyBrowsableForType(typeof(DatePicker))] - [AttachedPropertyBrowsableForType(typeof(ComboBox))] - [AttachedPropertyBrowsableForType(typeof(RichTextBox))] - public static Brush GetMouseOverBorderBrush(DependencyObject obj) - { - return (Brush)obj.GetValue(MouseOverBorderBrushProperty); - } - - #endregion - - #region AttachContentProperty 附加组件模板 - /// - /// 附加组件模板 - /// - public static readonly DependencyProperty AttachContentProperty = DependencyProperty.RegisterAttached( - "AttachContent", typeof(ControlTemplate), typeof(TextBoxAttach), new FrameworkPropertyMetadata(null)); - - public static ControlTemplate GetAttachContent(DependencyObject d) - { - return (ControlTemplate)d.GetValue(AttachContentProperty); - } - - public static void SetAttachContent(DependencyObject obj, ControlTemplate value) - { - obj.SetValue(AttachContentProperty, value); - } - #endregion - - #region WatermarkProperty 水印 - /// - /// 水印 - /// - public static readonly DependencyProperty WatermarkProperty = DependencyProperty.RegisterAttached( - "Watermark", typeof(string), typeof(TextBoxAttach), new FrameworkPropertyMetadata("")); - - public static string GetWatermark(DependencyObject d) - { - return (string)d.GetValue(WatermarkProperty); - } - - public static void SetWatermark(DependencyObject obj, string value) - { - obj.SetValue(WatermarkProperty, value); - } - #endregion - - #region CornerRadiusProperty Border圆角 - /// - /// Border圆角 - /// - public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.RegisterAttached( - "CornerRadius", typeof(CornerRadius), typeof(TextBoxAttach), new FrameworkPropertyMetadata(null)); - - public static CornerRadius GetCornerRadius(DependencyObject d) - { - return (CornerRadius)d.GetValue(CornerRadiusProperty); - } - - public static void SetCornerRadius(DependencyObject obj, CornerRadius value) - { - obj.SetValue(CornerRadiusProperty, value); - } - #endregion - - #region LabelProperty TextBox的头部Label - /// - /// TextBox的头部Label - /// - public static readonly DependencyProperty LabelProperty = DependencyProperty.RegisterAttached( - "Label", typeof(string), typeof(TextBoxAttach), new FrameworkPropertyMetadata(null)); - - [AttachedPropertyBrowsableForType(typeof(TextBox))] - public static string GetLabel(DependencyObject d) - { - return (string)d.GetValue(LabelProperty); - } - - public static void SetLabel(DependencyObject obj, string value) - { - obj.SetValue(LabelProperty, value); - } - #endregion - - #region LabelTemplateProperty TextBox的头部Label模板 - /// - /// TextBox的头部Label模板 - /// - public static readonly DependencyProperty LabelTemplateProperty = DependencyProperty.RegisterAttached( - "LabelTemplate", typeof(ControlTemplate), typeof(TextBoxAttach), new FrameworkPropertyMetadata(null)); - - [AttachedPropertyBrowsableForType(typeof(TextBox))] - public static ControlTemplate GetLabelTemplate(DependencyObject d) - { - return (ControlTemplate)d.GetValue(LabelTemplateProperty); - } - - public static void SetLabelTemplate(DependencyObject obj, ControlTemplate value) - { - obj.SetValue(LabelTemplateProperty, value); - } - #endregion + obj.SetValue(LabelTemplateProperty, value); } + #endregion } diff --git a/Vampirewal.Core/WpfTheme/Attach/TouchEventCommands.cs b/Vampirewal.Core/WpfTheme/Attach/TouchEventCommands.cs new file mode 100644 index 0000000000000000000000000000000000000000..78305cd0d7f967809edd3205bcc5cff87205f7e6 --- /dev/null +++ b/Vampirewal.Core/WpfTheme/Attach/TouchEventCommands.cs @@ -0,0 +1,126 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: TouchEventCommands +// 创建者: 杨程 +// 创建日期: 2022/11/2 17:55:35 + +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.WpfTheme.Attach; + +public interface IEventAction +{ + string EventName { get; } +} + +/// +/// MVVM事件绑定,详细看CSDN博客 +/// 此处代码引用自 若汝棋茗 +/// CSDN博客:https://blog.csdn.net/qq_40374647/article/details/127651804?spm=1001.2014.3001.5501 +/// 哔哩哔哩视频:https://space.bilibili.com/94253567 +/// Gitee源代码仓库:https://gitee.com/RRQM_Home +/// Github源代码仓库:https://github.com/RRQM +/// API首页:https://www.yuque.com/rrqm/touchsocket/index +/// 交流QQ群:234762506 +/// +public static class TouchEventCommands +{ + // Using a DependencyProperty as the backing store for Events. This enables animation, styling, binding, etc... + public static readonly DependencyProperty EventsProperty = + DependencyProperty.RegisterAttached("Events", typeof(IEnumerable), typeof(TouchEventCommands), new PropertyMetadata(null, OnCommandChanged)); + + public static IEnumerable GetEvents(DependencyObject obj) + { + return (IEnumerable)obj.GetValue(EventsProperty); + } + + public static void SetEvents(DependencyObject obj, IEnumerable value) + { + obj.SetValue(EventsProperty, value); + } + + private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (e.NewValue is IEnumerable eventActions) + { + foreach (IEventAction eventAction in eventActions) + { + if (!string.IsNullOrEmpty(eventAction.EventName)) + { + EventInfo eventInfo = d.GetType().GetEvent(eventAction.EventName); + if (eventInfo == null) + { + throw new Exception($"没有找到名称为{eventAction.EventName}的事件"); + } + Delegate @delegate = Delegate.CreateDelegate(eventInfo.EventHandlerType, eventAction, "Event"); + //Delegate @delegate2 = eventAction.Begin(eventInfo.EventHandlerType, typeof(object), typeof(MouseButtonEventArgs)); + //Delegate @delegate = DelegateBuilder.CreateDelegate(eventAction, "Event", eventInfo.EventHandlerType, BindingFlags.NonPublic); + eventInfo.AddEventHandler(d, @delegate); + } + else + { + throw new Exception($"事件名不能为空"); + } + } + } + } +} + +public class EventAction : IEventAction +{ + private readonly Action action; + + private readonly string eventName; + + public EventAction(string eventName, Action action) + { + this.eventName = eventName; + this.action = action; + } + + public string EventName => this.eventName; + + private void Event(TSender sender, TE e) + { + this.action?.Invoke(sender, e); + } +} + +public class EventAction : IEventAction +{ + private readonly Action action; + + private readonly Action action2; + + private readonly string eventName; + + public EventAction(string eventName, Action action) + { + this.eventName = eventName; + this.action = action; + } + + public EventAction(string eventName, Action action) + { + this.eventName = eventName; + this.action2 = action; + } + + public string EventName => this.eventName; + + private void Event(object sender, TE e) + { + this.action?.Invoke(sender); + this.action2?.Invoke(e); + } +} diff --git a/Vampirewal.Core/WpfTheme/Behavior/DataGridBehavior.cs b/Vampirewal.Core/WpfTheme/Behavior/DataGridBehavior.cs new file mode 100644 index 0000000000000000000000000000000000000000..52298c77166fff3367935c4904b167b186bb424c --- /dev/null +++ b/Vampirewal.Core/WpfTheme/Behavior/DataGridBehavior.cs @@ -0,0 +1,185 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:DataGridBehavior +// 创 建 者:杨程 +// 创建时间:2021/12/2 15:06:45 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + + + + + + +namespace Vampirewal.Core.WpfTheme.Behaviors; + +public class DataGridBehavior +{ + public DataGridBehavior() + { + //构造函数 + } + + #region 属性 + + #endregion + + #region 公共方法 + + #endregion + + #region 私有方法 + + #endregion + + #region 命令 + + #endregion +} + +/// +/// DataGrid添加GroupBy功能 +/// +public class DataGridGroupByBehavior : Behavior +{ + /// + /// 绑定分组名称 + /// + public string SetGroupByProrName { get; set; } + + protected override void OnAttached() + { + if (string.IsNullOrEmpty(SetGroupByProrName)) + { + return; + } + + base.OnAttached(); + base.AssociatedObject.LoadingRow += AssociatedObject_LoadingRow; + } + + private void AssociatedObject_LoadingRow(object sender, DataGridRowEventArgs e) + { + base.AssociatedObject.LoadingRow -= AssociatedObject_LoadingRow; + + var res = new ResourceDictionary() { Source = new Uri("pack://application:,,,/Vampirewal.Core;component/WpfTheme/CoreTheme.xaml", UriKind.RelativeOrAbsolute) }; + + DataGrid dataGrid = sender as DataGrid; + + foreach (var item in dataGrid.ItemsSource) + { + dataGrid.GroupStyle.Add(new GroupStyle() + { + ContainerStyle = res["GroupHeaderStyle"] as Style + }); + + } + + ICollectionView vw = CollectionViewSource.GetDefaultView(dataGrid.ItemsSource); + + var cur = SetGroupByProrName.Split("-").ToList(); + + foreach (var item in cur) + { + vw.GroupDescriptions.Add(new PropertyGroupDescription(item)); + } + + } + + +} + +/// +/// DataGrid添加分页功能 +/// +public class DataGridPagination : Behavior +{ + protected override void OnAttached() + { + base.OnAttached(); + //base.AssociatedObject.LoadingRow += AssociatedObject_LoadingRow; + + + + base.AssociatedObject.Loaded += AssociatedObject_Loaded; + base.AssociatedObject.LoadingRow += AssociatedObject_LoadingRow; + } + + private void AssociatedObject_LoadingRow(object sender, DataGridRowEventArgs e) + { + base.AssociatedObject.LoadingRow -= AssociatedObject_LoadingRow; + + vp.SetValue(VPagination.IsShowPageDataCountSelectorProperty, true); + vp.SetValue(VPagination.IsShowPageInfoProperty, true); + vp.SetValue(VPagination.TotalDataCountProperty, base.AssociatedObject.Items.Count); + vp.SetValue(VPagination.MaxShownPageCountProperty, 8); + //vp.SetValue(VPagination.TotalDataCountProperty,100); + vp.SetValue(VPagination.SelectedPageBackgroundProperty, Brushes.White); + //vp.SetValue(VPagination.PageDataCountProperty, 1); + } + + private ResourceDictionary res + { + get + { + return new ResourceDictionary() { Source = new Uri("pack://application:,,,/Vampirewal.Core;component/WpfTheme/CoreTheme.xaml", UriKind.RelativeOrAbsolute) }; + } + } + + VPagination vp = new VPagination(); + private void AssociatedObject_Loaded(object sender, RoutedEventArgs e) + { + base.AssociatedObject.Loaded -= AssociatedObject_Loaded; + + if (base.AssociatedObject.Parent != null) + { + var parent = base.AssociatedObject.Parent as Panel; + parent.Children.Remove(base.AssociatedObject); + + + Grid grid = new Grid(); + grid.RowDefinitions.Add(new RowDefinition() { Height=new GridLength(100, GridUnitType.Auto)}); + grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(50) }); + Grid.SetRow(base.AssociatedObject, 0); + grid.SetValue(Grid.BackgroundProperty, Brushes.Blue); + grid.Children.Add(base.AssociatedObject); + + //Border border = new Border(); + //border.Background = new SolidColorBrush(Colors.Red); + //border.Height = 50; + //border.Margin = new Thickness(5); + //Grid.SetRow(border, 1); + + //grid.Children.Add(border); + + + vp.Style = res["VPaginationStyle"] as Style; + vp.Height = 50; + vp.HorizontalAlignment = HorizontalAlignment.Stretch; + vp.Margin = new Thickness(5); + Grid.SetRow(vp, 1); + + + + + grid.Children.Add(vp); + + parent.Children.Add(grid); + + FrameworkElementFactory factory = new FrameworkElementFactory(typeof(Grid)); + + + } + } + + protected override void OnDetaching() + { + base.OnDetaching(); + + } +} diff --git a/Vampirewal.Core/WpfTheme/Behavior/NumTextBoxBehavior.cs b/Vampirewal.Core/WpfTheme/Behavior/NumTextBoxBehavior.cs index a972be22c6eed21eb3c3147247feacefc116cd9e..05310e8e55e6260b77f4a8a3f7a103108d74bdad 100644 --- a/Vampirewal.Core/WpfTheme/Behavior/NumTextBoxBehavior.cs +++ b/Vampirewal.Core/WpfTheme/Behavior/NumTextBoxBehavior.cs @@ -11,16 +11,8 @@ //----------------------------------------------------------------*/ #endregion -using Microsoft.Xaml.Behaviors; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Controls; -using System.Windows; -using System.Windows.Controls.Primitives; -using System.Windows.Input; + + namespace Vampirewal.Core.WpfTheme.Behaviors { diff --git a/Vampirewal.Core/WpfTheme/Converter/Bool2VisibilityConverter.cs b/Vampirewal.Core/WpfTheme/Converter/Bool2VisibilityConverter.cs index 1075a2c137ce19bf4eb6b92d54963c64999774e6..c25edde321ef3c68c78818b6893fd1d8b98d9305 100644 --- a/Vampirewal.Core/WpfTheme/Converter/Bool2VisibilityConverter.cs +++ b/Vampirewal.Core/WpfTheme/Converter/Bool2VisibilityConverter.cs @@ -11,42 +11,48 @@ //----------------------------------------------------------------*/ #endregion -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Data; - -namespace Vampirewal.Core.WpfTheme.Converter + + + +namespace Vampirewal.Core.WpfTheme.Converter; + +/// +/// Bool转Visibility转化类 +/// +public class Bool2VisibilityConverter : IValueConverter { - /// - /// Bool转Visibility转化类 - /// - public class Bool2VisibilityConverter : IValueConverter + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + if (value != null) { - if (value != null) + bool current = (bool)value; + if (current) { - bool current = (bool)value; - if (current) - { - return Visibility.Visible; - } - else - { - return Visibility.Collapsed; - } + return Visibility.Visible; + } + else + { + return Visibility.Collapsed; } - return Visibility.Collapsed; } + return Visibility.Collapsed; + } - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - throw new NotImplementedException(); - } + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } +} + +public class BoolToHideConverter : IValueConverter +{ + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return value.Equals(true) ? Visibility.Visible : Visibility.Hidden; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); } } diff --git a/Vampirewal.Core/WpfTheme/Converter/BoolReverseConverter.cs b/Vampirewal.Core/WpfTheme/Converter/BoolReverseConverter.cs new file mode 100644 index 0000000000000000000000000000000000000000..fb6ce5702b242ad0fcd6d18dceb713305716373f --- /dev/null +++ b/Vampirewal.Core/WpfTheme/Converter/BoolReverseConverter.cs @@ -0,0 +1,54 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:BoolReverseConverter +// 创 建 人:YangCheng +// 创建时间:2022/6/30 17:22:45 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.WpfTheme.Converter; + +/// +/// bool反转转换器,未实现ConvertBack +/// +public class BoolReverseConverter : IValueConverter +{ + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (parameter == null || string.IsNullOrWhiteSpace(parameter.ToString())) + { + if (value.Equals(true)) + return false; + else if (value.Equals(false)) + return true; + else + return false; + } + else if (parameter == null || parameter.ToString().ToUpper() == "VISIBILITY") + { + if (value.Equals(true)) + return Visibility.Collapsed; + else if (value.Equals(false)) + return Visibility.Visible; + else + return Visibility.Collapsed; + } + else + { + return value; + } + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } +} diff --git a/Vampirewal.Core/WpfTheme/Converter/DataContextConverter.cs b/Vampirewal.Core/WpfTheme/Converter/DataContextConverter.cs new file mode 100644 index 0000000000000000000000000000000000000000..fe2a7677c1f6621c5ef43795e513bdcbf56fc0cf --- /dev/null +++ b/Vampirewal.Core/WpfTheme/Converter/DataContextConverter.cs @@ -0,0 +1,38 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:DataContextConverter +// 创 建 人:YangCheng +// 创建时间:2022/5/23 15:23:05 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.WpfTheme.Converter; + +/// +/// +/// +public class DataContextConverter : IValueConverter +{ + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value == null) + return default; + + string VmName = parameter.ToString(); + + return ""; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } +} diff --git a/Vampirewal.Core/WpfTheme/Converter/LevelToIndentConverter.cs b/Vampirewal.Core/WpfTheme/Converter/LevelToIndentConverter.cs new file mode 100644 index 0000000000000000000000000000000000000000..2d73b813b22c49b39e4ec1478fe9c7a1f59d0946 --- /dev/null +++ b/Vampirewal.Core/WpfTheme/Converter/LevelToIndentConverter.cs @@ -0,0 +1,52 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:LevelToIndentConverter +// 创 建 人:YangCheng +// 创建时间:2022/8/10 19:02:45 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.WpfTheme.Converter; + +/// +/// +/// +public class LevelToIndentConverter : IValueConverter +{ + public object Convert(object o, Type type, object parameter, CultureInfo culture) + { + return new Thickness((int)o * c_IndentSize, 0, 0, 0); + } + + + public object ConvertBack(object o, Type type, object parameter, CultureInfo culture) + { + throw new NotSupportedException(); + } + + private const double c_IndentSize = 16.0; +} + +public class CanExpandConverter : IValueConverter +{ + public object Convert(object o, Type type, object parameter, CultureInfo culture) + { + if ((bool)o) + return Visibility.Visible; + else + return Visibility.Hidden; + } + + public object ConvertBack(object o, Type type, object parameter, CultureInfo culture) + { + throw new NotSupportedException(); + } +} diff --git a/Vampirewal.Core/WpfTheme/CoreTheme.xaml b/Vampirewal.Core/WpfTheme/CoreTheme.xaml index 386c61b68376ab8d2e27dfa85e321012484baf3c..aae5c0744b7ac30548927bca35bdc6f8b7d3a811 100644 --- a/Vampirewal.Core/WpfTheme/CoreTheme.xaml +++ b/Vampirewal.Core/WpfTheme/CoreTheme.xaml @@ -7,6 +7,14 @@ + + + + + + + + @@ -42,7 +50,7 @@ - + @@ -75,6 +83,17 @@ + + + + + + + + + + + diff --git a/Vampirewal.Core/WpfTheme/CustomControl/CalendarControl/Calendar.xaml b/Vampirewal.Core/WpfTheme/CustomControl/CalendarControl/Calendar.xaml new file mode 100644 index 0000000000000000000000000000000000000000..d6f6febbbde1c2ea77f7480d9d81677baceade4e --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/CalendarControl/Calendar.xaml @@ -0,0 +1,503 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Vampirewal.Core/WpfTheme/CustomControl/CalendarControl/Calendar.xaml.cs b/Vampirewal.Core/WpfTheme/CustomControl/CalendarControl/Calendar.xaml.cs new file mode 100644 index 0000000000000000000000000000000000000000..6743261289ed95df2f95ce03776776bfaa791a01 --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/CalendarControl/Calendar.xaml.cs @@ -0,0 +1,32 @@ + + +namespace Vampirewal.Core.WpfTheme.CustomControl; + +/// +/// Calendar.xaml 的交互逻辑 +/// +public partial class Calendar : UserControl +{ + public Calendar() + { + InitializeComponent(); + } + + #region 依赖属性 + + + #endregion + + public DateTime CurrentDateTime { get; set; } = DateTime.Today; + + + private void UserControl_Loaded(object sender, RoutedEventArgs e) + { + YearMonthTitle.Text = CurrentDateTime.ToString("yyyy年MM月"); + } + + private void ShangYiNianBtn_Click(object sender, RoutedEventArgs e) + { + CurrentDateTime = CurrentDateTime.AddYears(-1); + } +} diff --git a/Vampirewal.Core/WpfTheme/CustomControl/DataGrid/DataGridStyles.xaml b/Vampirewal.Core/WpfTheme/CustomControl/DataGrid/DataGridStyles.xaml new file mode 100644 index 0000000000000000000000000000000000000000..0becd00c2ec88e0797328762df69855635f67c38 --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/DataGrid/DataGridStyles.xaml @@ -0,0 +1,22 @@ + + + + + + + + \ No newline at end of file diff --git a/Vampirewal.Core/WpfTheme/CustomControl/EditPage/EditContainer.cs b/Vampirewal.Core/WpfTheme/CustomControl/EditPage/EditContainer.cs new file mode 100644 index 0000000000000000000000000000000000000000..c865620fdd005e407c7c738791297954a4125e96 --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/EditPage/EditContainer.cs @@ -0,0 +1,351 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:EditContainer +// 创 建 人:YangCheng +// 创建时间:2022/6/30 16:27:07 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + + + +namespace Vampirewal.Core.WpfTheme.CustomControl; + +/// +/// +/// +public class EditContainer:ListBox +{ + private class LocationInfo + { + public double SettingsItemLocation { get; set; } + + public double SettingsContainerLocation { get; set; } + + public RadioButton SettingsRb { get; set; } + } + + #region Properties + + /// + /// 属性项目标注,KeyValuePair:key对应容器坐标,value选择项目坐标 + /// + private Dictionary _dicSettingsItemContainerPoint; + /// + /// 设置选项定位名 + /// + private string _locationName; + private Border _cursor; + private ItemsPresenter _itemP; + private bool sbRunning; + /// + /// 内容项Y轴的偏移量 + /// + private double _tmpYOffset; + /// + /// 最后一项高度偏移高度 + /// + private double _lastItemHeightOffset; + + #region 动画元素 + private EasingDoubleKeyFrame _settingsLocationEasing; + private Storyboard _settingsLocation; + private Storyboard _mouseWheelMove; + private EasingDoubleKeyFrame _mouseWheelMoveEasing; + private Storyboard _location; + private EasingDoubleKeyFrame _locationEasing; + #endregion + + #endregion + + public EditContainer() + { + //构造函数 + Loaded += EditContainer_Loaded; + } + + private void EditContainer_Loaded(object sender, System.Windows.RoutedEventArgs e) + { + Loaded -= EditContainer_Loaded; + _dicSettingsItemContainerPoint = new Dictionary(); + _mouseWheelMove = CreateSettingsItemStoryboard(0); + _location = CreateSettingsItemStoryboard(0); + _settingsLocation = CreateStoryboard(0); + + if (_mouseWheelMove.Children.First() is DoubleAnimationUsingKeyFrames key && + key.KeyFrames[0] is EasingDoubleKeyFrame eas && + _location.Children.First() is DoubleAnimationUsingKeyFrames lKey && + lKey.KeyFrames[0] is EasingDoubleKeyFrame lEas && + _settingsLocation.Children.First() is DoubleAnimationUsingKeyFrames sKey && + sKey.KeyFrames[0] is EasingDoubleKeyFrame sEas && + Template.FindName("itemsP", this) is ItemsPresenter ip && + Template.FindName("br_Cursor", this) is Border br && + Template.FindName("editItemsContainer", this) is StackPanel sp && + Template.Resources["RbTabStyle"] is Style rbStyle && + Template.FindName("sv", this) is Grid sv) + { + _itemP = ip; + _itemP.SizeChanged += Can_SizeChanged; + _cursor = br; + eas.KeyTime = TimeSpan.Parse("0:0:0"); + _mouseWheelMoveEasing = eas; + _locationEasing = lEas; + _settingsLocationEasing = sEas; + _location.Completed += _sb2_Completed; + + for (int i = 0; i < ItemContainerGenerator.Items.Count; i++) + { + var editItem = ItemContainerGenerator.ContainerFromIndex(i) as EditItem; + editItem.Width = sv.ActualWidth; + var rbTmp = CreateTitle(rbStyle, editItem); + sp.Children.Add(rbTmp); + } + sv.AddHandler(Grid.PreviewMouseWheelEvent, new MouseWheelEventHandler(Sv_PreviewMouseWheel)); + sv.SizeChanged += Sv_SizeChanged; + //if (!string.IsNullOrEmpty(_locationName)) + // RunStoryboard(_locationName); + } + } + + private void Can_SizeChanged(object sender, SizeChangedEventArgs e) + { + if (Template.FindName("editItemsContainer", this) is StackPanel sp && + Template.Resources["RbTabStyle"] is Style rbStyle && + Template.FindName("sv", this) is Grid sv) + { + sp.Children.Clear(); + _dicSettingsItemContainerPoint.Clear(); + for (int i = 0; i < ItemContainerGenerator.Items.Count; i++) + { + var editItem = ItemContainerGenerator.ContainerFromIndex(i) as EditItem; + editItem.Width = sv.ActualWidth; + var rbTmp = CreateTitle(rbStyle, editItem); + sp.Children.Add(rbTmp); + sp.UpdateLayout(); + _dicSettingsItemContainerPoint.Add(rbTmp.Tag.ToString(), new LocationInfo() + { + SettingsContainerLocation = 0 - editItem.TranslatePoint(new Point(0, 0), sp).Y, + SettingsItemLocation = rbTmp.TranslatePoint(new Point(0, 0), sp).Y, + SettingsRb = rbTmp + }); + _lastItemHeightOffset = editItem.ActualHeight - this.ActualHeight; + } + } + } + + private void Sv_SizeChanged(object sender, SizeChangedEventArgs e) + { + for (int i = 0; i < ItemContainerGenerator.Items.Count; i++) + { + var editItem = ItemContainerGenerator.ContainerFromIndex(i) as EditItem; + editItem.Width = e.NewSize.Width; + } + } + + private void Sv_PreviewMouseWheel(object sender, MouseWheelEventArgs e) + { + if (!sbRunning) + { + if (e.Delta > 0 && _tmpYOffset <= 0) + { + _tmpYOffset = (_tmpYOffset + 48) > 0 ? 0 : _tmpYOffset + 48; + } + else if (e.Delta < 0 && _tmpYOffset >= _dicSettingsItemContainerPoint.Last().Value.SettingsContainerLocation) + { + _tmpYOffset = (_tmpYOffset - 48) <= _dicSettingsItemContainerPoint.Last().Value.SettingsContainerLocation ? _dicSettingsItemContainerPoint.Last().Value.SettingsContainerLocation : _tmpYOffset - 48; + } + if (_tmpYOffset <= 0) + { + var top = _dicSettingsItemContainerPoint.Last(t => t.Value.SettingsContainerLocation >= _tmpYOffset - 96); + if (_settingsLocationEasing.Value != top.Value.SettingsItemLocation) + { + _settingsLocationEasing.Value = top.Value.SettingsItemLocation; + top.Value.SettingsRb.IsChecked = true; + _settingsLocation.Begin(_cursor); + } + _mouseWheelMoveEasing.Value = _tmpYOffset; + _mouseWheelMove.Begin(_itemP); + } + } + e.Handled = true; + } + private void RunStoryboard(string settingsItemName) + { + _settingsLocationEasing.Value = _dicSettingsItemContainerPoint[settingsItemName].SettingsItemLocation; + _settingsLocation.Begin(_cursor); + + _tmpYOffset = _dicSettingsItemContainerPoint[settingsItemName].SettingsContainerLocation; + _locationEasing.Value = _tmpYOffset; + _dicSettingsItemContainerPoint[settingsItemName].SettingsRb.IsChecked = true; + sbRunning = true; + _location.Begin(_itemP); + } + + private void _sb2_Completed(object sender, EventArgs e) + { + sbRunning = false; + } + + + #region Tools + + private RadioButton CreateTitle(Style rbStyle, EditItem item) + { + RadioButton rb = new RadioButton(); + rb.Tag = Guid.NewGuid().ToString(); + Binding bind = new Binding("Visibility"); + bind.Source = item; + rb.SetBinding(RadioButton.VisibilityProperty, bind); + rb.GroupName = "EditPageGroup"; + rb.Style = rbStyle; + rb.Content = item.HeaderText; + rb.Click += StackPanel_Checked; + return rb; + } + + private void StackPanel_Checked(object sender, RoutedEventArgs e) + { + if (e.OriginalSource is RadioButton btn) + { + RunStoryboard(btn.Tag.ToString()); + } + } + + #region 动画创建 + private Storyboard CreateStoryboard(double y) + { + Storyboard sb = new Storyboard(); + DoubleAnimationUsingKeyFrames keyFrames = new DoubleAnimationUsingKeyFrames(); + EasingDoubleKeyFrame doubleKeyFrame = new EasingDoubleKeyFrame(); + doubleKeyFrame.KeyTime = TimeSpan.Parse("0:0:0.7"); + doubleKeyFrame.Value = y; + BackEase effect = new BackEase(); + effect.EasingMode = EasingMode.EaseOut; + effect.Amplitude = 0.4; + doubleKeyFrame.EasingFunction = effect; + keyFrames.KeyFrames.Add(doubleKeyFrame); + Storyboard.SetTargetProperty(keyFrames, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)")); + Storyboard.SetTarget(keyFrames, _cursor); + sb.Children.Add(keyFrames); + return sb; + } + private Storyboard CreateSettingsItemStoryboard(double y) + { + Storyboard sb = new Storyboard(); + DoubleAnimationUsingKeyFrames keyFrames = new DoubleAnimationUsingKeyFrames(); + EasingDoubleKeyFrame doubleKeyFrame = new EasingDoubleKeyFrame(); + doubleKeyFrame.KeyTime = TimeSpan.Parse("0:0:0.5"); + doubleKeyFrame.Value = y; + BackEase effect = new BackEase(); + effect.EasingMode = EasingMode.EaseInOut; + effect.Amplitude = 0.2; + doubleKeyFrame.EasingFunction = effect; + keyFrames.KeyFrames.Add(doubleKeyFrame); + Storyboard.SetTargetProperty(keyFrames, new PropertyPath("(UIElement.RenderTransform).(TranslateTransform.Y)")); + Storyboard.SetTarget(keyFrames, _itemP); + sb.Children.Add(keyFrames); + return sb; + } + #endregion + + #endregion + + static EditContainer() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(EditContainer), new FrameworkPropertyMetadata(typeof(EditContainer))); + } + + protected override bool IsItemItsOwnContainerOverride(object item) + { + return item is EditItem; + } + + protected override DependencyObject GetContainerForItemOverride() + { + return new EditItem(); + } + + + #region 依赖属性 + + #region 左侧 + + /// + /// 左侧背景色 + /// + public Brush LeftBackground + { + get { return (Brush)GetValue(LeftBackgroundProperty); } + set { SetValue(LeftBackgroundProperty, value); } + } + + // Using a DependencyProperty as the backing store for LeftBackground. This enables animation, styling, binding, etc... + public static readonly DependencyProperty LeftBackgroundProperty = + DependencyProperty.Register("LeftBackground", typeof(Brush), typeof(EditContainer), new PropertyMetadata(Brushes.WhiteSmoke)); + + + + /// + /// 左侧前景色 + /// + public Brush LeftForeground + { + get { return (Brush)GetValue(LeftForegroundProperty); } + set { SetValue(LeftForegroundProperty, value); } + } + + // Using a DependencyProperty as the backing store for LeftForeground. This enables animation, styling, binding, etc... + public static readonly DependencyProperty LeftForegroundProperty = + DependencyProperty.Register("LeftForeground", typeof(Brush), typeof(EditContainer), new PropertyMetadata(Brushes.Black)); + + + + + public Brush MouseOverColor + { + get { return (Brush)GetValue(MouseOverColorProperty); } + set { SetValue(MouseOverColorProperty, value); } + } + + // Using a DependencyProperty as the backing store for MouseOverColor. This enables animation, styling, binding, etc... + public static readonly DependencyProperty MouseOverColorProperty = + DependencyProperty.Register("MouseOverColor", typeof(Brush), typeof(EditContainer), new PropertyMetadata(Brushes.Chocolate)); + + + + + public Brush CheckedColor + { + get { return (Brush)GetValue(CheckedColorProperty); } + set { SetValue(CheckedColorProperty, value); } + } + + // Using a DependencyProperty as the backing store for CheckedColor. This enables animation, styling, binding, etc... + public static readonly DependencyProperty CheckedColorProperty = + DependencyProperty.Register("CheckedColor", typeof(Brush), typeof(EditContainer), new PropertyMetadata(Brushes.Chocolate)); + + + #endregion + + #region 中间 + + + public Brush ContainerBackground + { + get { return (Brush)GetValue(ContainerBackgroundProperty); } + set { SetValue(ContainerBackgroundProperty, value); } + } + + // Using a DependencyProperty as the backing store for ContainerBackground. This enables animation, styling, binding, etc... + public static readonly DependencyProperty ContainerBackgroundProperty = + DependencyProperty.Register("ContainerBackground", typeof(Brush), typeof(EditContainer), new PropertyMetadata(Brushes.White)); + + + #endregion + + #endregion +} diff --git a/Vampirewal.Core/WpfTheme/CustomControl/EditPage/EditContaninerStyle.xaml b/Vampirewal.Core/WpfTheme/CustomControl/EditPage/EditContaninerStyle.xaml new file mode 100644 index 0000000000000000000000000000000000000000..63c2eb9e211ac0d3843433fce865c820583942f0 --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/EditPage/EditContaninerStyle.xaml @@ -0,0 +1,233 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Vampirewal.Core/WpfTheme/CustomControl/EditPage/EditItem.cs b/Vampirewal.Core/WpfTheme/CustomControl/EditPage/EditItem.cs new file mode 100644 index 0000000000000000000000000000000000000000..545fb16d910491ac183e795b43f51bcca7991ab9 --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/EditPage/EditItem.cs @@ -0,0 +1,74 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:EditItem +// 创 建 人:YangCheng +// 创建时间:2022/6/30 16:34:59 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.WpfTheme.CustomControl; + +/// +/// +/// +public class EditItem : ListBoxItem +{ + public string HeaderText { get; set; } + + static EditItem() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(EditItem), new FrameworkPropertyMetadata(typeof(EditItem))); + } + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + if (Template.FindName("tb_Header", this) is TextBlock tb) + { + tb.Text = HeaderText; + } + } + + //屏蔽选中跳转效果 + protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) + { + e.Handled = true; + } + + #region 依赖属性 + + + public Brush IconColor + { + get { return (Brush)GetValue(IconColorProperty); } + set { SetValue(IconColorProperty, value); } + } + + // Using a DependencyProperty as the backing store for IconColor. This enables animation, styling, binding, etc... + public static readonly DependencyProperty IconColorProperty = + DependencyProperty.Register("IconColor", typeof(Brush), typeof(EditItem), new PropertyMetadata(Brushes.CadetBlue)); + + + + + public Brush TitleColor + { + get { return (Brush)GetValue(TitleColorProperty); } + set { SetValue(TitleColorProperty, value); } + } + + // Using a DependencyProperty as the backing store for TitleColor. This enables animation, styling, binding, etc... + public static readonly DependencyProperty TitleColorProperty = + DependencyProperty.Register("TitleColor", typeof(Brush), typeof(EditItem), new PropertyMetadata(Brushes.DarkBlue)); + + + #endregion +} diff --git a/Vampirewal.Core/WpfTheme/CustomControl/FlowDesignControl/FlowDesign.cs b/Vampirewal.Core/WpfTheme/CustomControl/FlowDesignControl/FlowDesign.cs new file mode 100644 index 0000000000000000000000000000000000000000..d687ba60ccc455f341f1baff0a3f5fb8687c58c1 --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/FlowDesignControl/FlowDesign.cs @@ -0,0 +1,201 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: FlowDesign +// 创建者: 杨程 +// 创建日期: 2022/12/18 15:07:08 + +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.WpfTheme.CustomControl; + +/// +/// 流程设计 +/// +public partial class FlowDesign : UserControl +{ + static FlowDesign() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(FlowDesign), new FrameworkPropertyMetadata(typeof(FlowDesign))); + } + + + /// + /// + /// + public FlowDesign() + { + //构造函数 + } + + private Canvas canvas { get; set; } + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + var StartNode = this.Template.FindName("StartNode", this) as Border; + var ToDoNode = this.Template.FindName("ToDoNode", this) as Border; + var EndNode = this.Template.FindName("EndNode", this) as Border; + canvas = this.Template.FindName("canvas", this) as Canvas; + + StartNode.MouseLeftButtonDown += StartNode_MouseLeftButtonDown; + ToDoNode.MouseLeftButtonDown += StartNode_MouseLeftButtonDown; + EndNode.MouseLeftButtonDown += StartNode_MouseLeftButtonDown; + + canvas.Drop += Canvas_Drop; + + canvas.SizeChanged += Canvas_SizeChanged; + } + + private void Canvas_SizeChanged(object sender, SizeChangedEventArgs e) + { + Canvas canvas = (Canvas)sender; + //canvas.Width = e.; + //canvas.Height = canvas.ActualHeight; + + } + + private void Canvas_Drop(object sender, DragEventArgs e) + { + Canvas canvas = (Canvas)sender; + + var data = e.Data.GetData(typeof(string)); + + FlowNode node = new FlowNode(); + node.Cursor = System.Windows.Input.Cursors.Hand; + if (data.ToString() == "开始") + { + node.NodeType = 1; + } + else if (data.ToString() == "执行中") + { + node.NodeType = 2; + } + else if (data.ToString() == "结束") + { + node.NodeType = 99; + } + + node.NodeName = data.ToString(); + + node.DragDelta += Node_DragDelta; + node.DragStarted += Node_DragStarted; + + canvas.Children.Add(node); + + var point = e.GetPosition(canvas); + + Canvas.SetLeft(node, point.X); + Canvas.SetTop(node, point.Y); + + + } + + private void Node_DragStarted(object sender, DragStartedEventArgs e) + { + + } + + private void Node_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e) + { + FlowNode myThumb = (FlowNode)sender; + double nTop = Canvas.GetTop(myThumb) + e.VerticalChange; + double nLeft = Canvas.GetLeft(myThumb) + e.HorizontalChange; + + if (nTop < 0) + { + nTop = 0; + } + else if ((nTop + myThumb.Height) > canvas.Height) + { + nTop = canvas.Height - myThumb.Height; + } + + if (nLeft < 0) + { + nLeft = 0; + } + else if ((nLeft + myThumb.Width) > canvas.Height) + { + nLeft = canvas.Height - myThumb.Width; + } + + //myThumb. + + + Canvas.SetTop(myThumb, nTop); + Canvas.SetLeft(myThumb, nLeft); + myThumb.ToolTip = $"X:{nTop}\r\nY:{nLeft}"; + } + private List NodeName = new List(); + + private void StartNode_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e) + { + Border border = (Border)sender; + + var nodename = border.Tag.ToString(); + + if (NodeName.Any(a => a.Equals(nodename)) && (nodename == "开始" || nodename == "结束")) + { + return; + } + + NodeName.Add(nodename); + + DragDrop.DoDragDrop(border, border.Tag, DragDropEffects.Copy); + } + + #region [ 依赖属性 ] + + public IEnumerable FlowNodes + { + get { return (IEnumerable)GetValue(FlowNodesProperty); } + set { SetValue(FlowNodesProperty, value); } + } + + // Using a DependencyProperty as the backing store for FlowNodes. This enables animation, styling, binding, etc... + public static readonly DependencyProperty FlowNodesProperty = + DependencyProperty.Register("FlowNodes", typeof(IEnumerable), typeof(FlowDesign), new PropertyMetadata(null)); + + + + + public IEnumerable FlowUnits + { + get { return (IEnumerable)GetValue(FlowUnitsProperty); } + set { SetValue(FlowUnitsProperty, value); } + } + + // Using a DependencyProperty as the backing store for FlowUnits. This enables animation, styling, binding, etc... + public static readonly DependencyProperty FlowUnitsProperty = + DependencyProperty.Register("FlowUnits", typeof(IEnumerable), typeof(FlowDesign), new PropertyMetadata(null)); + + + #endregion + + #region [ 属性 ] + + #endregion + + #region [ 公共方法 ] + + #endregion + + #region [ 私有方法 ] + + #endregion + + #region [ Command命令 ] + + #endregion +} diff --git a/Vampirewal.Core/WpfTheme/CustomControl/FlowDesignControl/FlowDesignStyle.xaml b/Vampirewal.Core/WpfTheme/CustomControl/FlowDesignControl/FlowDesignStyle.xaml new file mode 100644 index 0000000000000000000000000000000000000000..580400ea95438c9e8489bfec052fc4176792564c --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/FlowDesignControl/FlowDesignStyle.xaml @@ -0,0 +1,154 @@ + + + + + + + + \ No newline at end of file diff --git a/Vampirewal.Core/WpfTheme/CustomControl/FlowDesignControl/FlowNode.cs b/Vampirewal.Core/WpfTheme/CustomControl/FlowDesignControl/FlowNode.cs new file mode 100644 index 0000000000000000000000000000000000000000..ef9eee53fd23e0ccd09846a6a0b0f603c54395b0 --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/FlowDesignControl/FlowNode.cs @@ -0,0 +1,90 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: FlowNode +// 创建者: 杨程 +// 创建日期: 2022/12/18 15:17:42 + +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.WpfTheme.CustomControl; + +/// +/// 流程节点 +/// +public partial class FlowNode:Thumb +{ + static FlowNode() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(FlowNode), new FrameworkPropertyMetadata(typeof(FlowNode))); + } + + + /// + /// + /// + public FlowNode() + { + //构造函数 + } + + #region [ 依赖属性 ] + + #region 节点类型 + + public int NodeType + { + get { return (int)GetValue(NodeTypeProperty); } + set { SetValue(NodeTypeProperty, value); } + } + + // Using a DependencyProperty as the backing store for NodeType. This enables animation, styling, binding, etc... + public static readonly DependencyProperty NodeTypeProperty = + DependencyProperty.Register("NodeType", typeof(int), typeof(FlowNode), new PropertyMetadata(0)); + + #endregion + + #region 显示文字 + + + public string NodeName + { + get { return (string)GetValue(NodeNameProperty); } + set { SetValue(NodeNameProperty, value); } + } + + // Using a DependencyProperty as the backing store for NodeName. This enables animation, styling, binding, etc... + public static readonly DependencyProperty NodeNameProperty = + DependencyProperty.Register("NodeName", typeof(string), typeof(FlowNode), new PropertyMetadata("")); + + + + #endregion + + #endregion + + #region [ 属性 ] + + #endregion + + #region [ 公共方法 ] + + #endregion + + #region [ 私有方法 ] + + #endregion + + #region [ Command命令 ] + + #endregion +} diff --git a/Vampirewal.Core/WpfTheme/CustomControl/FlowDesignControl/FlowNodePosition.cs b/Vampirewal.Core/WpfTheme/CustomControl/FlowDesignControl/FlowNodePosition.cs new file mode 100644 index 0000000000000000000000000000000000000000..b0e7f151a78bd3d6b8cd373b0a947e192c9fb24f --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/FlowDesignControl/FlowNodePosition.cs @@ -0,0 +1,27 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: FlowNodePosition +// 创建者: 杨程 +// 创建日期: 2022/12/20 14:31:10 + +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.WpfTheme.CustomControl.FlowDesignControl; + +/// +/// 流程节点位置信息 +/// +public partial class FlowNodePosition +{ + +} diff --git a/Vampirewal.Core/WpfTheme/CustomControl/LoadingContainer/LoadingContainer.cs b/Vampirewal.Core/WpfTheme/CustomControl/LoadingContainer/LoadingContainer.cs new file mode 100644 index 0000000000000000000000000000000000000000..0ec924d6d96e972f06315462920f88e93251ead8 --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/LoadingContainer/LoadingContainer.cs @@ -0,0 +1,105 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:LoadingContainer +// 创 建 人:YangCheng +// 创建时间:2022/6/30 17:20:46 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.WpfTheme.CustomControl; + +/// +/// +/// +public class LoadingContainer : ContentControl +{ + + + public LoadingContainer() + { + //构造函数 + } + + private Storyboard _sbOnloading; + private Border _maskContainer; + + static LoadingContainer() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(LoadingContainer), new FrameworkPropertyMetadata(typeof(LoadingContainer))); + } + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + if (Template.Resources["OnLoading"] is Storyboard sb + && Template.FindName("MaskDG", this) is Border gd) + { + _sbOnloading = sb; + _maskContainer = gd; + _maskContainer.Visibility = Visibility.Hidden; + } + } + + #region Properties + + public string LoadingTips + { + get { return (string)GetValue(LoadingTipsProperty); } + set { SetValue(LoadingTipsProperty, value); } + } + + // Using a DependencyProperty as the backing store for LoadingTips. This enables animation, styling, binding, etc... + public static readonly DependencyProperty LoadingTipsProperty = + DependencyProperty.Register("LoadingTips", typeof(string), typeof(LoadingContainer), new PropertyMetadata("加载中,请稍等")); + + public bool OnLoading + { + get { return (bool)GetValue(OnLoadingProperty); } + set { SetValue(OnLoadingProperty, value); } + } + + // Using a DependencyProperty as the backing store for OnLoading. This enables animation, styling, binding, etc... + public static readonly DependencyProperty OnLoadingProperty = + DependencyProperty.Register("OnLoading", typeof(bool), typeof(LoadingContainer), new PropertyMetadata(OnloadingCallback)); + + private static void OnloadingCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is LoadingContainer fl) + { + if (e.NewValue.Equals(true)) + fl.StartupOnLoading(); + else + fl.StopOnLoading(); + } + } + + #endregion + + #region Tools + private void StartupOnLoading() + { + if (_sbOnloading != null) + { + _maskContainer.Visibility = Visibility.Visible; + _sbOnloading.Begin(_maskContainer); + } + } + + private void StopOnLoading() + { + if (_sbOnloading != null) + { + _sbOnloading.Stop(_maskContainer); + _maskContainer.Visibility = Visibility.Hidden; + } + } + #endregion +} diff --git a/Vampirewal.Core/WpfTheme/CustomControl/LoadingContainer/LoadingContainerStyle.xaml b/Vampirewal.Core/WpfTheme/CustomControl/LoadingContainer/LoadingContainerStyle.xaml new file mode 100644 index 0000000000000000000000000000000000000000..28d36c90ec55f34ec8e72b444e4d4f0d7e431c07 --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/LoadingContainer/LoadingContainerStyle.xaml @@ -0,0 +1,447 @@ + + + + + + \ No newline at end of file diff --git a/Vampirewal.Core/WpfTheme/CustomControl/NumTextBox/NumTextBox.cs b/Vampirewal.Core/WpfTheme/CustomControl/NumTextBox/NumTextBox.cs new file mode 100644 index 0000000000000000000000000000000000000000..66d3d6210f6372c125292ab2768d47b6caee9580 --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/NumTextBox/NumTextBox.cs @@ -0,0 +1,39 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:NumTextBox +// 创 建 者:杨程 +// 创建时间:2022/1/10 17:23:35 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.WpfTheme.CustomControl; + +public class NumTextBox:TextBox +{ + private ResourceDictionary res + { + get + { + return new ResourceDictionary() { Source = new Uri("pack://application:,,,/Vampirewal.Core;component/WpfTheme/CoreTheme.xaml", UriKind.RelativeOrAbsolute) }; + } + } + + public NumTextBox() + { + //构造函数 + + var BaseStyle = res["NumTextBoxStyle"] as Style; + + this.Style = BaseStyle; + } + + +} diff --git a/Vampirewal.Core/WpfTheme/CustomControl/NumTextBox/NumTextBoxStyle.xaml b/Vampirewal.Core/WpfTheme/CustomControl/NumTextBox/NumTextBoxStyle.xaml new file mode 100644 index 0000000000000000000000000000000000000000..8fce346f541135a6ba60d507550340c6a076fe95 --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/NumTextBox/NumTextBoxStyle.xaml @@ -0,0 +1,59 @@ + + + + \ No newline at end of file diff --git a/Vampirewal.Core/WpfTheme/CustomControl/Pagination/VPagination.cs b/Vampirewal.Core/WpfTheme/CustomControl/Pagination/VPagination.cs new file mode 100644 index 0000000000000000000000000000000000000000..fe326771e03f54b6a74d8a81353fcefdd423e474 --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/Pagination/VPagination.cs @@ -0,0 +1,705 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:VPagination +// 创 建 者:杨程 +// 创建时间:2021/12/8 9:50:21 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + + + +namespace Vampirewal.Core.WpfTheme.CustomControl; + +[TemplatePart(Name = "PART_ComboBox", Type = typeof(ComboBox))] +[TemplatePart(Name = "PART_ButtonFirstPage", Type = typeof(Button))] +[TemplatePart(Name = "PART_ButtonPrePage", Type = typeof(Button))] +[TemplatePart(Name = "PART_ListBoxPages", Type = typeof(ListBox))] +[TemplatePart(Name = "PART_ButtonNextPage", Type = typeof(Button))] +[TemplatePart(Name = "PART_ButtonLastPage", Type = typeof(Button))] +[TemplatePart(Name = "PART_PageInfo", Type = typeof(Panel))] +public class VPagination:Control +{ + public static event PropertyChangedEventHandler PropertyChanged; + + #region 是否显示每页数据量选择控件 + /// + /// 是否显示每页数据量选择控件 + /// + public bool IsShowPageDataCountSelector + { + get { return (bool)GetValue(IsShowPageDataCountSelectorProperty); } + set { SetValue(IsShowPageDataCountSelectorProperty, value); } + } + + /// + /// 是否显示每页数据量选择控件 + /// + public static readonly DependencyProperty IsShowPageDataCountSelectorProperty = + DependencyProperty.Register("IsShowPageDataCountSelector", typeof(bool), typeof(VPagination), new PropertyMetadata(true, null)); + #endregion + + #region 可选择的每页显示的数据条数集合 + /// + /// 可选择的每页显示的数据条数集合 + /// + public ObservableCollection PageDataCountCollection + { + get { return (ObservableCollection)GetValue(PageDataCountCollectionProperty); } + set { SetValue(PageDataCountCollectionProperty, value); } + } + + /// + /// 可选择的每页显示的数据条数集合 + /// + public static readonly DependencyProperty PageDataCountCollectionProperty = DependencyProperty.Register("PageDataCountCollection", typeof(ObservableCollection), typeof(VPagination), + new PropertyMetadata(new ObservableCollection { 20, 30, 50 }, null)); + #endregion + + #region 每页最多显示的数据条数 + /// + /// 每页最多显示的数据条数 + /// + public int PageDataCount + { + get { return (int)GetValue(PageDataCountProperty); } + set { SetValue(PageDataCountProperty, value); } + } + /// + /// 每页最多显示的数据条数 + /// + public static readonly DependencyProperty PageDataCountProperty = DependencyProperty.Register("PageDataCount", typeof(int), typeof(VPagination), + new PropertyMetadata(20, OnPageDataCountPropertyChanged)); + + /// + /// 每页显示的最大数据量发生改变时的回调方法 + /// + /// + /// + private static void OnPageDataCountPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + VPagination pagination = d as VPagination; + if (pagination == null) + { + return; + } + + pagination.InitData(); + } + #endregion + + #region 当前显示的可供选择的分页号集合 + /// + /// 当前显示的可供选择的分页号集合 + /// + public ObservableCollection ShowingPageNumberCollection + { + get { return (ObservableCollection)GetValue(ShowingPageNumberCollectionProperty); } + set { SetValue(ShowingPageNumberCollectionProperty, value); } + } + /// + /// 当前显示的可供选择的分页号集合 + /// + public static readonly DependencyProperty ShowingPageNumberCollectionProperty = DependencyProperty.Register("ShowingPageNumberCollection", typeof(ObservableCollection), typeof(VPagination), + new PropertyMetadata(null, null)); + #endregion + + #region 当前选择的页数 + /// + /// 当前选择的页数 + /// + public int CurrentPageNumber + { + get { return (int)GetValue(CurrentPageNumberProperty); } + set { SetValue(CurrentPageNumberProperty, value); } + } + /// + /// 当前选择的页数 + /// + public static readonly DependencyProperty CurrentPageNumberProperty = DependencyProperty.Register("CurrentPageNumber", typeof(int), typeof(VPagination), + new PropertyMetadata(1, OnCurrentPageNumberChanged)); + + /// + /// 当前选择的页数发生改变时的回调方法 + /// + /// + /// + private static void OnCurrentPageNumberChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + VPagination pagination = d as VPagination; + if (pagination == null) + { + return; + } + + if (pagination._lstShowingPage != null) + { + pagination._lstShowingPage.SelectedItem = e.NewValue; + } + + pagination.SetBtnEnable(); + //PropertyChanged(d, new PropertyChangedEventArgs(e.Property.Name)); + PropertyChanged?.Invoke(d, new PropertyChangedEventArgs(e.Property.Name)); + } + #endregion + + #region 是否显示分页信息 + /// + /// 是否显示分页信息 + /// + public bool IsShowPageInfo + { + get { return (bool)GetValue(IsShowPageInfoProperty); } + set { SetValue(IsShowPageInfoProperty, value); } + } + /// + /// 是否显示分页信息 + /// + public static readonly DependencyProperty IsShowPageInfoProperty = DependencyProperty.Register("IsShowPageInfo", typeof(bool), typeof(VPagination), + new PropertyMetadata(true, null)); + #endregion + + #region 总的数据量 + /// + /// 总的数据量 + /// + public int TotalDataCount + { + get { return (int)GetValue(TotalDataCountProperty); } + set { SetValue(TotalDataCountProperty, value); } + } + /// + /// 总的数据量 + /// + public static readonly DependencyProperty TotalDataCountProperty = DependencyProperty.Register("TotalDataCount", typeof(int), typeof(VPagination), + new PropertyMetadata(0, null)); + #endregion + + #region 当前页显示的数据条数 + /// + /// 当前页显示的数据条数 + /// + public int CurrentPageDataCount + { + get { return (int)GetValue(CurrentPageDataCountProperty); } + set { SetValue(CurrentPageDataCountProperty, value); } + } + /// + /// 当前页显示的数据条数 + /// + public static readonly DependencyProperty CurrentPageDataCountProperty = DependencyProperty.Register("CurrentPageDataCount", typeof(int), typeof(VPagination), + new PropertyMetadata(0, null)); + #endregion + + #region 总页数 + /// + /// 总页数 + /// + public int TotalPageCount + { + get { return (int)GetValue(TotalPageCountProperty); } + set { SetValue(TotalPageCountProperty, value); } + } + /// + /// 总页数 + /// + public static readonly DependencyProperty TotalPageCountProperty = DependencyProperty.Register("TotalPageCount", typeof(int), typeof(VPagination), + new PropertyMetadata(1, null)); + #endregion + + #region 当前显示页的数据起始编号 + /// + /// 当前显示页的数据起始编号 + /// + public int ShowingPageDataStartNumber + { + get { return (int)GetValue(ShowingPageDataStartNumberProperty); } + set { SetValue(ShowingPageDataStartNumberProperty, value); } + } + /// + /// 当前显示页的数据起始编号 + /// + public static readonly DependencyProperty ShowingPageDataStartNumberProperty = DependencyProperty.Register("ShowingPageDataStartNumber", typeof(int), typeof(VPagination), + new PropertyMetadata(0, null)); + #endregion + + #region 当前显示页的数据结束编号 + /// + /// 当前显示页的数据结束编号 + /// + public int ShowingPageDataEndNumber + { + get { return (int)GetValue(ShowingPageDataEndNumberProperty); } + set { SetValue(ShowingPageDataEndNumberProperty, value); } + } + /// + /// 当前显示页的数据结束编号 + /// + public static readonly DependencyProperty ShowingPageDataEndNumberProperty = DependencyProperty.Register("ShowingPageDataEndNumber", typeof(int), typeof(VPagination), + new PropertyMetadata(0, null)); + #endregion + + #region 显示的可选择页的最大数量 + /// + /// 显示的可选择页的最大数量 + /// + public int MaxShownPageCount + { + get { return (int)GetValue(MaxShownPageCountProperty); } + set { SetValue(MaxShownPageCountProperty, value); } + } + /// + /// 显示的可选择页的最大数量 + /// + public static readonly DependencyProperty MaxShownPageCountProperty = DependencyProperty.Register("MaxShownPageCount", typeof(int), typeof(VPagination), + new PropertyMetadata(7, null)); + #endregion + + #region 选中页的背景色 + /// + /// 选中页的背景色 + /// + public Brush SelectedPageBackground + { + get { return (Brush)GetValue(MaxShownPageCountProperty); } + set { SetValue(MaxShownPageCountProperty, value); } + } + /// + /// 选中页的背景色 + /// + public static readonly DependencyProperty SelectedPageBackgroundProperty = DependencyProperty.Register("SelectedPageBackground", typeof(Brush), typeof(VPagination), + new PropertyMetadata(new SolidColorBrush(Colors.Red), null)); + #endregion + + #region 未选择的页码的背景色 + /// + /// 未选择的页码的背景色 + /// + public Brush PageSelectorBackground + { + get { return (Brush)GetValue(PageSelectorBackgroundProperty); } + set { SetValue(PageSelectorBackgroundProperty, value); } + } + /// + /// 未选择的页码的背景色 + /// + public static readonly DependencyProperty PageSelectorBackgroundProperty = DependencyProperty.Register("PageSelectorBackground", typeof(Brush), typeof(VPagination), + new PropertyMetadata(null, null)); + #endregion + + //private ResourceDictionary res + //{ + // get + // { + // return new ResourceDictionary() { Source = new Uri("pack://application:,,,/Vampirewal.Core;component/WpfTheme/CoreTheme.xaml", UriKind.RelativeOrAbsolute) }; + // } + //} + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + //var VPaginationStyle = res["VPaginationStyle"] as Style; + + //this.Style = VPaginationStyle; + + //初始化控件 + InitControls(); + + //初始化数据 + ShowingPageNumberCollection = new ObservableCollection(); + InitData(); + } + + private ComboBox _cbbPageDataCount { get; set; } + + private ListBox _lstShowingPage { get; set; } + + private Button _btnFirstPage { get; set; } + + private Button _btnPrePage { get; set; } + + private Button _btnNextPage { get; set; } + + private Button _btnLastPage { get; set; } + + private bool _isIgnoreListBoxSelectionChanged { get; set; } + + private static object _lock = new object(); + + public VPagination() + { + + } + + static VPagination() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(VPagination), new FrameworkPropertyMetadata(typeof(VPagination))); + } + + /// + /// 初始化控件 + /// + private void InitControls() + { + + _cbbPageDataCount = this.Template.FindName("PART_ComboBox", this) as ComboBox; + if (_cbbPageDataCount != null) + { + _cbbPageDataCount.SelectionChanged += _cbbPageDataCount_SelectionChanged; + } + + _lstShowingPage = GetTemplateChild("PART_ListBoxPages") as ListBox; + if (_lstShowingPage != null) + { + _lstShowingPage.SelectionChanged += _lstShowingPage_SelectionChanged; + } + + _btnFirstPage = GetTemplateChild("PART_ButtonFirstPage") as Button; + if (_btnFirstPage != null) + { + _btnFirstPage.Click += _btnFirstPage_Click; + } + + _btnPrePage = GetTemplateChild("PART_ButtonPrePage") as Button; + if (_btnPrePage != null) + { + _btnPrePage.Click += _btnPrePage_Click; + } + + _btnNextPage = GetTemplateChild("PART_ButtonNextPage") as Button; + if (_btnNextPage != null) + { + _btnNextPage.Click += _btnNextPage_Click; + } + + _btnLastPage = GetTemplateChild("PART_ButtonLastPage") as Button; + if (_btnLastPage != null) + { + _btnLastPage.Click += _btnLastPage_Click; + } + } + + /// + /// 初始化数据 + /// + private void InitData() + { + try + { + _isIgnoreListBoxSelectionChanged = true; + if (PageDataCount > 0) + { + //根据总的数据量和每页最大显示的数据量计算总的页数 + if (TotalDataCount % PageDataCount > 0) + { + TotalPageCount = TotalDataCount / PageDataCount + 1; + } + else + { + TotalPageCount = TotalDataCount / PageDataCount; + } + + //将可选择页码加入到数据绑定集合中 + if (ShowingPageNumberCollection != null) + { + lock (_lock) + { + ShowingPageNumberCollection.Clear(); + int addPageCount = MaxShownPageCount; + if (TotalPageCount < MaxShownPageCount) + { + addPageCount = TotalPageCount; + } + + for (int i = 1; i <= addPageCount; i++) + { + ShowingPageNumberCollection.Add(i); + } + } + } + + //初始化选中页 + if (_lstShowingPage != null) + { + _lstShowingPage.SelectedIndex = 0; + CurrentPageNumber = 1; + } + + //更新分页数据信息 + UpdateShowingPageInfo(); + } + + SetBtnEnable(); + } + finally + { + _isIgnoreListBoxSelectionChanged = false; + } + } + + private void _cbbPageDataCount_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + ComboBox cbb = sender as ComboBox; + if (cbb == null || cbb.SelectedItem == null) + { + return; + } + + string selectedCountString = cbb.SelectedItem.ToString(); + if (!int.TryParse(selectedCountString, out int selectedDataCount)) + { + return; + } + + PageDataCount = selectedDataCount; + InitData(); + } + private void _lstShowingPage_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (_isIgnoreListBoxSelectionChanged) + { + return; + } + + try + { + _isIgnoreListBoxSelectionChanged = true; + + ListBox lst = sender as ListBox; + if (lst == null || lst.SelectedItem == null) + { + return; + } + + string selectedPageString = lst.SelectedItem.ToString(); + if (!int.TryParse(selectedPageString, out int selectedPageNumber)) + { + return; + } + + //总页数小于最大可显示页数表明无论选中的页数为何,均不需要改动页码集合中的数据,此时直接返回 + if (TotalPageCount <= MaxShownPageCount) + { + CurrentPageNumber = selectedPageNumber; + UpdateShowingPageInfo(); + return; + } + + //计算为保持选中项居中而需要向右移动的次数 比较中间位置与选中项的下标 + int moveCount = MaxShownPageCount / 2 - _lstShowingPage.SelectedIndex; + int startPageNumber = ShowingPageNumberCollection.First(); + if (moveCount > 0) //向右移动 + { + int realMoveCount = moveCount; + if (ShowingPageNumberCollection.First() - 1 < moveCount) + { + realMoveCount = ShowingPageNumberCollection.First() - 1; + } + + startPageNumber = ShowingPageNumberCollection.First() - realMoveCount; + } + else if (moveCount < 0) //向左移动 + { + int realMoveCount = -moveCount; + if (TotalPageCount - ShowingPageNumberCollection.Last() < realMoveCount) + { + realMoveCount = TotalPageCount - ShowingPageNumberCollection.Last(); + } + + startPageNumber = ShowingPageNumberCollection.First() + realMoveCount; + } + + lock (_lock) + { + ShowingPageNumberCollection.Clear(); + for (int i = 0; i < MaxShownPageCount; i++) + { + ShowingPageNumberCollection.Add(startPageNumber + i); + } + } + + int selectedItemIndex = ShowingPageNumberCollection.IndexOf(selectedPageNumber); + _lstShowingPage.SelectedIndex = selectedItemIndex; + + CurrentPageNumber = selectedPageNumber; + UpdateShowingPageInfo(); + } + finally + { + _isIgnoreListBoxSelectionChanged = false; + } + } + /// + /// 跳转到首页 + /// + /// + /// + private void _btnFirstPage_Click(object sender, RoutedEventArgs e) + { + if (_lstShowingPage == null + || ShowingPageNumberCollection == null + || ShowingPageNumberCollection.Count == 0) + { + return; + } + + if (ShowingPageNumberCollection[0] != 1) + { + try + { + _isIgnoreListBoxSelectionChanged = true; + lock (_lock) + { + ShowingPageNumberCollection.Clear(); + for (int i = 1; i <= MaxShownPageCount; i++) + { + ShowingPageNumberCollection.Add(i); + } + } + } + finally + { + _isIgnoreListBoxSelectionChanged = false; + } + } + + _lstShowingPage.SelectedIndex = 0; + } + /// + /// 跳转到尾页 + /// + /// + /// + private void _btnLastPage_Click(object sender, RoutedEventArgs e) + { + if (_lstShowingPage == null + || ShowingPageNumberCollection == null + || ShowingPageNumberCollection.Count == 0) + { + return; + } + + if (ShowingPageNumberCollection.Last() != TotalPageCount) + { + try + { + _isIgnoreListBoxSelectionChanged = true; + lock (_lock) + { + ShowingPageNumberCollection.Clear(); + for (int i = 0; i < MaxShownPageCount; i++) + { + ShowingPageNumberCollection.Add(TotalPageCount - MaxShownPageCount + i + 1); + } + } + } + finally + { + _isIgnoreListBoxSelectionChanged = false; + } + } + + _lstShowingPage.SelectedIndex = _lstShowingPage.Items.Count - 1; + } + /// + /// 跳转到前一页 + /// + /// + /// + private void _btnPrePage_Click(object sender, RoutedEventArgs e) + { + if (_lstShowingPage == null + || ShowingPageNumberCollection == null + || ShowingPageNumberCollection.Count == 0) + { + return; + } + + if (_lstShowingPage.SelectedIndex > 0) + { + _lstShowingPage.SelectedIndex--; + } + } + /// + /// 跳转到后一条 + /// + /// + /// + private void _btnNextPage_Click(object sender, RoutedEventArgs e) + { + if (_lstShowingPage == null + || ShowingPageNumberCollection == null + || ShowingPageNumberCollection.Count == 0) + { + return; + } + + if (_lstShowingPage.SelectedIndex < MaxShownPageCount - 1) + { + _lstShowingPage.SelectedIndex++; + } + } + + private void UpdateShowingPageInfo() + { + if (TotalPageCount == 0) + { + ShowingPageDataStartNumber = 0; + ShowingPageDataEndNumber = 0; + } + else if (CurrentPageNumber < TotalPageCount) + { + ShowingPageDataStartNumber = (CurrentPageNumber - 1) * PageDataCount + 1; + ShowingPageDataEndNumber = CurrentPageNumber * PageDataCount; + } + else if (CurrentPageNumber == TotalPageCount) + { + ShowingPageDataStartNumber = (CurrentPageNumber - 1) * PageDataCount + 1; + ShowingPageDataEndNumber = TotalDataCount; + } + } + + /// + /// 设置按钮的可用性 + /// + private void SetBtnEnable() + { + if (_btnFirstPage == null || _btnPrePage == null + || _btnNextPage == null || _btnLastPage == null) + { + return; + } + + _btnPrePage.IsEnabled = true; + _btnNextPage.IsEnabled = true; + _btnFirstPage.IsEnabled = true; + _btnLastPage.IsEnabled = true; + + if (ShowingPageNumberCollection == null || ShowingPageNumberCollection.Count == 0)//集合为空或者无数据,则所有按钮不可用 + { + _btnPrePage.IsEnabled = false; + _btnNextPage.IsEnabled = false; + _btnFirstPage.IsEnabled = false; + _btnLastPage.IsEnabled = false; + } + else + { + if (CurrentPageNumber == 1) + { + _btnFirstPage.IsEnabled = false; + _btnPrePage.IsEnabled = false; + } + + if (CurrentPageNumber == TotalPageCount) + { + _btnNextPage.IsEnabled = false; + _btnLastPage.IsEnabled = false; + } + } + } +} diff --git a/Vampirewal.Core/WpfTheme/CustomControl/Pagination/VPaginationStyles.xaml b/Vampirewal.Core/WpfTheme/CustomControl/Pagination/VPaginationStyles.xaml new file mode 100644 index 0000000000000000000000000000000000000000..79a2a54f7e055797cf2f6fc036011635caf9d320 --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/Pagination/VPaginationStyles.xaml @@ -0,0 +1,152 @@ + + + + + + \ No newline at end of file diff --git a/Vampirewal.Core/WpfTheme/CustomControl/RadarChartControl/RadarChart.cs b/Vampirewal.Core/WpfTheme/CustomControl/RadarChartControl/RadarChart.cs new file mode 100644 index 0000000000000000000000000000000000000000..a4e4b675de1e649621db9fcd9d4ee2d5b338b0ef --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/RadarChartControl/RadarChart.cs @@ -0,0 +1,204 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:RadarChart +// 创 建 者:杨程 +// 创建时间:2022/3/11 14:53:16 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + + +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Shapes; +using Vampirewal.Core.SimpleMVVM; + +namespace Vampirewal.Core.WpfTheme.CustomControl +{ + /// + /// 雷达图控件 + /// + //public class RadarChart : Control + //{ + + // public ObservableCollection RadarArray + // { + // get { return (ObservableCollection)GetValue(RadarArrayProperty); } + // set { SetValue(RadarArrayProperty, value); } + // } + + // public static readonly DependencyProperty RadarArrayProperty = + // DependencyProperty.Register("RadarArray", typeof(ObservableCollection), typeof(RadarChart), new PropertyMetadata(null)); + + + + + + // public Brush RadarChartTitleForeground + // { + // get { return (Brush)GetValue(RadarChartTitleForegroundProperty); } + // set { SetValue(RadarChartTitleForegroundProperty, value); } + // } + + // // Using a DependencyProperty as the backing store for RadarChartTitleForeground. This enables animation, styling, binding, etc... + // public static readonly DependencyProperty RadarChartTitleForegroundProperty = + // DependencyProperty.Register("RadarChartTitleForeground", typeof(Brush), typeof(RadarChart), new PropertyMetadata(Brushes.Black)); + + + + // /// + // /// 雷达图大小 + // /// + // public int RadarSize + // { + // get { return (int)GetValue(RadarSizeProperty); } + // set { SetValue(RadarSizeProperty, value); } + // } + + // // Using a DependencyProperty as the backing store for RadarSize. This enables animation, styling, binding, etc... + // public static readonly DependencyProperty RadarSizeProperty = + // DependencyProperty.Register("RadarSize", typeof(int), typeof(RadarChart), new PropertyMetadata(10)); + + + + // static RadarChart() + // { + // DefaultStyleKeyProperty.OverrideMetadata(typeof(RadarChart), new FrameworkPropertyMetadata(typeof(RadarChart))); + // } + // protected override void OnRender(DrawingContext drawingContext) + // { + // DrawPoints(RadarSize*3, drawingContext, true); + // DrawPoints(RadarSize*2, drawingContext); + // DrawPoints(RadarSize, drawingContext); + + // var myPen = new Pen + // { + // Thickness = 4, + // Brush = Brushes.DodgerBlue + // }; + // myPen.Freeze(); + // StreamGeometry streamGeometry = new StreamGeometry(); + // using (StreamGeometryContext geometryContext = streamGeometry.Open()) + // { + // var h = this.ActualHeight / 2; + // var w = this.ActualWidth / 2; + // PointCollection points = new PointCollection(); + // foreach (var item in RadarArray) + // { + // var ss = new Point((item.PointValue.X - w) / 100 * item.ValueMax + w, (item.PointValue.Y - h) / 100 * item.ValueMax + h); + // points.Add(ss); + // } + // geometryContext.BeginFigure(points[points.Count - 1], true, true); + // geometryContext.PolyLineTo(points, true, true); + // } + + // streamGeometry.Freeze(); + // SolidColorBrush rectBrush = new SolidColorBrush(Colors.LightSkyBlue); + // rectBrush.Opacity = 0.5; + // drawingContext.DrawGeometry(rectBrush, myPen, streamGeometry); + // } + // void DrawPoints(int circleRadius, DrawingContext drawingContext, bool isDrawText = false) + // { + // var myPen = new Pen + // { + // Thickness = 2, + // Brush = Brushes.Gainsboro + // }; + // myPen.Freeze(); + // StreamGeometry streamGeometry = new StreamGeometry(); + // using (StreamGeometryContext geometryContext = streamGeometry.Open()) + // { + // var h = this.ActualHeight / 2; + // var w = this.ActualWidth / 2; + // PointCollection points = null; + // if (isDrawText) + // points = GetPolygonPoint(new Point(w, h), circleRadius, RadarArray.Count, drawingContext); + // else + // points = GetPolygonPoint(new Point(w, h), circleRadius, RadarArray.Count); + // geometryContext.BeginFigure(points[points.Count - 1], true, true); + // geometryContext.PolyLineTo(points, true, true); + // } + // streamGeometry.Freeze(); + // drawingContext.DrawGeometry(null, myPen, streamGeometry); + // } + // private PointCollection GetPolygonPoint(Point center, double r, int polygonBound, DrawingContext drawingContext = null) + // { + // double g = 18; + // double perangle = 360 / polygonBound; + // double pi = Math.PI; + // List values = new List(); + // for (int i = 0; i < polygonBound; i++) + // { + // Point p2 = new Point(r * Math.Cos(g * pi / 180) + center.X, r * Math.Sin(g * pi / 180) + center.Y); + // if (drawingContext != null) + // { + // FormattedText formattedText = new FormattedText( + // RadarArray[i].Text, + // CultureInfo.CurrentCulture, + // FlowDirection.LeftToRight, + // new Typeface(new FontFamily("Arial"), FontStyles.Normal, FontWeights.Thin, FontStretches.Normal), + // 20.001D, RadarChartTitleForeground,1.25d) + // { + // MaxLineCount = 1, + // TextAlignment = TextAlignment.Justify, + // Trimming = TextTrimming.CharacterEllipsis + // }; + // RadarArray[i].PointValue = p2; + // if (p2.Y > center.Y && p2.X < center.X) + // drawingContext.DrawText(formattedText, new Point(p2.X - formattedText.Width - 5, p2.Y - formattedText.Height / 2)); + // else if (p2.Y < center.Y && p2.X > center.X) + // drawingContext.DrawText(formattedText, new Point(p2.X, p2.Y - formattedText.Height)); + // else if (p2.Y < center.Y && p2.X < center.X) + // drawingContext.DrawText(formattedText, new Point(p2.X - formattedText.Width - 5, p2.Y - formattedText.Height)); + // else if (p2.Y < center.Y && p2.X == center.X) + // drawingContext.DrawText(formattedText, new Point(p2.X - formattedText.Width, p2.Y - formattedText.Height)); + // else + // drawingContext.DrawText(formattedText, new Point(p2.X, p2.Y)); + // } + // values.Add(p2); + // g += perangle; + // } + // PointCollection pcollect = new PointCollection(values); + // return pcollect; + // } + //} + + //public class RadarModel : NotifyBase + //{ + // public string Text { get; set; } + + // private int _valueMax; + + // public int ValueMax + // { + // get { return _valueMax; } + // set + // { + // _valueMax = value; + // DoNotify(); + // } + // } + // private Point _pointValue; + + // public Point PointValue + // { + // get { return _pointValue; } + // set + // { + // _pointValue = value; + // DoNotify(); + // } + // } + //} +} diff --git a/Vampirewal.Core/WpfTheme/CustomControl/RadarChartControl/RadarControl.xaml b/Vampirewal.Core/WpfTheme/CustomControl/RadarChartControl/RadarControl.xaml new file mode 100644 index 0000000000000000000000000000000000000000..5602c70168f1a04fd63dcb46d2e16602499433e6 --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/RadarChartControl/RadarControl.xaml @@ -0,0 +1,15 @@ + + + + + diff --git a/Vampirewal.Core/WpfTheme/CustomControl/RadarChartControl/RadarControl.xaml.cs b/Vampirewal.Core/WpfTheme/CustomControl/RadarChartControl/RadarControl.xaml.cs new file mode 100644 index 0000000000000000000000000000000000000000..ffab265a8866c89f20a9aae1e4cb45e1c5d0dfa2 --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/RadarChartControl/RadarControl.xaml.cs @@ -0,0 +1,722 @@ + + + + +using Path = System.Windows.Shapes.Path; + +namespace Vampirewal.Core.WpfTheme.CustomControl; + +/// +/// 使用说明: +/// 1、 +/// +public partial class RadarControl : UserControl +{ + public RadarControl() + { + InitializeComponent(); + } + + #region 属性 + + /// + /// 数值区域填充色 + /// + public Brush AreaBrush + { + get { return (Brush)GetValue(AreaBrushProperty); } + set { SetValue(AreaBrushProperty, value); } + } + + public static readonly DependencyProperty AreaBrushProperty = DependencyProperty.Register("AreaBrush", typeof(Brush), + typeof(RadarControl), new PropertyMetadata(Brushes.Black)); + + /// + /// 数值区域点填充色 + /// + public Brush AreaPointBrush + { + get { return (Brush)GetValue(AreaPointBrushProperty); } + set { SetValue(AreaPointBrushProperty, value); } + } + + public static readonly DependencyProperty AreaPointBrushProperty = DependencyProperty.Register("AreaPointBrush", typeof(Brush), + typeof(RadarControl), new PropertyMetadata(Brushes.Black)); + + /// + /// 雷达网格线填充充色 + /// + public Brush RadarNetBrush + { + get { return (Brush)GetValue(RadarNetBrushProperty); } + set { SetValue(RadarNetBrushProperty, value); } + } + + public static readonly DependencyProperty RadarNetBrushProperty = DependencyProperty.Register("RadarNetBrush", typeof(Brush), + typeof(RadarControl), new PropertyMetadata(Brushes.Black)); + + /// + /// 雷达网格线宽度 + /// + public double RadarNetThickness + { + get { return (double)GetValue(RadarNetThicknessProperty); } + set { SetValue(RadarNetThicknessProperty, value); } + } + + public static readonly DependencyProperty RadarNetThicknessProperty = DependencyProperty.Register("RadarNetThickness", typeof(double), + typeof(RadarControl), new PropertyMetadata(1.0)); + + /// + /// 数值点高宽度,0为不显示 + /// + public double AreaPointSize + { + get { return (double)GetValue(AreaPointSizeProperty); } + set { SetValue(AreaPointSizeProperty, value); } + } + + public static readonly DependencyProperty AreaPointSizeProperty = DependencyProperty.Register("AreaPointSize", typeof(double), + typeof(RadarControl), new PropertyMetadata(10.0)); + + /// + /// 纬线数量 + /// + public int LatitudeCount + { + get { return (int)GetValue(LatitudeCountProperty); } + set { SetValue(LatitudeCountProperty, value); } + } + + public static readonly DependencyProperty LatitudeCountProperty = DependencyProperty.Register("LatitudeCount", typeof(int), + typeof(RadarControl), new PropertyMetadata(5)); + + /// + /// 网格图停靠间距 + /// + public int RadarNetMargin + { + get { return (int)GetValue(RadarNetMarginProperty); } + set { SetValue(RadarNetMarginProperty, value); } + } + + public static readonly DependencyProperty RadarNetMarginProperty = DependencyProperty.Register("RadarNetMargin", typeof(int), + typeof(RadarControl), new PropertyMetadata(50)); + + /// + /// 显示值标注 + /// + public bool ShowValuesLabel + { + get { return (bool)GetValue(ShowValuesLabelProperty); } + set { SetValue(ShowValuesLabelProperty, value); } + } + + public static readonly DependencyProperty ShowValuesLabelProperty = DependencyProperty.Register("ShowValuesLabel", typeof(bool), + typeof(RadarControl), new PropertyMetadata(true)); + + /// + /// 显示组标签 + /// + public bool ShowGroupsLabel + { + get { return (bool)GetValue(ShowGroupsLabelProperty); } + set { SetValue(ShowGroupsLabelProperty, value); } + } + + public static readonly DependencyProperty ShowGroupsLabelProperty = DependencyProperty.Register("ShowGroupsLabel", typeof(bool), + typeof(RadarControl), new PropertyMetadata(true)); + + /// + /// 是否为多重绘图模式(默认否) + /// + public bool MoreGraphics + { + get { return (bool)GetValue(MoreGraphicsProperty); } + set { SetValue(MoreGraphicsProperty, value); } + } + + public static readonly DependencyProperty MoreGraphicsProperty = DependencyProperty.Register("MoreGraphics", typeof(bool), + typeof(RadarControl), new PropertyMetadata(false)); + + /// + /// 分隔角度 + /// + private double Angle + { + get + { + int count = MoreGraphics ? MoreDatas[0].Count : Datas.Count; + double angle = 360 / count; + return angle; + } + } + + /// + /// 数据 + /// + [Bindable(true)] + public ObservableCollection Datas + { + get { return (ObservableCollection)GetValue(DatasProperty); } + set { SetValue(DatasProperty, value); } + } + + public static readonly DependencyProperty DatasProperty = DependencyProperty.Register("Datas", typeof(ObservableCollection), + typeof(RadarControl), new PropertyMetadata(new ObservableCollection(), DataChangedCallBack)); + + private static void DataChangedCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + //var NewData=e.NewValue as ObservableCollection; + //if (NewData != null) + //{ + // RadarControl rc=d as RadarControl; + + // rc.InitalData(); + //} + + RadarControl control = d as RadarControl; + if (control != null) + { + control.DataCollectionChanged(); + } + } + + public void DataCollectionChanged() + { + if (Datas is INotifyCollectionChanged) + { + (Datas as INotifyCollectionChanged).CollectionChanged -= DataCollectionChanged_CollectionChanged; + (Datas as INotifyCollectionChanged).CollectionChanged += DataCollectionChanged_CollectionChanged; + } + } + + private void DataCollectionChanged_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) + { + //try + //{ + // switch (e.Action) + // { + // case NotifyCollectionChangedAction.Add: + + // foreach (var item in e.NewItems) + // { + + // } + + // break; + // case NotifyCollectionChangedAction.Remove: + // break; + + // } + + + //} + //catch (Exception) + //{ + + // throw; + //} + + InitalData(); + } + + /// + /// 多元数据 + /// + [Bindable(true)] + public ObservableCollection[] MoreDatas + { + get { return (ObservableCollection[])GetValue(MoreDatasProperty); } + set { SetValue(MoreDatasProperty, value); } + } + + public static readonly DependencyProperty MoreDatasProperty = DependencyProperty.Register("MoreDatas", typeof(ObservableCollection[]), + typeof(RadarControl), new PropertyMetadata(new ObservableCollection[2])); + + /// + /// 多元数据画笔 + /// + public List RadarNetBrushes + { + get { return (List)GetValue(RadarNetBrushesProperty); } + set { SetValue(RadarNetBrushesProperty, value); } + } + + public static readonly DependencyProperty RadarNetBrushesProperty = DependencyProperty.Register("RadarNetBrushes", typeof(List), + typeof(RadarControl), new PropertyMetadata(new List())); + + /// + /// 当前绘制大区域 + /// + private double MaxSize + { + get + { + var par = this.Parent as FrameworkElement; + return par.ActualHeight > par.ActualWidth ? par.ActualWidth : par.ActualHeight; + } + } + + #endregion 属性 + + private void RadarControl_SizeChanged(object sender, SizeChangedEventArgs e) + { + if (!MoreGraphics) + InitalData(); + else + InitalMoreData(); + + } + + /// + /// 设置标注 + /// + /// + /// + /// + private void SetLabel(RadarObj obj, Point location, bool isGroupLabel) + { + //计算偏移量 + bool x = true; + bool y = true; + + if (location.X < 0) + x = false; + if (location.Y < 0) + y = false; + + TextBlock txb = new TextBlock() { Text = isGroupLabel ? obj.Name : obj.DataValue.ToString(), Foreground = this.Foreground, FontSize = this.FontSize }; + Size s = ControlSizeUtils.GetTextAreaSize(txb.Text, this.FontSize); + CanvasPanel.Children.Add(txb); + if (location.X > -5 && location.X < 5) + Canvas.SetLeft(txb, location.X - (s.Width / 2)); + else + Canvas.SetLeft(txb, location.X + (x ? 0 : -(s.Width))); + + if (location.Y > -5 && location.Y < 5) + Canvas.SetTop(txb, location.Y - (s.Height / 2)); + else + Canvas.SetTop(txb, location.Y + (y ? 0 : -(s.Height))); + } + + /// + /// 设置数据显示 + /// + private void InitalData() + { + CanvasPanel.Children.Clear(); + if (Datas != null && Datas.Count > 0) + { + this.CanvasPanel.Width = this.CanvasPanel.Height = 0; + + //计算比例尺 + var scale = ((MaxSize / 2) - RadarNetMargin) / Datas.Max(i => i.DataValue); + + //计算实际半径 + for (int i = 0; i < Datas.Count; i++) + { + Datas[i].DataRaidus = Datas[i].DataValue * scale; + } + + //获取最大数值 + double maxData = Datas.Max(i => i.DataRaidus); + + //计算纬线间距半径 + double length = maxData / LatitudeCount; + + for (int index = 1; index < LatitudeCount + 1; index++) + { + //多边形半径 + var r = length * index; + Polygon polygonBorder = new Polygon() { Fill = Brushes.Transparent, Stroke = RadarNetBrush, StrokeThickness = RadarNetThickness }; + //绘制多边形 + for (int currentIndex = 0; currentIndex < Datas.Count; currentIndex++) + { + double angle = ((Angle * currentIndex + 90) / 360) * 2 * Math.PI; + polygonBorder.Points.Add(new Point(r * Math.Cos(angle), r * Math.Sin(angle))); + } + CanvasPanel.Children.Add(polygonBorder); + } + + //数值区域多边形 + Polygon polygonArea = new Polygon() { Fill = AreaBrush, Opacity = 0.5, Stroke = AreaPointBrush, StrokeThickness = 5 }; + + //经线长度 + var maxRadius = LatitudeCount * length; + + List ellipselst = new List(); + Dictionary valuesLabelLocations = new Dictionary(); + Dictionary groupLabelLocations = new Dictionary(); + + //绘制数据多边形 + for (int Index = 0; Index < Datas.Count; Index++) + { + //计算角度 + double angle = ((Angle * Index + 90) / 360) * 2 * Math.PI; + //计算距离值 + var cou = Datas[Index].DataRaidus / length; //计算倍距 + var rac = Datas[Index].DataRaidus % length;//计算余距 + double Radius = cou * length + rac; + + //超过最大半径则设置为最大半径 + if (Radius > maxRadius) + { + Radius = maxRadius; + } + Point pt = new Point(Radius * Math.Cos(angle), Radius * Math.Sin(angle)); + polygonArea.Points.Add(pt); + valuesLabelLocations.Add(Datas[Index], new Point((Radius) * Math.Cos(angle), (Radius) * Math.Sin(angle)));//记录点位标注标识 + //设置数值点,如果数值点尺寸大于0则绘制 + if (AreaPointSize > 0) + { + var ellipse = new Ellipse() { Width = AreaPointSize, Height = AreaPointSize, Fill = AreaPointBrush }; + //var ellipse = new Ellipse() { Width = AreaPointSize, Height = AreaPointSize, Fill = Datas[Index].Fill }; AreaPointBrush + Canvas.SetLeft(ellipse, pt.X - (AreaPointSize / 2)); + Canvas.SetTop(ellipse, pt.Y - (AreaPointSize / 2)); + ellipselst.Add(ellipse); + } + + Point ptMax = new Point(maxRadius * Math.Cos(angle), maxRadius * Math.Sin(angle)); + + //记录组点位标注标识 + groupLabelLocations.Add(Datas[Index], new Point((maxRadius + 20) * Math.Cos(angle), (maxRadius + 20) * Math.Sin(angle))); + + //绘制经线 + Path pth = new Path() { Stroke = RadarNetBrush, StrokeThickness = RadarNetThickness }; + // Path pth = new Path() { Stroke = Datas[Index].Stroke, StrokeThickness = RadarNetThickness }; + pth.Data = (Geometry)new GeometryConverter().ConvertFromString(String.Format("M0,0 {0},{1}", ptMax.X.ToString(), ptMax.Y.ToString())); + CanvasPanel.Children.Add(pth); + } + CanvasPanel.Children.Add(polygonArea); + + //绘点 + foreach (var elc in ellipselst) + CanvasPanel.Children.Add(elc); + + //标注值标签 + if (ShowValuesLabel) + { + foreach (var item in valuesLabelLocations) + { + SetLabel(item.Key, item.Value, false); + } + } + //标注组标签 + if (ShowGroupsLabel) + { + foreach (var item in groupLabelLocations) + SetLabel(item.Key, item.Value, true); + } + this.SizeChanged -= RadarControl_SizeChanged; + this.SizeChanged += RadarControl_SizeChanged; + } + } + + /// + /// 设置数据显示 + /// + private void InitalMoreData() + { + CanvasPanel.Children.Clear(); + if (this.MoreDatas != null && MoreDatas.Length > 0) + { + this.CanvasPanel.Width = this.CanvasPanel.Height = 0; + + //计算比例尺 + var max = 0.00; + foreach (var item in MoreDatas) + if (item.Max(i => i.DataValue) > max) + max = item.Max(i => i.DataValue); + var scale = ((MaxSize / 2) - RadarNetMargin) / max; + + //计算实际半径 + for (int index = 0; index < MoreDatas.Length; index++) + for (int i = 0; i < MoreDatas[index].Count; i++) + MoreDatas[index][i].DataRaidus = MoreDatas[index][i].DataValue * scale; + + + //获取最大数值 + double maxData = 0.000; + foreach (var item in MoreDatas) + if (item.Max(i => i.DataRaidus) > maxData) + maxData = item.Max(i => i.DataRaidus); + + //计算纬线间距半径 + double length = maxData / LatitudeCount; + + for (int index = 1; index < LatitudeCount + 1; index++) + { + //多边形半径 + var r = length * index;//RadarNetBrush + Polygon polygonBorder = new Polygon() { Fill = Brushes.Transparent, Stroke = RadarNetBrush, StrokeThickness = RadarNetThickness }; + //绘制多边形 + for (int currentIndex = 0; currentIndex < MoreDatas[0].Count; currentIndex++) + { + double angle = ((Angle * currentIndex + 90) / 360) * 2 * Math.PI; + polygonBorder.Points.Add(new Point(r * Math.Cos(angle), r * Math.Sin(angle))); + } + CanvasPanel.Children.Add(polygonBorder); + } + + //数值区域多边形 + List polygonAreaList = new List(); + for (int index = 0; index < this.MoreDatas.Length; index++) + polygonAreaList.Add(new Polygon() { Fill = RadarNetBrushes[index], Opacity = 0.5, Stroke = Brushes.LightGreen, StrokeThickness = 3 }); + + //经线长度 + var maxRadius = LatitudeCount * length; + + List ellipselst = new List(); + Dictionary valuesLabelLocations = new Dictionary(); + Dictionary groupLabelLocations = new Dictionary(); + + + //绘制数据多边形 + for (int Index = 0; Index < MoreDatas[0].Count; Index++) + { + //计算角度 + double angle = ((Angle * Index + 90) / 360) * 2 * Math.PI; + + //逐步生成每类数据的各组实际数据:例如A、B、C、D的交通数据数据 + for (int dataIndex = 0; dataIndex < MoreDatas.Length; dataIndex++) + { + //计算距离值 + var cou = MoreDatas[dataIndex][Index].DataRaidus / length; //计算倍距 + var rac = MoreDatas[dataIndex][Index].DataRaidus % length;//计算余距 + double Radius = cou * length + rac; + + //超过最大半径则设置为最大半径 + if (Radius > maxRadius) + { + Radius = maxRadius; + } + Point pt = new Point(Radius * Math.Cos(angle), Radius * Math.Sin(angle)); + polygonAreaList[dataIndex].Points.Add(pt); + //valuesLabelLocations.Add(Datas[Index], new Point((Radius) * Math.Cos(angle), (Radius) * Math.Sin(angle)));//记录点位标注标识 + //设置数值点,如果数值点尺寸大于0则绘制 + if (AreaPointSize > 0) + { + var ellipse = new Ellipse() { Width = AreaPointSize / 2, Height = AreaPointSize / 2, Fill = new SolidColorBrush((Color)ColorConverter.ConvertFromString(ChartColorPool.ColorStrings[Index])) }; + Canvas.SetLeft(ellipse, pt.X - (AreaPointSize / 4)); + Canvas.SetTop(ellipse, pt.Y - (AreaPointSize / 4)); + ellipselst.Add(ellipse); + } + } + Point ptMax = new Point(maxRadius * Math.Cos(angle), maxRadius * Math.Sin(angle)); + + //记录组点位标注标识 + groupLabelLocations.Add(MoreDatas[0][Index], new Point((maxRadius + 20) * Math.Cos(angle), (maxRadius + 20) * Math.Sin(angle))); + + //绘制经线 RadarNetBrush + Path pth = new Path() { Stroke = RadarNetBrush, StrokeThickness = RadarNetThickness }; + pth.Data = (Geometry)new GeometryConverter().ConvertFromString(String.Format("M0,0 {0},{1}", ptMax.X.ToString(), ptMax.Y.ToString())); + CanvasPanel.Children.Add(pth); + } + foreach (var polygonArea in polygonAreaList) + CanvasPanel.Children.Add(polygonArea); + + //绘点 + foreach (var elc in ellipselst) + CanvasPanel.Children.Add(elc); + + //标注组标签 + if (ShowGroupsLabel) + { + foreach (var item in groupLabelLocations) + SetLabel(item.Key, item.Value, true); + } + this.SizeChanged -= RadarControl_SizeChanged; + this.SizeChanged += RadarControl_SizeChanged; + } + } + + public void InitalControl() + { + } + + /// + /// 加载数据 + /// + /// + public void SetData(object dataobj) + { + if (!MoreGraphics) + { + this.Datas = (dataobj) as ObservableCollection; + this.InitalData(); + } + else + { + this.MoreDatas = (dataobj) as ObservableCollection[]; + InitalMoreData(); + } + + } + + private Brush _stroke = Brushes.Yellow; + + /// + /// Series stroke + /// + public Brush Stroke + { + get + { + return _stroke; + } + set + { + _stroke = value; + } + } + + private Brush _fill = Brushes.Yellow; + + /// + /// Series Fill + /// + public Brush Fill + { + get + { + return _fill; + } + set + { + _fill = value; + } + } +} + +public class RadarObj +{ + public string Name { get; set; } + + public int DataValue { get; set; } + + public double DataRaidus { get; set; } +} + + + +/// +/// 计算指定字符串占用的高宽 +/// +public class ControlSizeUtils +{ + + private static Size MeasureTextSize(string text, Typeface typeface, double fontSize) + { + var ft = new FormattedText(text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, typeface, fontSize, Brushes.Black); + return new Size(ft.Width, ft.Height); + } + + /// + /// 衡量字符尺寸 + /// + /// + public static Size GetTextAreaSize(string text, double fontsize) + { + FontFamily fontFamily; FontStyle fontStyle; FontWeight fontWeight; FontStretch fontStretch; + fontFamily = new FontFamily("微软雅黑"); fontStyle = FontStyles.Normal; + fontWeight = FontWeights.Normal; + fontStretch = FontStretches.Normal; + double fontSize = fontsize; + if (text == null) + return new Size(0, 0); + + Typeface typeface = new Typeface(fontFamily, fontStyle, fontWeight, fontStretch); + GlyphTypeface gt; + + if (!typeface.TryGetGlyphTypeface(out gt)) + return MeasureTextSize(text, typeface, fontSize); + + double totalWidth = 0; + double totalHeight = 0; + + // 替换换行符 + var array = text.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); + + foreach (var splitted in array) + { + double lineWidth = 0; + double lineHeight = 0; + + // 计算每行的宽度和高度 + for (int n = 0; n < splitted.Length; n++) + { + try + { + ushort glyphIndex = gt.CharacterToGlyphMap[splitted[n]]; + double width = gt.AdvanceWidths[glyphIndex] * fontSize; + double height = gt.AdvanceHeights[glyphIndex] * fontSize; + lineHeight = Math.Max(totalHeight, height); + lineWidth += width; + } + catch (Exception exp) + { + lineWidth += fontSize; + } + } + totalWidth = Math.Max(totalWidth, lineWidth); + totalHeight = Math.Max(totalHeight, lineHeight); + } + if (totalWidth < 5) + totalWidth = 5; + return new Size(totalWidth, totalHeight); + } +} + +/// +/// 颜色池 +/// +public static class ChartColorPool +{ + public static List ColorStrings { get; set; } = new List() { + "#FF09F7D7", + "#FF97F18E", + "#FFF1ADAD", + "#FFF44336", + "#FFE91E63", + "#FF9C27B0", + "#FF673AB7", + "#FF3F51B5", + "#FF2196F3", + "#FF03A9F4", + "#FF00BCD4", + "#FF009688", + "#FF4CAF50", + "#FF8BC34A", + "#FFCDDC39", + "#FFFFEB3B", + "#FFFFC107", + "#FFFF9800", + "#FFFF5722", + "#FF795548", + "#FF9E9E9E", + "#FF607D8B", + "#32CD32", + "#FFFF00", + "#32CD32", + "#FFFF00", + "#21B6BA", + "#D84E67", + "#B44ED6", + "#0092FF", + "#E6FF0D", + "#21B962", + "#FF0000", //[32]Red-纯红 + "#00BFFF" , //[33]DeepSkyBlue-深天蓝 + "#0099D7",//浅蓝 + "#FF9B4D", //橙色 + "#00F8A4", //浅绿 + "#FFEF53", //黄色 + "#EB7274", //粉色 + "#8B95AD", //浅灰 + "#00DFDE", //浅蓝 + "#C19EDC", //浅紫 + "#62474C"//褐色 + }; +} + diff --git a/Vampirewal.Core/WpfTheme/CustomControl/SearchControl/SearchControl.cs b/Vampirewal.Core/WpfTheme/CustomControl/SearchControl/SearchControl.cs new file mode 100644 index 0000000000000000000000000000000000000000..e54e4f26d3a576fef350ef5a01257b0ea2af36d1 --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/SearchControl/SearchControl.cs @@ -0,0 +1,116 @@ +#region << 文 件 说 明 >> +/*---------------------------------------------------------------- +// 文件名称:SreachControl +// 创 建 者:杨程 +// 创建时间:2021/12/21 10:26:27 +// 文件版本:V1.0.0 +// =============================================================== +// 功能描述: +// +// +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.WpfTheme.CustomControl; + +public class SearchControl:TextBox +{ + private ResourceDictionary res + { + get + { + return new ResourceDictionary() { Source = new Uri("pack://application:,,,/Vampirewal.Core;component/WpfTheme/CoreTheme.xaml", UriKind.RelativeOrAbsolute) }; + } + } + + public SearchControl() + { + //构造函数 + + var BaseStyle = res["SearchControlStyle"] as Style; + + this.Style = BaseStyle; + } + + private TextBox SearchText { get; set; } + private Button SearchButton { get; set; } + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + SearchText=this.Template.FindName("SearchText",this) as TextBox; + + if (SearchTextStyle!=null) + { + SearchText.Style = SearchTextStyle; + } + + SearchButton = this.Template.FindName("SearchButton", this) as Button; + + if (SearchButtonStyle != null) + { + SearchButton.Style = SearchButtonStyle; + } + } + + #region 属性 + + #endregion + + #region 公共方法 + + #endregion + + #region 私有方法 + + #endregion + + #region 命令 + + #endregion + + #region 依赖属性 + + public ICommand SearchCommand + { + get { return (ICommand)GetValue(SearchCommandProperty); } + set { SetValue(SearchCommandProperty, value); } + } + + // Using a DependencyProperty as the backing store for SreachCommand. This enables animation, styling, binding, etc... + public static readonly DependencyProperty SearchCommandProperty = + DependencyProperty.Register("SearchCommand", typeof(ICommand), typeof(SearchControl), new PropertyMetadata(null)); + + + + + public Style SearchTextStyle + { + get { return (Style)GetValue(SearchTextStyleProperty); } + set { SetValue(SearchTextStyleProperty, value); } + } + + // Using a DependencyProperty as the backing store for SreachTextStyle. This enables animation, styling, binding, etc... + public static readonly DependencyProperty SearchTextStyleProperty = + DependencyProperty.Register("SearchTextStyle", typeof(Style), typeof(SearchControl), new PropertyMetadata(null)); + + + + + public Style SearchButtonStyle + { + get { return (Style)GetValue(SearchButtonStyleProperty); } + set { SetValue(SearchButtonStyleProperty, value); } + } + + // Using a DependencyProperty as the backing store for SearchButtonStyle. This enables animation, styling, binding, etc... + public static readonly DependencyProperty SearchButtonStyleProperty = + DependencyProperty.Register("SearchButtonStyle", typeof(Style), typeof(SearchControl), new PropertyMetadata(null)); + + + + + #endregion +} diff --git a/Vampirewal.Core/WpfTheme/CustomControl/SearchControl/SearchControlStyle.xaml b/Vampirewal.Core/WpfTheme/CustomControl/SearchControl/SearchControlStyle.xaml new file mode 100644 index 0000000000000000000000000000000000000000..ca566cab99b88fb59e3de84ad58f0c08ecca80cb --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/SearchControl/SearchControlStyle.xaml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Vampirewal.Core/WpfTheme/CustomControl/TitleContent/TitleContent.cs b/Vampirewal.Core/WpfTheme/CustomControl/TitleContent/TitleContent.cs index 3e968f3bfae0dbb35b949ec752f1e1179dfcafbf..5002636bed65af674eef9c2a73d1b696551b7d00 100644 --- a/Vampirewal.Core/WpfTheme/CustomControl/TitleContent/TitleContent.cs +++ b/Vampirewal.Core/WpfTheme/CustomControl/TitleContent/TitleContent.cs @@ -11,153 +11,146 @@ //----------------------------------------------------------------*/ #endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Media; - -namespace Vampirewal.Core.WpfTheme.CustomControl + + + +namespace Vampirewal.Core.WpfTheme.CustomControl; + +/// +/// 带标题的内容控件 +/// +public class TitleContent : ContentControl { - /// - /// 带标题的内容控件 - /// - public class TitleContent : ContentControl + static TitleContent() { - static TitleContent() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(TitleContent), new FrameworkPropertyMetadata(typeof(TitleContent))); - } + DefaultStyleKeyProperty.OverrideMetadata(typeof(TitleContent), new FrameworkPropertyMetadata(typeof(TitleContent))); + } - private ResourceDictionary res + private ResourceDictionary res + { + get { - get - { - return new ResourceDictionary() { Source = new Uri("pack://application:,,,/Vampirewal.Core;component/WpfTheme/CoreTheme.xaml", UriKind.RelativeOrAbsolute) }; - } + return new ResourceDictionary() { Source = new Uri("pack://application:,,,/Vampirewal.Core;component/WpfTheme/CoreTheme.xaml", UriKind.RelativeOrAbsolute) }; } + } - public TitleContent() - { - //构造函数 - var TitleContentStyle = res["TitleContentStyle"] as Style; + public TitleContent() + { + //构造函数 + var TitleContentStyle = res["TitleContentStyle"] as Style; - this.Style = TitleContentStyle; - } + this.Style = TitleContentStyle; + } - public override void OnApplyTemplate() - { - base.OnApplyTemplate(); - - //var title = this.Template.FindName("Title", this) as TextBlock; - //title.Text = Title; - //if (TitleWidth > 0) - //{ - // //title.Width = TitleWidth; - // Binding widthBind = new Binding("TitleWidth"); - // widthBind.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor); - // widthBind.RelativeSource.AncestorType = typeof(TitleContent); - // title.SetBinding(TextBlock.WidthProperty, widthBind); - //} - } + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + //var title = this.Template.FindName("Title", this) as TextBlock; + //title.Text = Title; + //if (TitleWidth > 0) + //{ + // //title.Width = TitleWidth; + // Binding widthBind = new Binding("TitleWidth"); + // widthBind.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor); + // widthBind.RelativeSource.AncestorType = typeof(TitleContent); + // title.SetBinding(TextBlock.WidthProperty, widthBind); + //} + } - public string Title - { - get { return (string)GetValue(TitleProperty); } - set { SetValue(TitleProperty, value); } - } + public string Title + { + get { return (string)GetValue(TitleProperty); } + set { SetValue(TitleProperty, value); } + } - // Using a DependencyProperty as the backing store for Title. This enables animation, styling, binding, etc... - public static readonly DependencyProperty TitleProperty = - DependencyProperty.Register("Title", typeof(string), typeof(TitleContent), new PropertyMetadata("")); + // Using a DependencyProperty as the backing store for Title. This enables animation, styling, binding, etc... + public static readonly DependencyProperty TitleProperty = + DependencyProperty.Register("Title", typeof(string), typeof(TitleContent), new PropertyMetadata("")); - private static void TitlePropertyCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) + private static void TitlePropertyCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is TitleContent && e.NewValue != null) { - if (d is TitleContent && e.NewValue != null) - { - var control = d as TitleContent; - control.SetValue(TitleContent.TitleProperty, e.NewValue); - } + var control = d as TitleContent; + control.SetValue(TitleContent.TitleProperty, e.NewValue); } + } - public double TitleWidth - { - get { return (double)GetValue(TitleWidthProperty); } - set { SetValue(TitleWidthProperty, value); } - } + public double TitleWidth + { + get { return (double)GetValue(TitleWidthProperty); } + set { SetValue(TitleWidthProperty, value); } + } - // Using a DependencyProperty as the backing store for TitleWidth. This enables animation, styling, binding, etc... - public static readonly DependencyProperty TitleWidthProperty = - DependencyProperty.Register("TitleWidth", typeof(double), typeof(TitleContent), new PropertyMetadata(0d)); + // Using a DependencyProperty as the backing store for TitleWidth. This enables animation, styling, binding, etc... + public static readonly DependencyProperty TitleWidthProperty = + DependencyProperty.Register("TitleWidth", typeof(double), typeof(TitleContent), new PropertyMetadata(0d)); - private static void TitleWidthCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) + private static void TitleWidthCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is TitleContent && e.NewValue != null) { - if (d is TitleContent && e.NewValue != null) - { - var control = d as TitleContent; - control.SetValue(TitleContent.TitleWidthProperty, e.NewValue); - } + var control = d as TitleContent; + control.SetValue(TitleContent.TitleWidthProperty, e.NewValue); } + } - public VerticalAlignment TitleVerticalAlignment - { - get { return (VerticalAlignment)GetValue(MyPropertyProperty); } - set { SetValue(MyPropertyProperty, value); } - } + public VerticalAlignment TitleVerticalAlignment + { + get { return (VerticalAlignment)GetValue(MyPropertyProperty); } + set { SetValue(MyPropertyProperty, value); } + } - // Using a DependencyProperty as the backing store for TitleVerticalAlignment. This enables animation, styling, binding, etc... - public static readonly DependencyProperty MyPropertyProperty = - DependencyProperty.Register("TitleVerticalAlignment", typeof(VerticalAlignment), typeof(TitleContent), new PropertyMetadata(VerticalAlignment.Center)); + // Using a DependencyProperty as the backing store for TitleVerticalAlignment. This enables animation, styling, binding, etc... + public static readonly DependencyProperty MyPropertyProperty = + DependencyProperty.Register("TitleVerticalAlignment", typeof(VerticalAlignment), typeof(TitleContent), new PropertyMetadata(VerticalAlignment.Center)); - public Thickness TitlePadding - { - get { return (Thickness)GetValue(TitlePaddingProperty); } - set { SetValue(TitlePaddingProperty, value); } - } + public Thickness TitlePadding + { + get { return (Thickness)GetValue(TitlePaddingProperty); } + set { SetValue(TitlePaddingProperty, value); } + } - // Using a DependencyProperty as the backing store for TitlePadding. This enables animation, styling, binding, etc... - public static readonly DependencyProperty TitlePaddingProperty = - DependencyProperty.Register("TitlePadding", typeof(Thickness), typeof(TitleContent), new PropertyMetadata(new Thickness(0, 0, 10, 0))); + // Using a DependencyProperty as the backing store for TitlePadding. This enables animation, styling, binding, etc... + public static readonly DependencyProperty TitlePaddingProperty = + DependencyProperty.Register("TitlePadding", typeof(Thickness), typeof(TitleContent), new PropertyMetadata(new Thickness(0, 0, 10, 0))); - public Brush TitleForeground - { - get { return (Brush)GetValue(TitleForegroundProperty); } - set { SetValue(TitleForegroundProperty, value); } - } + public Brush TitleForeground + { + get { return (Brush)GetValue(TitleForegroundProperty); } + set { SetValue(TitleForegroundProperty, value); } + } - // Using a DependencyProperty as the backing store for TitleForeground. This enables animation, styling, binding, etc... - public static readonly DependencyProperty TitleForegroundProperty = - DependencyProperty.Register("TitleForeground", typeof(Brush), typeof(TitleContent), new PropertyMetadata(Brushes.Black)); + // Using a DependencyProperty as the backing store for TitleForeground. This enables animation, styling, binding, etc... + public static readonly DependencyProperty TitleForegroundProperty = + DependencyProperty.Register("TitleForeground", typeof(Brush), typeof(TitleContent), new PropertyMetadata(Brushes.Black)); - #region 属性 + #region 属性 - #endregion + #endregion - #region 公共方法 + #region 公共方法 - #endregion + #endregion - #region 私有方法 + #region 私有方法 - #endregion + #endregion - #region 命令 + #region 命令 - #endregion - } + #endregion } diff --git a/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/FirstColumn.cs b/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/FirstColumn.cs new file mode 100644 index 0000000000000000000000000000000000000000..2aa12cb1c1d5eb7c600a74bc49953fdd904eda23 --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/FirstColumn.cs @@ -0,0 +1,136 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: FirstColumn +// 创建者: 杨程 +// 创建日期: 2022/11/22 10:13:45 + +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.WpfTheme.CustomControl; + +/// +/// 首列 +/// +public abstract class FirstColumn : DependencyObject +{ + /// + /// 首列列头 + /// + public string HeaderDisplayValue { get; protected set; } + + /// + /// 是否有复选框 + /// + public bool HasCheckBox { get; set; } + + #region 样式 + + /// + /// 列宽 + /// + public double HeaderWidth { get; set; } = 100d; + /// + /// 纵向对齐方式 + /// + public VerticalAlignment VerticalAlignment { get; set; } = VerticalAlignment.Center; + + /// + /// 横向对齐方式 + /// + public HorizontalAlignment HorizontalAlignment { get; set; } = HorizontalAlignment.Left; + + /// + /// 文字颜色 + /// + public Brush Foreground { get; set; } = Brushes.Black; + #endregion +} + +/// +/// 自动序号首列 +/// +public class AutoCodeFirstColumn : FirstColumn +{ + public AutoCodeFirstColumn() + { + base.HeaderDisplayValue = "序号"; + } + + /// + /// 标题 + /// + public string FirstColumnHeader + { + get + { + return base.HeaderDisplayValue; + } + } + + /// + /// 是否启用自动编号 + /// + public bool UseAutoCode { get; set; } = true; +} + +/// +/// 自定义首列 +/// +public class CustromFirstColumn : FirstColumn +{ + #region SourceUpdate触发 + + public ICommand FirstColumnSourceUpdateCommand + { + get { return (ICommand)GetValue(FirstColumnSourceUpdateCommandProperty); } + set { SetValue(FirstColumnSourceUpdateCommandProperty, value); } + } + + // Using a DependencyProperty as the backing store for FirstColumnSourceUpdateCommand. This enables animation, styling, binding, etc... + public static readonly DependencyProperty FirstColumnSourceUpdateCommandProperty = + DependencyProperty.Register("FirstColumnSourceUpdateCommand", typeof(ICommand), typeof(CustromFirstColumn), new PropertyMetadata(null)); + + #endregion + + public string FirstColumnHeader + { + get + { + return base.HeaderDisplayValue; + } + set + { + base.HeaderDisplayValue = value; + } + } + + /// + /// 首列绑定的属性,以文字形式展示 + /// + public string FirstColumnBindingPath { get; set; } + + /// + /// 首列转换器 + /// + public IValueConverter Converter { get; set; } + + /// + /// 是否为只读 + /// + public bool IsReadOnly { get; set; } = true; + + /// + /// 是否只能编辑最明细项 + /// + public bool JustEditDetailItem { get; set; } +} diff --git a/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/GeneralTreeContainer.cs b/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/GeneralTreeContainer.cs new file mode 100644 index 0000000000000000000000000000000000000000..19f3ec050e4896adad6b268b048801c8c2215c4c --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/GeneralTreeContainer.cs @@ -0,0 +1,202 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: GeneralTreeContainer +// 创建者: 杨程 +// 创建日期: 2022/11/21 15:59:41 + +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.WpfTheme.CustomControl; + +/// +/// 通用树形容器 +/// +public partial class GeneralTreeContainer:ObservableObject + where TTreeData : ITreeNode +{ + /// + /// + /// + public GeneralTreeContainer(TTreeData treeNode) + { + //构造函数 + TreeNode = treeNode; + } + public GeneralTreeContainer(GeneralTreeContainer parentNode, TTreeData treeNode) + : this(treeNode) + { + ParentNode = parentNode; + } + + #region 重写 + + #endregion + + #region 属性 + + + /// + /// 当前节点值 + /// + public TTreeData TreeNode { get; private set; } + /// + /// 父节点,null表示顶节点 + /// + public GeneralTreeContainer ParentNode { get; set; } + + #region 是否选中 + + /// + /// 是否选中 + /// + [ObservableProperty] + public bool? isChecked=false; + + [ObservableProperty] + public bool isSelected=false; + + + [ObservableProperty] + public bool isExpanded; + + + #endregion + + #region 树内部层级 + + public void RefreshLevel(int rootIndex = -1) + { + if (ParentNode != null) + { + var levelIndex = ParentNode.SubItems.IndexOf(this) + 1; + _treeLevelPath = $"{ParentNode.TreeLevelPath}-{levelIndex}"; + } + else if (rootIndex >= 0) + { + _treeLevelPath = $"{rootIndex}"; + } + } + + private string _treeLevelPath; + /// + /// 树内部层级 + /// + public string TreeLevelPath + { + get + { + RefreshLevel(); + return _treeLevelPath; + } + internal set + { + _treeLevelPath = value; + OnPropertyChanged(); + } + } + #endregion + + #region Methodes + + /// + /// 获取子节点列表 + /// + /// 子节点列表集合 + public void GetSubNodeList(ref List> treeList) + { + if (SubItems == null) + return; + foreach (var item in SubItems) + { + treeList.Add(item); + item.GetSubNodeList(ref treeList); + } + } + + /// + /// 根据删除指定的节点数据 + /// + /// 当子节点清空后,是否删除父节点 + /// 要删除的节点 + public List> RemoveSubNode(bool isRemoveParentNode, ref List delNodes) + { + List> delNodeList = new List>(); + if (delNodes.Count < 1 || SubItems == null) + return delNodeList; + + for (int i = 0; i < SubItems.Count; i++) + { + var tmpDelNode = delNodes.FirstOrDefault(t => t.IsSameNode(SubItems[i].TreeNode)); + if (tmpDelNode != null) + { + //获取被删除节点下的所有子节点 + delNodeList.Add(SubItems[i]); + SubItems[i].GetSubNodeList(ref delNodeList); + //删除子节点 + SubItems.RemoveAt(i); + delNodes.Remove(tmpDelNode); + i--; + } + else if (SubItems[i].SubItems != null) + { + delNodeList.AddRange(SubItems[i].RemoveSubNode(isRemoveParentNode, ref delNodes)); + if (isRemoveParentNode && SubItems[i].SubItems.Count < 1) + { + //子节点清空后,删除对应父节点,添加节点到已删除列表 + delNodeList.Add(SubItems[i]); + + SubItems.RemoveAt(i); + i--; + } + } + } + return delNodeList; + } + + /// + /// 添加子节点 + /// + /// 要添加的子节点 + public void AppendSubNode(IEnumerable> subItems) + { + foreach (var item in subItems) + { + item.ParentNode = this; + } + if (SubItems == null) + SubItems = new ObservableCollection>(subItems); + else + { + foreach (var item in subItems) + { + SubItems.Add(item); + } + } + } + + #endregion + + #region 子节点 + + private ObservableCollection> _subItems; + /// + /// 子节点 + /// + [ObservableProperty] + public ObservableCollection> subItems; + + #endregion + #endregion + + +} diff --git a/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/GeneralTreeItemsManager.cs b/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/GeneralTreeItemsManager.cs new file mode 100644 index 0000000000000000000000000000000000000000..9a22a37547e835cb78d2d750a2797bc1a020a78b --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/GeneralTreeItemsManager.cs @@ -0,0 +1,109 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: GeneralTreeItemsManager +// 创建者: 杨程 +// 创建日期: 2022/11/21 16:46:16 + +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.WpfTheme.CustomControl; + +/// +/// +/// +public class GeneralTreeItemsManager where TNode : class, ITreeNode +{ + /// + /// 构建树 + /// + /// 树列表数据 + public static List> BuildTree(IEnumerable nodes) + { + //存树结构 + List> treeNodes = new List>(); + var treeContainerList = nodes.AsParallel() + .Select(t => new GeneralTreeContainer(t)) + .ToDictionary(t => t.TreeNode.GetCurrentNodeMark()); + + foreach (var item in treeContainerList) + { + if (treeContainerList.ContainsKey(item.Value.TreeNode.GetParentNodeMark())) + { + item.Value.ParentNode = treeContainerList[item.Value.TreeNode.GetParentNodeMark()]; + treeContainerList[item.Value.TreeNode.GetParentNodeMark()].SubItems = treeContainerList[item.Value.TreeNode.GetParentNodeMark()].SubItems ?? + new ObservableCollection>(); + treeContainerList[item.Value.TreeNode.GetParentNodeMark()].SubItems.Add(item.Value); + } + else + { + treeNodes.Add(item.Value); + } + + } + return treeNodes; + } + + /// + /// 仅用容器包裹 + /// + /// + /// + public static List> BuildContainer(IEnumerable nodes) + { + return nodes.AsParallel().Select(t => new GeneralTreeContainer(t)).ToList(); + } + + /// + /// 获取传入集合中的顶节点 + /// + /// 节点数据 + /// + public static TNode GetRootNode(IEnumerable nodes) + { + if (nodes != null && nodes.Count() > 0) + { + TNode tmpNode = nodes.First(); + TNode rootNode = tmpNode; + while (true) + { + tmpNode = nodes.FirstOrDefault(t => t.IsSubNode(tmpNode)); + if (tmpNode == null) + break; + else + rootNode = tmpNode; + } + return rootNode; + } + return null; + } + + /// + /// 获取最子级节点 + /// + /// + /// + public static IEnumerable GetLeafNode(IEnumerable nodes) + { + List results = new List(); + if (nodes != null && nodes.Count() > 0) + { + foreach (var node in nodes) + { + var tmp = nodes.Where(p => p.IsParentNode(node)); + if (tmp.Count() == 0) results.Add(node); + } + return results; + } + return null; + } +} diff --git a/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/ITreeBuilder.cs b/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/ITreeBuilder.cs new file mode 100644 index 0000000000000000000000000000000000000000..e354aa719cd652e94b5cab4b27cd08f8b37c4245 --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/ITreeBuilder.cs @@ -0,0 +1,85 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: ITreeBuilder +// 创建者: 杨程 +// 创建日期: 2022/11/23 14:32:12 + +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.WpfTheme.CustomControl; + +/// +/// +/// +public interface ITreeBuilder +{ + /// + /// 是否选中全部节点 + /// + bool? CheckedAllNodes { get; } + + + /// + /// 是否为单步加载模式 + /// + bool IsSingleLoadMode { get; } + + /// + /// 选中并更新节点选择状态 + /// + /// + /// + void CheckAndUpdateStateNode(object curNode, bool isChecked); + + /// + /// 设置全局选择状态 + /// + /// + void SetCheckStatusOfAllNodes(bool isChecked); + + + /// + /// 选中复制项(Ctrl) + /// + /// 当前选中项 + void SelectedCopyItemByCtrl(object selectedItem); + + + /// + /// 选中复制项(Shift) + /// + /// 当前选中项 + void SelectedCopyItemByShift(object selectedItem); + + + /// + /// 清除所有已选择的待复制项,并选中指定的项 + /// + /// 当前选中项 + void ClearSelectedCopyItems(object selectedItem); + + + /// + /// 搜索并定位到节点 + /// + /// 搜索的字符串 + /// 是否向下搜索 + void SearchAndLocationNode(string searchStr, bool searchOfDown = true); + + + /// + /// 开始加载子项 + /// + /// 父节点信息 + void BeginLoadSubItems(object parentNode); +} diff --git a/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/ITreeNode.cs b/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/ITreeNode.cs new file mode 100644 index 0000000000000000000000000000000000000000..736e4e5c7004c3c80c0ed5d84bf1f198ebe12cca --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/ITreeNode.cs @@ -0,0 +1,79 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: ITreeNode +// 创建者: 杨程 +// 创建日期: 2022/11/21 15:55:02 + +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.WpfTheme.CustomControl; + +/// +/// +/// +public interface ITreeNode +{ + + + /// + /// 获取父节点标识 + /// + /// + object GetParentNodeMark(); + + + /// + /// 设置父节点标识 + /// + /// 设置的父节点对象 + void SetParentNodeMark(object parentObj); + + + /// + /// 获取当前节点标识 + /// + /// + object GetCurrentNodeMark(); + + + /// + /// subNode是否为当前节点的子节点 + /// + /// 子节点 + /// + bool IsSubNode(ITreeNode subNode); + + + + /// + /// parentNode是否为当前节点的父节点 + /// + /// + /// + bool IsParentNode(ITreeNode parentNode); + + + /// + /// node是否与当前节点相同 + /// + /// 需要比较的节点 + /// + bool IsSameNode(ITreeNode node); + + /// + /// node是否与该项拥有相同父节点 + /// + /// + /// + bool IsSameParent(ITreeNode node); +} diff --git a/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/TreeBuilderBase.cs b/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/TreeBuilderBase.cs new file mode 100644 index 0000000000000000000000000000000000000000..46947ea6a25c06ee2dc0c53c3b696669f7811fa4 --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/TreeBuilderBase.cs @@ -0,0 +1,387 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: TreeBuilderBase +// 创建者: 杨程 +// 创建日期: 2022/11/21 16:35:52 + +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.WpfTheme.CustomControl; + +/// +/// 通用树构建基础 +/// +public abstract class TreeBuilderBase :ITreeBuilder, IDisposable + where TNode : class, ITreeNode +{ + /// + /// + /// + public TreeBuilderBase() + { + //构造函数 + BindingTreeItems = new ObservableCollection>(); + _sourceTreeNodes = new List>(); + } + + #region 重写 + + #endregion + + #region 属性 + /// + /// 全选节点 + /// + public bool? CheckedAllNodes { get; private set; } + /// + /// 是否单步加载模式 + /// + public bool IsSingleLoadMode { get; protected set; } + /// + /// 绑定的值 + /// + public ObservableCollection> BindingTreeItems { get; } + + /// + /// 树节点元数据 + /// + protected List> _sourceTreeNodes; + + public event Action Evt_SelectedNode; + public event Action Evt_CheckNodes; + + public void Dispose() + { + + } + #endregion + + #region 公共方法 + + #region 可重载方法 + + /// + /// 添加新的树型数据 + /// + /// 要插入的目标节点 + /// 要插入的节点,可以包含子节点 + /// + public virtual void AppendNodes(TNode target, params TNode[] subItems) + { + if (subItems == null || subItems.Length == 0) + return; + + var disNodes = GetDisplayNodes(); + var targetNode = disNodes.FirstOrDefault(t => t.TreeNode.IsSameNode(target)); + var treeNodes = GeneralTreeItemsManager.BuildTree(subItems); + + if (targetNode == null) + throw new NullReferenceException("要插入的数据,在原数据树中未找到"); + else + { + //设置父节点,如果subItems是树,那么内部会设置其子节点的信息(包括父节点) + targetNode.AppendSubNode(treeNodes); + } + } + + /// + /// 添加新的顶节点 + /// + /// 要添加的顶节点 + public virtual void AddRootNodes(params TNode[] rootNodes) + { + foreach (var item in rootNodes) + { + var node = new GeneralTreeContainer(item); + node.RefreshLevel(BindingTreeItems.Count + 1); + BindingTreeItems.Add(node); + } + } + + /// + /// 当前数据树中是否包含节点 + /// + /// 搜索的节点 + /// + public virtual bool HasItem(TNode node) + { + var itemsSource = GetDisplayNodes(); + return itemsSource.Any(t => t.TreeNode.IsSameNode(node)); + } + + /// + /// 获取树层级路径 + /// + /// + /// + public string GetTreeLevelPath(TNode node) + { + return GetDisplayNodes().FirstOrDefault(t => t.TreeNode.IsSameNode(node)).TreeLevelPath; + } + + /// + /// 获取当前数据树列表 + /// + /// + public virtual List GetSourceItems() + { + return GetDisplayNodes().Select(t => t.TreeNode).ToList(); + } + + /// + /// 根据获取其父节点列表,包含节点 + /// + /// 开始获取的入口节点 + public virtual List GetParentNodeList(TNode entryNode) + { + var disNodes = GetDisplayNodes(); + var tmpNode = disNodes.FirstOrDefault(t => t.TreeNode.IsSameNode(entryNode)); + if (tmpNode == null) + throw new ArgumentNullException("查询节点entryNode未找到"); + List parentList = new List() { tmpNode.TreeNode }; + var parent = tmpNode.ParentNode; + while (true) + { + if (parent == null) + break; + else + { + parentList.Add(parent.TreeNode); + parent = parent.ParentNode; + } + } + return parentList; + } + + /// + /// 根据更新整棵树, + /// 内部构建树会默认将的顶节点作为当前的root节点 + /// 请确保与已有树顶节点一致 + /// + /// 必须为包含顶节点的树型数据 + /// + public virtual void UpdateTreeNodes(IEnumerable treeNodeList) + { + var disNodes = GetDisplayNodes(); + var rootNode = GeneralTreeItemsManager.GetRootNode(treeNodeList); //传入数据顶节点 + var treeNodes = GeneralTreeItemsManager.BuildTree(treeNodeList); //传入数据构建树 + + if (BindingTreeItems.Count != 0 && !rootNode.IsSameParent(BindingTreeItems.First().TreeNode)) + throw new Exception("传入树与已有树顶节点不相同"); + else + { + foreach (var rootItem in treeNodes) + { + if (disNodes.Any(t => t.TreeNode.IsSameNode(rootItem.TreeNode))) + { + //在已有树中找到顶节点,则继续查询并更新下级子节点 + //获取子节点 + List> tmpSubNodes = new List>(rootItem.SubItems); + + while (tmpSubNodes.Count > 0) + { + var nodesArray = tmpSubNodes.ToArray(); + tmpSubNodes.Clear(); + //查找并添加新节点 + foreach (var item in nodesArray) + { + var parent = disNodes.FirstOrDefault(t => t.TreeNode.IsSubNode(item.TreeNode)); + var loadedNode = disNodes.FirstOrDefault(t => t.TreeNode.IsSameNode(item.TreeNode)); + if (loadedNode == null) + { + //未找到节点,表示为新增加节点 + item.ParentNode = parent; + parent.SubItems.Add(item); + } + else if (item.SubItems != null) + { + //添加子节点 + tmpSubNodes.AddRange(item.SubItems); + } + } + } + } + else + { + //未在已有树中找到顶节点,则直接添加 + BindingTreeItems.Add(rootItem); + } + } + } + } + + /// + /// 删除已有节点 + /// + /// 当子节点清空后,是否删除父节点 + /// 要删除的节点项 + public virtual void RemoveNode(bool isRemoveParentNode, params TNode[] delNodes) + { + + if (delNodes.Length < 1) + return; + List delNodeList = delNodes.ToList(); + for (int i = 0; i < BindingTreeItems.Count; i++) + { + if (delNodeList.Count == 0) + break; + var tmpDelNode = delNodeList.FirstOrDefault(t => t.IsSameNode(BindingTreeItems[i].TreeNode)); + if (tmpDelNode != null) + { + BindingTreeItems.RemoveAt(i); + delNodeList.Remove(tmpDelNode); + i--; + } + else + { + BindingTreeItems[i].RemoveSubNode(isRemoveParentNode, ref delNodeList); + if (isRemoveParentNode && BindingTreeItems[i].SubItems.Count < 1) + { + BindingTreeItems.RemoveAt(i); + i--; + } + } + } + } + + /// + /// 开始加载子项(通过ITreeBuilder接口调用) + /// + /// + protected virtual void DoLoadSubItems(TNode parentNode) { } + + #endregion + + + + #region 获取显示节点 + + /// + /// 获取已显示的节点列表 + /// + /// 需要查询的树,null表示查询BindingTreeItems + /// + public List> GetDisplayNodes(params GeneralTreeContainer[] parentNodes) + { + List> disNodes = new List>(); + if (parentNodes.Length == 0) + { + foreach (var item in BindingTreeItems) + { + disNodes.Add(item); + item.GetSubNodeList(ref disNodes); + } + } + else + { + foreach (var item in parentNodes) + { + disNodes.Add(item); + item.GetSubNodeList(ref disNodes); + } + } + return disNodes; + } + + /// + /// 获取Cheked条件的节点 + /// + /// 筛选条件 + /// + public List GetCheckedNodes(bool? TrueOrFalse) + { + return this.GetDisplayNodes().Where(w => w.IsChecked == TrueOrFalse).Select(s => s.TreeNode).ToList(); + } + + #endregion + #endregion + + #region 私有方法 + + #region TreeGrid选中状态变更 + + private void SetNodeCheckStateOfSubItem(GeneralTreeContainer curItem, bool isChecked) + { + curItem.IsChecked = isChecked; + if (curItem.SubItems != null) + foreach (var item in curItem.SubItems) + { + SetNodeCheckStateOfSubItem(item, isChecked); + } + } + + private void SetNodeCheckStateOfParentItem(GeneralTreeContainer curItem) + { + if (curItem.ParentNode != null) + { + var checkGroup = curItem.ParentNode.SubItems.GroupBy(t => t.IsChecked); + curItem.ParentNode.IsChecked = checkGroup.Count() > 1 ? null : checkGroup.First().First().IsChecked; + SetNodeCheckStateOfParentItem(curItem.ParentNode); + } + } + + public void CheckAndUpdateStateNode(object curNode, bool isChecked) + { + var disNodesList = GetDisplayNodes(); + var cur = disNodesList.FirstOrDefault(t => t.Equals(curNode)); + if (cur != null) + { + //刷新状态 + SetNodeCheckStateOfSubItem(cur, isChecked); + SetNodeCheckStateOfParentItem(cur); + + //更新全部选中状态 + var group = disNodesList.GroupBy(t => t.IsChecked); + CheckedAllNodes = group.Count() > 1 ? null : group.First().First().IsChecked; + } + } + + public void SetCheckStatusOfAllNodes(bool isChecked) + { + var disNodesList = GetDisplayNodes(); + disNodesList.ForEach(t => t.IsChecked = isChecked); + } + + public void SelectedCopyItemByCtrl(object selectedItem) + { + throw new NotImplementedException(); + } + + public void SelectedCopyItemByShift(object selectedItem) + { + throw new NotImplementedException(); + } + + public void ClearSelectedCopyItems(object selectedItem) + { + throw new NotImplementedException(); + } + + public void SearchAndLocationNode(string searchStr, bool searchOfDown = true) + { + throw new NotImplementedException(); + } + + public void BeginLoadSubItems(object parentNode) + { + DoLoadSubItems(parentNode as TNode); + } + + + + #endregion + + #endregion + + +} diff --git a/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/TreeBuilderByFullLoad.cs b/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/TreeBuilderByFullLoad.cs new file mode 100644 index 0000000000000000000000000000000000000000..e93a542d3eff7c1822a28c04c9ff122f56a344fb --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/TreeBuilderByFullLoad.cs @@ -0,0 +1,49 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: TreeBuilderByFullLoad +// 创建者: 杨程 +// 创建日期: 2022/11/21 16:51:21 + +//----------------------------------------------------------------*/ +#endregion + + + + + +namespace Vampirewal.Core.WpfTheme.CustomControl; + +/// +/// 全量加载树数据 +/// +public class TreeBuilderByFullLoad : TreeBuilderBase + where TSource : class, ITreeNode +{ + /// + /// 加载全数据节点 + /// + /// 节点数据集合 + public void LoadFullNodes(IEnumerable nodes) + { + BindingTreeItems.Clear(); + _sourceTreeNodes.Clear(); + if (nodes != null && nodes.Count() > 0) + { + var rootNodes = GeneralTreeItemsManager.BuildTree(nodes); + _sourceTreeNodes.AddRange(GeneralTreeItemsManager.BuildContainer(nodes)); + int tmpIndex = 1; + foreach (var item in rootNodes) + { + BindingTreeItems.Add(item); + item.RefreshLevel(tmpIndex); + tmpIndex++; + } + } + } +} diff --git a/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/TreeListView.cs b/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/TreeListView.cs new file mode 100644 index 0000000000000000000000000000000000000000..666304fd6c81f3bebb5548f9153038a37fad7f00 --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/TreeListView.cs @@ -0,0 +1,576 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: TreeListView +// 创建者: 杨程 +// 创建日期: 2022/11/17 11:30:41 + +//----------------------------------------------------------------*/ +#endregion + + + + + +namespace Vampirewal.Core.WpfTheme.CustomControl; + +/// +/// +/// +public class TreeListView : TreeView +{ + static TreeListView() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(TreeListView), new FrameworkPropertyMetadata(typeof(TreeListView))); + } + + private ResourceDictionary res + { + get + { + return new ResourceDictionary() { Source = new Uri("pack://application:,,,/Vampirewal.Core;component/WpfTheme/CoreTheme.xaml", UriKind.RelativeOrAbsolute) }; + } + } + + public TreeListView() + { + //构造函数 + //var TreeListViewStyle = res["TreeListViewStyle"] as Style; + + //this.Style = TreeListViewStyle; + + Columns = new GridViewColumnCollection(); + Columns.CollectionChanged += Columns_CollectionChanged; + } + + private void Columns_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + bool? isAddEvt = null; + if (e.Action == NotifyCollectionChangedAction.Add) + { + isAddEvt = true; + } + else if (e.Action == NotifyCollectionChangedAction.Remove) + { + isAddEvt = false; + } + if (isAddEvt.HasValue && isAddEvt.Value) + { + foreach (var item in e.NewItems) + { + if (item is TreeItemColumn tg) + { + tg.Evt_ColumnVisibleChanged -= Tg_Evt_ColumnVisibleChanged; + tg.Evt_ColumnVisibleChanged += Tg_Evt_ColumnVisibleChanged; + } + } + } + } + + private void Tg_Evt_ColumnVisibleChanged(DependencyObject arg1, bool isVisible) + { + /* + * TODO + * 目前控制不支持中途添加列 + * + */ + if (arg1 is TreeItemColumn tmpColumn) + { + //加载模板之前 + //if (_menuHeaderContainer == null) + // if (_initColumnVisibleState.Keys.Contains(tmpColumn.ColumnID)) + // _initColumnVisibleState[tmpColumn.ColumnID] = isVisible; + // else + // _initColumnVisibleState.Add(tmpColumn.ColumnID, isVisible); + //else + //{ + // UpdateColumnState(tmpColumn, isVisible); + //} + } + } + #region 依赖属性 + + + + public GridViewColumnCollection Columns + { + get { return (GridViewColumnCollection)GetValue(ColumnsProperty); } + set { SetValue(ColumnsProperty, value); } + } + + // Using a DependencyProperty as the backing store for Columns. This enables animation, styling, binding, etc... + public static readonly DependencyProperty ColumnsProperty = + DependencyProperty.Register("Columns", typeof(GridViewColumnCollection), typeof(TreeListView), new PropertyMetadata(null)); + + + public ITreeBuilder TreeBuilder + { + get { return (ITreeBuilder)GetValue(TreeBuilderProperty); } + set { SetValue(TreeBuilderProperty, value); } + } + + // Using a DependencyProperty as the backing store for TreeBuilder. This enables animation, styling, binding, etc... + public static readonly DependencyProperty TreeBuilderProperty = + DependencyProperty.Register("TreeBuilder", typeof(ITreeBuilder), typeof(TreeListView), new PropertyMetadata(null, DynamicItemsChanged)); + + private static void DynamicItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is TreeListView tg) + tg.RegisterDynamicItemsChangedEvent(); + } + + internal void RegisterDynamicItemsChangedEvent() + { + //TreeBuilder.SetCallback(TreeBuilder_Evt_DynamicInnerElementChanged); + //TreeBuilder.Evt_DynamicInnerElementChanged -= TreeBuilder_Evt_DynamicInnerElementChanged; + //TreeBuilder.Evt_SelectedNode -= TreeBuilder_Evt_SelectedNode; + //TreeBuilder.Evt_CheckNodes -= TreeBuilder_Evt_CheckNodes; + + //TreeBuilder.Evt_DynamicInnerElementChanged += TreeBuilder_Evt_DynamicInnerElementChanged; + //TreeBuilder.Evt_SelectedNode += TreeBuilder_Evt_SelectedNode; + //TreeBuilder.Evt_CheckNodes += TreeBuilder_Evt_CheckNodes; + //InsertOrReplaceFirstColumn(); + } + + + #region 当前选中项 + + public object SelectedItemEx + { + get { return (object)GetValue(SelectedItemExProperty); } + set { SetValue(SelectedItemExProperty, value); } + } + + // Using a DependencyProperty as the backing store for SelectedItemEx. This enables animation, styling, binding, etc... + public static readonly DependencyProperty SelectedItemExProperty = + DependencyProperty.Register("SelectedItemEx", typeof(object), typeof(TreeListView), new PropertyMetadata(null)); + + #endregion + + #region 圆角 + + + //public CornerRadius TreeCornerRadius + //{ + // get { return (CornerRadius)GetValue(TreeCornerRadiusProperty); } + // set { SetValue(TreeCornerRadiusProperty, value); } + //} + + //// Using a DependencyProperty as the backing store for TreeCornerRadius. This enables animation, styling, binding, etc... + //public static readonly DependencyProperty TreeCornerRadiusProperty = + // DependencyProperty.Register("TreeCornerRadius", typeof(CornerRadius), typeof(TreeListView), new PropertyMetadata(0)); + + + #endregion + + #endregion + + + //这两个默认的是TreeViewItem + protected override DependencyObject GetContainerForItemOverride()//创建或标识用于显示指定项的元素。 + { + return new TreeListViewItem(); + } + + protected override bool IsItemItsOwnContainerOverride(object item)//确定指定项是否是(或可作为)其自己的 ItemContainer + { + //return item is TreeListViewItem; + bool _isTreeLVI = item is TreeListViewItem; + return _isTreeLVI; + } + + /// + /// 首列 + /// + public FirstColumn FirstColumnInfo { get; set; } + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + //GridViewColumn + if (FirstColumnInfo == null) + { + throw new NullReferenceException("FirstColumnBindingPath为必要属性,不能为null"); + } + + InsertOrReplaceFirstColumn(); + + AddHandler(TreeListViewItem.SelectedEvent, new RoutedEventHandler(TreeListViewItemSelectedCallback)); + } + + private void TreeListViewItemSelectedCallback(object sender, RoutedEventArgs e) + { + if (e.OriginalSource is TreeListViewItem tgi) + { + SelectedItemEx = tgi.DataContext; + //if (AllowPaste) + //{ + // if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) + // TreeBuilder.SelectedCopyItemByCtrl(tgi.DataContext); + // else if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift)) + // TreeBuilder.SelectedCopyItemByShift(tgi.DataContext); + // else + // TreeBuilder.ClearSelectedCopyItems(tgi.DataContext); + //} + } + } + + /// + /// 插入第一列,如果已经有第一列,则替换 + /// + private void InsertOrReplaceFirstColumn() + { + //if (Columns.Count > 0 && Columns[0] is GridViewColumn) + // return; + Columns.Insert(0, CreateFirstColumnOfRowIndexEx()); + //if (_menuHeaderContainer != null) + //{ + // var firstColumnCb = CreateCheckBoxInMenu(FirstColumnInfo.HeaderDisplayValue, Guid.Empty); + // firstColumnCb.IsEnabled = false; + // _menuHeaderContainer.Children.Insert(0, firstColumnCb); + //} + } + + + private CheckBox _headerCb; + /// + /// 创建首列 + /// + /// + private GridViewColumn CreateFirstColumnOfRowIndexEx() + { + GridViewColumn firstColumn = new GridViewColumn(); + firstColumn.Width = FirstColumnInfo.HeaderWidth; + firstColumn.HeaderContainerStyle = Template.Resources["FirstHeaderStyle"] as Style; + + #region 创建带复选框的列头 + StackPanel header = new StackPanel(); + header.Orientation = Orientation.Horizontal; + header.HorizontalAlignment = HorizontalAlignment.Center; + if (FirstColumnInfo.HasCheckBox) + { + _headerCb = new CheckBox() + { + Margin = new Thickness(3, 0, 5, 0), + }; + _headerCb.Click += _headerCb_Click; ; + header.Children.Add(_headerCb); + } + TextBlock headerText = new TextBlock() + { + Text = FirstColumnInfo.HeaderDisplayValue, + }; + header.Children.Add(headerText); + firstColumn.Header = header; + #endregion + + FrameworkElementFactory firstContainer = null; + if (FirstColumnInfo is AutoCodeFirstColumn auto) + { + firstContainer = CreateAutoCodeCellTempalte(auto); + } + else if (FirstColumnInfo is CustromFirstColumn cus) + { + firstContainer = CreateCustromCellTempalte(cus); + } + + firstColumn.CellTemplate = new DataTemplate() { VisualTree = firstContainer }; + return firstColumn; + } + + private void _headerCb_Click(object sender, RoutedEventArgs e) + { + if (sender is CheckBox cb && cb.IsChecked.HasValue) + { + TreeBuilder?.SetCheckStatusOfAllNodes(cb.IsChecked.Value); + } + + } + + /// + /// 创建自动序号的首列 + /// + /// + /// + private FrameworkElementFactory CreateAutoCodeCellTempalte(AutoCodeFirstColumn autoColumn) + { + FrameworkElementFactory firstContainer = new FrameworkElementFactory(typeof(DockPanel)); + firstContainer.SetValue(DockPanel.BackgroundProperty, Brushes.Transparent); + + #region 创建折叠按钮 + FrameworkElementFactory tgb = new FrameworkElementFactory(typeof(ToggleButton)); + tgb.SetValue(ToggleButton.WidthProperty, 19d); + tgb.SetValue(ToggleButton.HeightProperty, 13d); + tgb.SetValue(ToggleButton.StyleProperty, res["ExpandCollapseToggleStyle"] as Style); + + Binding tgbMarginBind = new Binding("Level"); + tgbMarginBind.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor); + tgbMarginBind.RelativeSource.AncestorType = typeof(TreeViewItem); + tgbMarginBind.Converter = new LevelToIndentConverter(); + tgb.SetBinding(ToggleButton.MarginProperty, tgbMarginBind); + + Binding checkBind = new Binding("IsExpanded"); + checkBind.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor); + checkBind.RelativeSource.AncestorType = typeof(TreeViewItem); + tgb.SetBinding(ToggleButton.IsCheckedProperty, checkBind); + + Binding visibleBind = new Binding("HasItems"); + visibleBind.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor); + visibleBind.RelativeSource.AncestorType = typeof(TreeViewItem); + visibleBind.Converter = new BoolToHideConverter(); + tgb.SetBinding(ToggleButton.VisibilityProperty, visibleBind); + firstContainer.AppendChild(tgb); + #endregion + + Binding headerBind = new Binding("TreeLevelPath"); + if (autoColumn.HasCheckBox) + { + var firstCellTemplateOfCheckBox = new FrameworkElementFactory(typeof(CheckBox)); + firstCellTemplateOfCheckBox.SetValue(CheckBox.ForegroundProperty, autoColumn.Foreground); + firstCellTemplateOfCheckBox.SetValue(CheckBox.MarginProperty, new Thickness(10, 0, 0, 0)); + firstCellTemplateOfCheckBox.SetValue(CheckBox.VerticalContentAlignmentProperty, VerticalAlignment.Center); + firstCellTemplateOfCheckBox.SetValue(CheckBox.VerticalAlignmentProperty, autoColumn.VerticalAlignment); + firstCellTemplateOfCheckBox.SetValue(CheckBox.HorizontalAlignmentProperty, autoColumn.HorizontalAlignment); + firstCellTemplateOfCheckBox.AddHandler(CheckBox.CheckedEvent, new RoutedEventHandler(Click_Checked)); + firstCellTemplateOfCheckBox.AddHandler(CheckBox.UncheckedEvent, new RoutedEventHandler(Click_Checked)); + //firstCellTemplateOfCheckBox.AddHandler(CheckBox.ClickEvent, new RoutedEventHandler(Click_Checked)); + firstCellTemplateOfCheckBox.SetBinding(CheckBox.ContentProperty, headerBind); + #region 为CheckBox创建选择绑定 + Binding cbBind = new Binding("IsChecked"); + cbBind.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; + cbBind.Mode = BindingMode.TwoWay; + firstCellTemplateOfCheckBox.SetBinding(CheckBox.IsCheckedProperty, cbBind); + firstContainer.AppendChild(firstCellTemplateOfCheckBox); + #endregion + } + else if (autoColumn.UseAutoCode) + { + var firstCellTemplate = new FrameworkElementFactory(typeof(TextBlock)); + firstCellTemplate.SetValue(TextBlock.ForegroundProperty, FirstColumnInfo.Foreground); + firstCellTemplate.SetValue(TextBlock.MarginProperty, new Thickness(10, 0, 0, 0)); + firstCellTemplate.SetValue(TextBlock.VerticalAlignmentProperty, FirstColumnInfo.VerticalAlignment); + firstCellTemplate.SetValue(TextBlock.HorizontalAlignmentProperty, FirstColumnInfo.HorizontalAlignment); + firstCellTemplate.SetBinding(TextBlock.TextProperty, headerBind); + firstContainer.AppendChild(firstCellTemplate); + } + return firstContainer; + } + + /// + /// 创建自定义首列 + /// + /// + /// + private FrameworkElementFactory CreateCustromCellTempalte(CustromFirstColumn cusColumn) + { + FrameworkElementFactory firstContainer = new FrameworkElementFactory(typeof(DockPanel)); + firstContainer.SetValue(DockPanel.BackgroundProperty, Brushes.Transparent); + FrameworkElementFactory firstCellTemplateOfCheckBox = null; + FrameworkElementFactory firstCellTemplate = null; + #region 创建折叠按钮 + FrameworkElementFactory tgb = new FrameworkElementFactory(typeof(ToggleButton)); + tgb.SetValue(ToggleButton.WidthProperty, 19d); + tgb.SetValue(ToggleButton.HeightProperty, 13d); + tgb.SetValue(ToggleButton.StyleProperty, res["ExpandCollapseToggleStyle"] as Style); + + Binding tgbMarginBind = new Binding("Level"); + tgbMarginBind.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor); + tgbMarginBind.RelativeSource.AncestorType = typeof(TreeViewItem); + tgbMarginBind.Converter = new LevelToIndentConverter(); + tgb.SetBinding(ToggleButton.MarginProperty, tgbMarginBind); + + Binding checkBind = new Binding("IsExpanded"); + checkBind.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor); + checkBind.RelativeSource.AncestorType = typeof(TreeViewItem); + tgb.SetBinding(ToggleButton.IsCheckedProperty, checkBind); + + Binding visibleBind = new Binding("HasItems"); + visibleBind.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor); + visibleBind.RelativeSource.AncestorType = typeof(TreeViewItem); + visibleBind.Converter = new BoolToHideConverter(); + tgb.SetBinding(ToggleButton.VisibilityProperty, visibleBind); + firstContainer.AppendChild(tgb); + #endregion + + if (cusColumn.HasCheckBox) + { + firstCellTemplateOfCheckBox = new FrameworkElementFactory(typeof(CheckBox)); + firstCellTemplateOfCheckBox.SetValue(CheckBox.ForegroundProperty, cusColumn.Foreground); + firstCellTemplateOfCheckBox.SetValue(CheckBox.MarginProperty, new Thickness(10, 0, 0, 0)); + firstCellTemplateOfCheckBox.SetValue(CheckBox.VerticalContentAlignmentProperty, VerticalAlignment.Center); + firstCellTemplateOfCheckBox.SetValue(CheckBox.VerticalAlignmentProperty, cusColumn.VerticalAlignment); + firstCellTemplateOfCheckBox.SetValue(CheckBox.HorizontalAlignmentProperty, cusColumn.HorizontalAlignment); + firstCellTemplateOfCheckBox.AddHandler(CheckBox.CheckedEvent, new RoutedEventHandler(Click_Checked)); + firstCellTemplateOfCheckBox.AddHandler(CheckBox.UncheckedEvent, new RoutedEventHandler(Click_Checked)); + //firstCellTemplateOfCheckBox.AddHandler(CheckBox.ClickEvent, new RoutedEventHandler(Click_Checked)); + //firstCellTemplateOfCheckBox.SetBinding(CheckBox.ContentProperty, headerBind); + #region 为CheckBox创建选择绑定 + Binding cbBind = new Binding("IsChecked"); + cbBind.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; + cbBind.Mode = BindingMode.TwoWay; + firstCellTemplateOfCheckBox.SetBinding(CheckBox.IsCheckedProperty, cbBind); + firstContainer.AppendChild(firstCellTemplateOfCheckBox); + #endregion + } + Binding headerBind = new Binding($"DataContext.TreeNode.{cusColumn.FirstColumnBindingPath}"); + headerBind.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor); + headerBind.RelativeSource.AncestorType = typeof(TreeViewItem); + headerBind.Converter = cusColumn.Converter; + if (cusColumn.IsReadOnly) + { + firstCellTemplate = new FrameworkElementFactory(typeof(TextBlock)); + firstCellTemplate.SetValue(TextBlock.ForegroundProperty, cusColumn.Foreground); + firstCellTemplate.SetValue(TextBlock.MarginProperty, new Thickness(10, 0, 0, 0)); + firstCellTemplate.SetValue(TextBlock.VerticalAlignmentProperty, cusColumn.VerticalAlignment); + firstCellTemplate.SetValue(TextBlock.HorizontalAlignmentProperty, cusColumn.HorizontalAlignment); + firstCellTemplate.SetBinding(TextBlock.TextProperty, headerBind); + } + else + { + headerBind.NotifyOnSourceUpdated = true; + firstCellTemplate = new FrameworkElementFactory(typeof(TextBox)); + firstCellTemplate.SetValue(TextBox.ForegroundProperty, cusColumn.Foreground); + firstCellTemplate.SetValue(TextBox.MarginProperty, new Thickness(10, 0, 0, 0)); + firstCellTemplate.SetValue(TextBox.VerticalAlignmentProperty, cusColumn.VerticalAlignment); + firstCellTemplate.SetValue(TextBox.HorizontalAlignmentProperty, cusColumn.HorizontalAlignment); + firstCellTemplate.AddHandler(TextBox.LoadedEvent, new RoutedEventHandler(FirstColumnLoadedCallback)); + firstCellTemplate.SetBinding(TextBox.TextProperty, headerBind); + if (cusColumn.JustEditDetailItem) + { + Binding editBind = new Binding("HasItems"); + editBind.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor); + editBind.RelativeSource.AncestorType = typeof(TreeListViewItem); + firstCellTemplate.SetBinding(TextBox.IsReadOnlyProperty, editBind); + } + } + firstContainer.AppendChild(firstCellTemplate); + return firstContainer; + } + + private void FirstColumnLoadedCallback(object sender, RoutedEventArgs e) + { + if (sender is TextBox tb) + { + tb.SourceUpdated -= Tb_SourceUpdated1; + tb.SourceUpdated += Tb_SourceUpdated1; + } + } + + private void Tb_SourceUpdated1(object sender, DataTransferEventArgs e) + { + if (sender is TextBox tb + && FirstColumnInfo is CustromFirstColumn ctrColumn + && ctrColumn.FirstColumnSourceUpdateCommand != null) + { + var data = tb.DataContext.GetType().GetProperty("TreeNode").GetValue(tb.DataContext, null); + ctrColumn.FirstColumnSourceUpdateCommand.Execute(data); + } + } + + private void Click_Checked(object sender, RoutedEventArgs e) + { + if (sender is CheckBox cb && cb.IsChecked.HasValue) + { + TreeBuilder?.CheckAndUpdateStateNode(cb.DataContext, cb.IsChecked.Value); + } + + _headerCb.IsChecked = TreeBuilder.CheckedAllNodes; + } +} + +public class TreeListViewItem : TreeViewItem +{ + static TreeListViewItem() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(TreeListViewItem), new FrameworkPropertyMetadata(typeof(TreeListViewItem))); + } + + /// + /// hierarchy + /// + public int Level + { + get + { + if (_level == -1) + { + TreeListViewItem parent = ItemsControl.ItemsControlFromItemContainer(this) as TreeListViewItem;//返回拥有指定的容器元素中 ItemsControl 。 + _level = (parent != null) ? parent.Level + 1 : 0; + } + return _level; + } + } + + + protected override DependencyObject GetContainerForItemOverride() + { + TreeListViewItem item = new TreeListViewItem(); + item.ParentNode = this; + return item; + } + + protected override bool IsItemItsOwnContainerOverride(object item) + { + //return item is TreeListViewItem; + bool _isITV = item is TreeListViewItem; + return _isITV; + } + + private int _level = -1; + + #region 父节点 + /// + /// 父节点 + /// + internal TreeListViewItem ParentNode { get; set; } + #endregion +} + +/// +/// 树形节点列 +/// +public class TreeItemColumn : GridViewColumn +{ + public event Action Evt_ColumnVisibleChanged; + + public TreeItemColumn() + { + ColumnID = Guid.NewGuid(); + } + + /// + /// 列的别名,用于筛选 + /// + public string Alias { get; set; } + /// + /// 列的唯一标识 + /// + internal Guid ColumnID { get; } + + #region 是否显示列 + /// + /// 是否显示 + /// + public bool IsVisible + { + get { return (bool)GetValue(IsVisibleProperty); } + set { SetValue(IsVisibleProperty, value); } + } + + // Using a DependencyProperty as the backing store for IsVisible. This enables animation, styling, binding, etc... + public static readonly DependencyProperty IsVisibleProperty = + DependencyProperty.Register("IsVisible", typeof(bool), typeof(TreeItemColumn), new PropertyMetadata(true, VisibleChangedCallback)); + + private static void VisibleChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is TreeItemColumn tg) + tg.Evt_ColumnVisibleChanged?.Invoke(d, (bool)e.NewValue); + } + #endregion +} + diff --git a/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/TreeListViewStyle.xaml b/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/TreeListViewStyle.xaml new file mode 100644 index 0000000000000000000000000000000000000000..5c58b4a76116a876b1e164507fd62b2631f02e97 --- /dev/null +++ b/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/TreeListViewStyle.xaml @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + #F8F8FF + #DCDCDC + + + + + + + + + + \ No newline at end of file diff --git a/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/list_header_bk.png b/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/list_header_bk.png new file mode 100644 index 0000000000000000000000000000000000000000..df1f48933b959d9ecd66238f10ce976cea902e88 Binary files /dev/null and b/Vampirewal.Core/WpfTheme/CustomControl/TreeListView/list_header_bk.png differ diff --git a/Vampirewal.Core/WpfTheme/GridLengthAnimation.cs b/Vampirewal.Core/WpfTheme/GridLengthAnimation.cs index 03af2c3a2ea58c250dfa1b01b4c2d84f3b4be3b4..5990dcd12e79d4d7cc463e4917a0a516ecbb749f 100644 --- a/Vampirewal.Core/WpfTheme/GridLengthAnimation.cs +++ b/Vampirewal.Core/WpfTheme/GridLengthAnimation.cs @@ -11,130 +11,124 @@ //----------------------------------------------------------------*/ #endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Media.Animation; -using System.Windows; - -namespace Vampirewal.Core.WpfTheme + + + +namespace Vampirewal.Core.WpfTheme; + +/// +/// +/// +public class GridLengthAnimation : AnimationTimeline { - /// - /// - /// - public class GridLengthAnimation : AnimationTimeline + static GridLengthAnimation() + { + FromProperty = DependencyProperty.Register("From", typeof(GridLength), typeof(GridLengthAnimation)); + ToProperty = DependencyProperty.Register("To", typeof(GridLength), typeof(GridLengthAnimation)); + } + + public static readonly DependencyProperty FromProperty; + public GridLength From { - static GridLengthAnimation() + get { - FromProperty = DependencyProperty.Register("From", typeof(GridLength), typeof(GridLengthAnimation)); - ToProperty = DependencyProperty.Register("To", typeof(GridLength), typeof(GridLengthAnimation)); + return (GridLength)GetValue(GridLengthAnimation.FromProperty); } - - public static readonly DependencyProperty FromProperty; - public GridLength From + set { - get - { - return (GridLength)GetValue(GridLengthAnimation.FromProperty); - } - set - { - SetValue(GridLengthAnimation.FromProperty, value); - } + SetValue(GridLengthAnimation.FromProperty, value); } + } - public static readonly DependencyProperty ToProperty; - public GridLength To + public static readonly DependencyProperty ToProperty; + public GridLength To + { + get { - get - { - return (GridLength)GetValue(GridLengthAnimation.ToProperty); - } - set - { - SetValue(GridLengthAnimation.ToProperty, value); - } + return (GridLength)GetValue(GridLengthAnimation.ToProperty); } - - public override Type TargetPropertyType + set { - get - { - return typeof(GridLength); - } + SetValue(GridLengthAnimation.ToProperty, value); } + } - protected override System.Windows.Freezable CreateInstanceCore() + public override Type TargetPropertyType + { + get { - return new GridLengthAnimation(); + return typeof(GridLength); } + } - public override object GetCurrentValue(object defaultOriginValue, - object defaultDestinationValue, AnimationClock animationClock) + protected override System.Windows.Freezable CreateInstanceCore() + { + return new GridLengthAnimation(); + } + + public override object GetCurrentValue(object defaultOriginValue, + object defaultDestinationValue, AnimationClock animationClock) + { + double fromVal = ((GridLength)GetValue(GridLengthAnimation.FromProperty)).Value; + double toVal = ((GridLength)GetValue(GridLengthAnimation.ToProperty)).Value; + + if (fromVal > toVal) { - double fromVal = ((GridLength)GetValue(GridLengthAnimation.FromProperty)).Value; - double toVal = ((GridLength)GetValue(GridLengthAnimation.ToProperty)).Value; - - if (fromVal > toVal) - { - return new GridLength((1 - animationClock.CurrentProgress.Value) * (fromVal - toVal) + toVal, - ((GridLength)GetValue(GridLengthAnimation.FromProperty)).GridUnitType); - } - else - return new GridLength(animationClock.CurrentProgress.Value * (toVal - fromVal) + fromVal, - ((GridLength)GetValue(GridLengthAnimation.ToProperty)).GridUnitType); + return new GridLength((1 - animationClock.CurrentProgress.Value) * (fromVal - toVal) + toVal, + ((GridLength)GetValue(GridLengthAnimation.FromProperty)).GridUnitType); } + else + return new GridLength(animationClock.CurrentProgress.Value * (toVal - fromVal) + fromVal, + ((GridLength)GetValue(GridLengthAnimation.ToProperty)).GridUnitType); + } - //public override object GetCurrentValue(object defaultOriginValue, object defaultDestinationValue, AnimationClock animationClock) - //{ - // double fromVal = ((GridLength)GetValue(FromProperty)).Value; - // double toVal = ((GridLength)GetValue(ToProperty)).Value; - // double progress = animationClock.CurrentProgress.Value; + //public override object GetCurrentValue(object defaultOriginValue, object defaultDestinationValue, AnimationClock animationClock) + //{ + // double fromVal = ((GridLength)GetValue(FromProperty)).Value; + // double toVal = ((GridLength)GetValue(ToProperty)).Value; + // double progress = animationClock.CurrentProgress.Value; - // IEasingFunction easingFunction = EasingFunction; - // if (easingFunction != null) - // { - // progress = easingFunction.Ease(progress); - // } + // IEasingFunction easingFunction = EasingFunction; + // if (easingFunction != null) + // { + // progress = easingFunction.Ease(progress); + // } - // if (fromVal > toVal) - // return new GridLength((1 - progress) * (fromVal - toVal) + toVal, GridUnitType.Star); + // if (fromVal > toVal) + // return new GridLength((1 - progress) * (fromVal - toVal) + toVal, GridUnitType.Star); - // return new GridLength(progress * (toVal - fromVal) + fromVal, GridUnitType.Star); - //} + // return new GridLength(progress * (toVal - fromVal) + fromVal, GridUnitType.Star); + //} - /// - /// The dependency property's name. - /// - public const string EasingFunctionPropertyName = "EasingFunction"; + /// + /// The dependency property's name. + /// + public const string EasingFunctionPropertyName = "EasingFunction"; - /// - /// Gets or sets the value of the - /// property. This is a dependency property. - /// - public IEasingFunction EasingFunction + /// + /// Gets or sets the value of the + /// property. This is a dependency property. + /// + public IEasingFunction EasingFunction + { + get + { + return (IEasingFunction)GetValue(EasingFunctionProperty); + } + set { - get - { - return (IEasingFunction)GetValue(EasingFunctionProperty); - } - set - { - SetValue(EasingFunctionProperty, value); - } + SetValue(EasingFunctionProperty, value); } + } - /// - /// Identifies the dependency property. - /// - public static readonly DependencyProperty EasingFunctionProperty = DependencyProperty.Register( - EasingFunctionPropertyName, - typeof(IEasingFunction), - typeof(GridLengthAnimation), - new UIPropertyMetadata(null)); + /// + /// Identifies the dependency property. + /// + public static readonly DependencyProperty EasingFunctionProperty = DependencyProperty.Register( + EasingFunctionPropertyName, + typeof(IEasingFunction), + typeof(GridLengthAnimation), + new UIPropertyMetadata(null)); - } } diff --git a/Vampirewal.Core/WpfTheme/UcView/AddOrEditUcViewBase.cs b/Vampirewal.Core/WpfTheme/UcView/AddOrEditUcViewBase.cs index 81e58406778777c1db27b5367effc4e878c61c3f..6f30192db7679587eb0529dfb9a80078cd9c8e56 100644 --- a/Vampirewal.Core/WpfTheme/UcView/AddOrEditUcViewBase.cs +++ b/Vampirewal.Core/WpfTheme/UcView/AddOrEditUcViewBase.cs @@ -11,81 +11,65 @@ //----------------------------------------------------------------*/ #endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -namespace Vampirewal.Core.WpfTheme.UcView + +namespace Vampirewal.Core.WpfTheme.UcView; + +/// +/// 新增或修改页面基类 +/// +public class AddOrEditUcViewBase:UcViewBase { + #region 界面 + + #region 底部 + /// + /// 底部模块菜单 + /// + public List BottomBtnItems { get; set; } = new List(); + #endregion + + #endregion + static AddOrEditUcViewBase() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(AddOrEditUcViewBase), new FrameworkPropertyMetadata(typeof(AddOrEditUcViewBase))); + } /// - /// 新增或修改页面基类 + /// 构造函数 /// - public class AddOrEditUcViewBase:UcViewBase + public AddOrEditUcViewBase() { - #region 界面 + //构造函数 - #region 底部 - /// - /// 底部模块菜单 - /// - public List BottomBtnItems { get; set; } = new List(); - #endregion + var AddOrEditUcViewBaseStyle = base.res["AddOrEditUcViewBase"] as Style; - #endregion - static AddOrEditUcViewBase() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(AddOrEditUcViewBase), new FrameworkPropertyMetadata(typeof(AddOrEditUcViewBase))); - } - /// - /// 构造函数 - /// - public AddOrEditUcViewBase() - { - //构造函数 + this.Style = AddOrEditUcViewBaseStyle; + } - var AddOrEditUcViewBaseStyle = base.res["AddOrEditUcViewBase"] as Style; + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); - this.Style = AddOrEditUcViewBaseStyle; - } + var BottomCustomArea = this.Template.FindName("BottomItems", this) as StackPanel; + var Bottoms=this.Template.FindName("Bottom",this) as RowDefinition; - public override void OnApplyTemplate() + if (BottomBtnItems.Count > 0) { - base.OnApplyTemplate(); - - var BottomCustomArea = this.Template.FindName("BottomItems", this) as StackPanel; - - if (BottomBtnItems.Count > 0) + //BottomCustomArea.Height = 50; + foreach (var item in BottomBtnItems) { - //BottomCustomArea.Height = 50; - foreach (var item in BottomBtnItems) - { - BottomCustomArea.Children.Add(item); - } + BottomCustomArea.Children.Add(item); } } + else + { + Bottoms.Height = new GridLength(0); + } + } - #region 属性 - - #endregion - - #region 公共方法 - - #endregion - - #region 私有方法 - - #endregion - - #region 命令 - - #endregion + - #region 依赖属性 + #region 依赖属性 - #endregion - } + #endregion } diff --git a/Vampirewal.Core/WpfTheme/UcView/LayoutGeneralListViewBase.cs b/Vampirewal.Core/WpfTheme/UcView/LayoutGeneralListViewBase.cs new file mode 100644 index 0000000000000000000000000000000000000000..77b4918aec48a571a7e3aa594f6c400bf9258535 --- /dev/null +++ b/Vampirewal.Core/WpfTheme/UcView/LayoutGeneralListViewBase.cs @@ -0,0 +1,77 @@ + +#region 文件信息 +/*---------------------------------------------------------------- +// +// 文件名称: +// 文件功能描述: +// 设计要求: +// +// 文 件 名: LayoutGeneralListViewBase +// 创建者: 杨程 +// 创建日期: 2022/12/23 12:44:41 + +//----------------------------------------------------------------*/ +#endregion + + + + +namespace Vampirewal.Core.WpfTheme.UcView; + +/// +/// +/// +public partial class LayoutGeneralListViewBase : UcViewBase +{ + /// + /// 底部区域 + /// + public UIElement BottomArea { get; set; } + + /// + /// 拖动条样式 + /// + public ControlTemplate GridSplitterStyle { get; set; } + + + static LayoutGeneralListViewBase() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(LayoutGeneralListViewBase), new FrameworkPropertyMetadata(typeof(LayoutGeneralListViewBase))); + } + /// + /// + /// + public LayoutGeneralListViewBase() + { + //构造函数 + var LayoutGeneralListViewBaseStyle = base.res["LayoutGeneralListViewBase"] as Style; + + this.Style = LayoutGeneralListViewBaseStyle; + } + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + #region 拖动条设置 + var GS = this.Template.FindName("gs", this) as GridSplitter; + + #region 自定义GridSplitter模版 + if (GridSplitterStyle != null) + { + if (GridSplitterStyle.TargetType == typeof(GridSplitter)) + { + GS.Template = GridSplitterStyle; + } + } + #endregion + + #endregion + var bottomarea = this.Template.FindName("BottomArea1", this) as ContentPresenter; + if (BottomArea == null) + { + GS.Visibility = Visibility.Collapsed; + bottomarea.Visibility = Visibility.Collapsed; + } + } +} diff --git a/Vampirewal.Core/WpfTheme/UcView/LayoutUcViewBase.cs b/Vampirewal.Core/WpfTheme/UcView/LayoutUcViewBase.cs index 6ec37a094dea671c1d5534dee9a20705a6c834c4..351cddf8efab1c8ec2c24a0c1c11f6ab21f6aa13 100644 --- a/Vampirewal.Core/WpfTheme/UcView/LayoutUcViewBase.cs +++ b/Vampirewal.Core/WpfTheme/UcView/LayoutUcViewBase.cs @@ -11,82 +11,75 @@ //----------------------------------------------------------------*/ #endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; - -namespace Vampirewal.Core.WpfTheme.UcView + + + +namespace Vampirewal.Core.WpfTheme.UcView; + +/// +/// 页面布局基类 +/// +public class LayoutUcViewBase:UcViewBase { + public UIElement BottomArea { get; set; } + /// - /// 页面布局基类 + /// 拖动条样式 /// - public class LayoutUcViewBase:UcViewBase + public ControlTemplate GridSplitterStyle { get; set; } + + static LayoutUcViewBase() { - public UIElement BottomArea { get; set; } + DefaultStyleKeyProperty.OverrideMetadata(typeof(LayoutUcViewBase), new FrameworkPropertyMetadata(typeof(LayoutUcViewBase))); + } - /// - /// 拖动条样式 - /// - public ControlTemplate GridSplitterStyle { get; set; } + public LayoutUcViewBase() + { + //构造函数 + var LayoutUcViewBaseStyle = base.res["LayoutUcViewBase"] as Style; - static LayoutUcViewBase() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(LayoutUcViewBase), new FrameworkPropertyMetadata(typeof(LayoutUcViewBase))); - } + this.Style = LayoutUcViewBaseStyle; + } - public LayoutUcViewBase() - { - //构造函数 - var LayoutUcViewBaseStyle = base.res["LayoutUcViewBase"] as Style; + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); - this.Style = LayoutUcViewBaseStyle; - } + #region 拖动条设置 + var GS = this.Template.FindName("gs", this) as GridSplitter; - public override void OnApplyTemplate() + #region 自定义GridSplitter模版 + if (GridSplitterStyle != null) { - base.OnApplyTemplate(); - - - - #region 拖动条设置 - var GS = this.Template.FindName("gs", this) as GridSplitter; - - #region 自定义GridSplitter模版 - if (GridSplitterStyle != null) - { - if (GridSplitterStyle.TargetType == typeof(GridSplitter)) - { - GS.Template = GridSplitterStyle; - } - } - #endregion - #endregion - var bottomarea = this.Template.FindName("BottomArea1", this) as ContentPresenter; - if (BottomArea == null) + if (GridSplitterStyle.TargetType == typeof(GridSplitter)) { - GS.Visibility = Visibility.Collapsed; - bottomarea.Visibility = Visibility.Collapsed; + GS.Template = GridSplitterStyle; } } - - #region 属性 + #endregion #endregion + var bottomarea = this.Template.FindName("BottomArea1", this) as ContentPresenter; + if (BottomArea == null) + { + GS.Visibility = Visibility.Collapsed; + bottomarea.Visibility = Visibility.Collapsed; + } + } - #region 公共方法 + #region 属性 - #endregion + #endregion - #region 私有方法 + #region 公共方法 - #endregion + #endregion - #region 命令 + #region 私有方法 - #endregion - } + #endregion + + #region 命令 + + #endregion } diff --git a/Vampirewal.Core/WpfTheme/UcView/TopLeftRightUcViewBase.cs b/Vampirewal.Core/WpfTheme/UcView/TopLeftRightUcViewBase.cs index 4c6aeec113727878e083eb6bc5d25cc3feafd26c..a1822725dc03b7a73aec6a46242034bb391d64e8 100644 --- a/Vampirewal.Core/WpfTheme/UcView/TopLeftRightUcViewBase.cs +++ b/Vampirewal.Core/WpfTheme/UcView/TopLeftRightUcViewBase.cs @@ -11,104 +11,96 @@ //----------------------------------------------------------------*/ #endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; - -namespace Vampirewal.Core.WpfTheme.UcView + + + +namespace Vampirewal.Core.WpfTheme.UcView; + +/// +/// 上(主模块)=>左(模块菜单)=>右(主内容)布局;适用于MainView +/// +public class TopLeftRightUcViewBase:UcViewBase { + #region 界面元素 + + #region 顶部 + /// + /// 顶部模块菜单 + /// + public List TopBtnItems { get; set; } = new List(); + #endregion + + #region 左侧 + /// + /// 左侧功能菜单区域 + /// + public UIElement LeftMenuArea { get; set; } + #endregion + + #endregion /// - /// 上(主模块)=>左(模块菜单)=>右(主内容)布局;适用于MainView + /// 构造函数 /// - public class TopLeftRightUcViewBase:UcViewBase + public TopLeftRightUcViewBase() { - #region 界面元素 - - #region 顶部 - /// - /// 顶部模块菜单 - /// - public List TopBtnItems { get; set; } = new List(); - #endregion - - #region 左侧 - /// - /// 左侧功能菜单区域 - /// - public UIElement LeftMenuArea { get; set; } - #endregion - - #endregion - /// - /// 构造函数 - /// - public TopLeftRightUcViewBase() - { - //构造函数 - - - //获取样式 - var TopLeftRightUcViewBaseStyle = base.res["TopLeftRightUcViewBase"] as Style; - - this.Style = TopLeftRightUcViewBaseStyle; - } - - static TopLeftRightUcViewBase() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(TopLeftRightUcViewBase), new FrameworkPropertyMetadata(typeof(TopLeftRightUcViewBase))); - } - - public override void OnApplyTemplate() - { - base.OnApplyTemplate(); - - } - - #region 依赖属性 - - - #region 顶部区域高度 - /// - /// 顶部区域高度 - /// - public double TopAreaHeight - { - get { return (double)GetValue(TopAreaHeightProperty); } - set { SetValue(TopAreaHeightProperty, value); } - } - - /// - /// 顶部区域高度 - /// - // Using a DependencyProperty as the backing store for TopAreaHeight. This enables animation, styling, binding, etc... - public static readonly DependencyProperty TopAreaHeightProperty = - DependencyProperty.Register("TopAreaHeight", typeof(double), typeof(TopLeftRightUcViewBase), new PropertyMetadata(100)); - #endregion - - - #region 左侧菜单区域最大宽度 - /// - /// 左侧菜单区域最大宽度 - /// - public double LeftMenuAreaMaxWidth - { - get { return (double)GetValue(LeftMenuAreaMaxWidthProperty); } - set { SetValue(LeftMenuAreaMaxWidthProperty, value); } - } - - /// - /// 左侧菜单区域最大宽度 - /// - // Using a DependencyProperty as the backing store for LeftMenuAreaMaxWidth. This enables animation, styling, binding, etc... - public static readonly DependencyProperty LeftMenuAreaMaxWidthProperty = - DependencyProperty.Register("LeftMenuAreaMaxWidth", typeof(double), typeof(TopLeftRightUcViewBase), new PropertyMetadata(230)); - #endregion - - - - #endregion + //获取样式 + var TopLeftRightUcViewBaseStyle = base.res["TopLeftRightUcViewBase"] as Style; + + this.Style = TopLeftRightUcViewBaseStyle; + } + + static TopLeftRightUcViewBase() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(TopLeftRightUcViewBase), new FrameworkPropertyMetadata(typeof(TopLeftRightUcViewBase))); + } + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + } + + #region 依赖属性 + + + #region 顶部区域高度 + /// + /// 顶部区域高度 + /// + public double TopAreaHeight + { + get { return (double)GetValue(TopAreaHeightProperty); } + set { SetValue(TopAreaHeightProperty, value); } + } + + /// + /// 顶部区域高度 + /// + // Using a DependencyProperty as the backing store for TopAreaHeight. This enables animation, styling, binding, etc... + public static readonly DependencyProperty TopAreaHeightProperty = + DependencyProperty.Register("TopAreaHeight", typeof(double), typeof(TopLeftRightUcViewBase), new PropertyMetadata(100)); + #endregion + + + #region 左侧菜单区域最大宽度 + /// + /// 左侧菜单区域最大宽度 + /// + public double LeftMenuAreaMaxWidth + { + get { return (double)GetValue(LeftMenuAreaMaxWidthProperty); } + set { SetValue(LeftMenuAreaMaxWidthProperty, value); } + } + + /// + /// 左侧菜单区域最大宽度 + /// + // Using a DependencyProperty as the backing store for LeftMenuAreaMaxWidth. This enables animation, styling, binding, etc... + public static readonly DependencyProperty LeftMenuAreaMaxWidthProperty = + DependencyProperty.Register("LeftMenuAreaMaxWidth", typeof(double), typeof(TopLeftRightUcViewBase), new PropertyMetadata(230)); + #endregion + + + + #endregion } diff --git a/Vampirewal.Core/WpfTheme/UcView/UcViewBase.cs b/Vampirewal.Core/WpfTheme/UcView/UcViewBase.cs index 34b8d39e48ebfa2b0523920a0d70e349ce2637e9..feec003e2ec914e769b805b1beda320b5a916c45 100644 --- a/Vampirewal.Core/WpfTheme/UcView/UcViewBase.cs +++ b/Vampirewal.Core/WpfTheme/UcView/UcViewBase.cs @@ -11,69 +11,126 @@ //----------------------------------------------------------------*/ #endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using Vampirewal.Core.WpfTheme.WindowStyle; - -namespace Vampirewal.Core.WpfTheme.UcView + + + +namespace Vampirewal.Core.WpfTheme.UcView; + +public class UcViewBase:UserControl { - public class UcViewBase:UserControl + static UcViewBase() { - static UcViewBase() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(UcViewBase), new FrameworkPropertyMetadata(typeof(UcViewBase))); - } + DefaultStyleKeyProperty.OverrideMetadata(typeof(UcViewBase), new FrameworkPropertyMetadata(typeof(UcViewBase))); + } - public UcViewBase() - { - //构造函数 - } + public UcViewBase() + { + //构造函数 - #region 属性 - /// - /// UserControlID - /// - public Guid ViewID - { - get - { - return Guid.NewGuid(); - } - } + this.IsVisibleChanged += UcViewBase_IsVisibleChanged; + this.Loaded += UcViewBase_Loaded; + + //if (!string.IsNullOrEmpty(ViewModelKey)) + //{ + // if (VampirewalCoreContext.GetInstance().GetViewOrViewModel(ViewModelKey, out Type VM)) + // { + // var VMB = VampirewalCoreContext.GetInstance().GetViewModel(ViewModelKey); - /// - /// 窗体样式引用 - /// - protected ResourceDictionary res + // if (VMB != null) + // { + // DataSource = VMB; + // DataSource.View = Window.GetWindow(this); + // SetValue(DataContextProperty, DataSource); + // } + // } + // else + // { + // throw new Exception($"未找到<{ViewModelKey}>Key值的ViewModel类型!"); + // } + //} + } + + protected virtual void UcViewBase_Loaded(object sender, RoutedEventArgs e) + { + + } + + private void UcViewBase_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) + { + if ((bool)e.NewValue) { - get + if (DataContext == null) { - return new ResourceDictionary() { Source = new Uri("pack://application:,,,/Vampirewal.Core;component/WpfTheme/CoreTheme.xaml", UriKind.RelativeOrAbsolute) }; + if (!string.IsNullOrEmpty(ViewModelKey)) + { + if (VampirewalCoreContext.GetInstance().GetViewOrViewModel(ViewModelKey, out Type VM)) + { + var VMB = VampirewalCoreContext.GetInstance().Services.GetService(VM) as ViewModelBase; + + if (VMB != null) + { + DataSource = VMB; + DataSource.View = Window.GetWindow(this); + SetValue(DataContextProperty, DataSource); + } + } + else + { + throw new Exception($"未找到<{ViewModelKey}>Key值的ViewModel类型!"); + } + } } } - #endregion + } - + #region 属性 + /// + /// 数据上下文 + /// + public virtual ViewModelBase DataSource { get; set; } - #region 依赖属性 + /// + /// UserControlID + /// + public Guid ViewID + { + get + { + return Guid.NewGuid(); + } + } + /// + /// 对应ViewModelKey + /// + /// + public virtual string ViewModelKey { get; } - public string Title + /// + /// 窗体样式引用 + /// + protected ResourceDictionary res + { + get { - get { return (string)GetValue(TitleProperty); } - set { SetValue(TitleProperty, value); } + return new ResourceDictionary() { Source = new Uri("pack://application:,,,/Vampirewal.Core;component/WpfTheme/CoreTheme.xaml", UriKind.RelativeOrAbsolute) }; } + } + #endregion - // Using a DependencyProperty as the backing store for Title. This enables animation, styling, binding, etc... - public static readonly DependencyProperty TitleProperty = - DependencyProperty.Register("Title", typeof(string), typeof(UcViewBase), new PropertyMetadata("")); - - #endregion + + #region 依赖属性 + + + // Using a DependencyProperty as the backing store for Title. This enables animation, styling, binding, etc... + public static readonly DependencyProperty TitleProperty = + DependencyProperty.Register("Title", typeof(string), typeof(UcViewBase), new PropertyMetadata("")); + + public string Title + { + get { return (string)GetValue(TitleProperty); } + set { SetValue(TitleProperty, value); } } + #endregion } diff --git a/Vampirewal.Core/WpfTheme/UcView/UcViewStyles.xaml b/Vampirewal.Core/WpfTheme/UcView/UcViewStyles.xaml index 8a80a659a15672d8bca258129321908d8640ac9a..e4663c86addfb7962855269fd92c9dcfa7f2caf8 100644 --- a/Vampirewal.Core/WpfTheme/UcView/UcViewStyles.xaml +++ b/Vampirewal.Core/WpfTheme/UcView/UcViewStyles.xaml @@ -12,7 +12,7 @@ - + - + - + + \ No newline at end of file diff --git a/Vampirewal.Core/WpfTheme/WindowStyle/MainWindowBase.cs b/Vampirewal.Core/WpfTheme/WindowStyle/MainWindowBase.cs index 93e57d3690d1a120eeed5d13931ce0a65b47388d..e17e034974851ce2873251ce3a66fc10ff194664 100644 --- a/Vampirewal.Core/WpfTheme/WindowStyle/MainWindowBase.cs +++ b/Vampirewal.Core/WpfTheme/WindowStyle/MainWindowBase.cs @@ -11,171 +11,187 @@ //----------------------------------------------------------------*/ #endregion -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Controls.Primitives; -using System.Windows.Shell; -using Vampirewal.Core.SimpleMVVM; - -namespace Vampirewal.Core.WpfTheme.WindowStyle + + +namespace Vampirewal.Core.WpfTheme.WindowStyle; + +/// +/// 适用于主窗体的页面 +/// +public class MainWindowBase : WindowBase { + private ColumnDefinition leftcontent { get; set; } + /// - /// 适用于主窗体的页面 + /// 记录最右位置 /// - public class MainWindowBase : WindowBase - { - private ColumnDefinition leftcontent { get; set; } + private GridLength _lastLength; - /// - /// 记录最右位置 - /// - private GridLength _lastLength; + public UIElement LeftContent { get; set; } - public UIElement LeftContent { get; set; } + public List MainAreas { get; set; } = new List(); - public List MainAreas { get; set; } = new List(); + /// + /// 拖动条样式 + /// + public ControlTemplate GridSplitterStyle { get; set; } - /// - /// 拖动条样式 - /// - public ControlTemplate GridSplitterStyle { get; set; } + static MainWindowBase() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(MainWindowBase), new FrameworkPropertyMetadata(typeof(MainWindowBase))); + } - static MainWindowBase() - { - DefaultStyleKeyProperty.OverrideMetadata(typeof(MainWindowBase), new FrameworkPropertyMetadata(typeof(MainWindowBase))); - } + /// + /// 构造函数 + /// + public MainWindowBase() + { + var BaseStyle = res["MainWindow"] as Style; - /// - /// 构造函数 - /// - public MainWindowBase() - { - var BaseStyle = res["MainWindow"] as Style; + this.Style = BaseStyle; - this.Style = BaseStyle; - } + //this.IsVisibleChanged += MainWindowBase_IsVisibleChanged; + } - public override void OnApplyTemplate() - { - base.OnApplyTemplate(); - //var aaa = base.Resources["WindowBase"] as Style;//如果前端添加引用之后,可以使用这个方法 + #region 20221125 注释,交给WindowBase去处理,代码重复了 + //private void MainWindowBase_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) + //{ + // if ((bool)e.NewValue) + // { + // if (DataContext != null && DataContext is ViewModelBase dc) + // { + // DataSource = dc; + // DataSource.View = GetWindow(this); + // } + + // if (DataSource != null && DataContext == null) + // { + // DataSource.View = GetWindow(this); + // SetValue(DataContextProperty, DataSource); + // } + // } + //} + #endregion + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + //var aaa = base.Resources["WindowBase"] as Style;//如果前端添加引用之后,可以使用这个方法 - #region 顶部模块 - var MainArea = this.Template.FindName("MainAreaMenu", this) as StackPanel; + #region 顶部模块 + var MainArea = this.Template.FindName("MainAreaMenu", this) as StackPanel; - if (MainAreas.Count > 0) - { - foreach (var item in MainAreas) - { - MainArea.Children.Add(item); - } - } - else + if (MainAreas.Count > 0) + { + foreach (var item in MainAreas) { - MainAreaHeight = 0; + MainArea.Children.Add(item); } - #endregion + } + else + { + MainAreaHeight = 0; + } + #endregion - #region 拖动条设置 - var GS = this.Template.FindName("gs", this) as GridSplitter; + #region 拖动条设置 + var GS = this.Template.FindName("gs", this) as GridSplitter; - GS.MouseDoubleClick += GS_MouseDoubleClick; + GS.MouseDoubleClick += GS_MouseDoubleClick; - _lastLength = new GridLength(LeftMenuMaxWidth, GridUnitType.Star); + _lastLength = new GridLength(LeftMenuMaxWidth, GridUnitType.Star); - #region 自定义GridSplitter模版 - if (GridSplitterStyle != null) + #region 自定义GridSplitter模版 + if (GridSplitterStyle != null) + { + if (GridSplitterStyle.TargetType == typeof(GridSplitter)) { - if (GridSplitterStyle.TargetType == typeof(GridSplitter)) - { - GS.Template = GridSplitterStyle; - } + GS.Template = GridSplitterStyle; } - #endregion + } + #endregion - #endregion + #endregion - #region 左侧菜单栏 + #region 左侧菜单栏 - leftcontent = this.Template.FindName("leftcontent", this) as ColumnDefinition; + leftcontent = this.Template.FindName("leftcontent", this) as ColumnDefinition; - if (LeftContent == null) - { - leftcontent.Width = new GridLength(0, GridUnitType.Star); - GS.Visibility = Visibility.Collapsed; - } - #endregion - } + if (LeftContent == null) + { + leftcontent.Width = new GridLength(0, GridUnitType.Star); + GS.Visibility = Visibility.Collapsed; + } + #endregion + } - private void GS_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e) + private void GS_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e) + { + if (leftcontent != null) { - if (leftcontent != null) + if (leftcontent.Width.Value > 0) + { + leftcontent.Width = new GridLength(0, GridUnitType.Star); + } + else { - if (leftcontent.Width.Value > 0) - { - leftcontent.Width = new GridLength(0, GridUnitType.Star); - } - else - { - leftcontent.Width = _lastLength; - } + leftcontent.Width = _lastLength; } } + } - /// - /// 关闭窗体(可重写,需保留base.CloseWin_Click) - /// - /// - /// - protected virtual void CloseButton_Click(object sender, RoutedEventArgs e) - { - WindowsManager.CloseWindow(this); - //this.Close(); - } + ///// + ///// 关闭窗体(可重写,需保留base.CloseWin_Click) + ///// + ///// + ///// + //protected virtual void CloseButton_Click(object sender, RoutedEventArgs e) + //{ + // WindowsManager.CloseWindow(this); + // //this.Close(); + //} + + protected override void OnStyleChanged(Style oldStyle, Style newStyle) + { + base.OnStyleChanged(oldStyle, newStyle); + } - protected override void OnStyleChanged(Style oldStyle, Style newStyle) - { - base.OnStyleChanged(oldStyle, newStyle); - } + #region 依赖属性 - #region 依赖属性 + #region 左侧菜单栏最大宽度 + public int LeftMenuMaxWidth + { + get { return (int)GetValue(LeftMenuMaxWidthProperty); } + set { SetValue(LeftMenuMaxWidthProperty, value); } + } - #region 左侧菜单栏最大宽度 - public int LeftMenuMaxWidth - { - get { return (int)GetValue(LeftMenuMaxWidthProperty); } - set { SetValue(LeftMenuMaxWidthProperty, value); } - } + // Using a DependencyProperty as the backing store for LeftMenuMaxWidth. This enables animation, styling, binding, etc... + public static readonly DependencyProperty LeftMenuMaxWidthProperty = + DependencyProperty.Register("LeftMenuMaxWidth", typeof(int), typeof(MainWindowBase), new PropertyMetadata(230)); + #endregion - // Using a DependencyProperty as the backing store for LeftMenuMaxWidth. This enables animation, styling, binding, etc... - public static readonly DependencyProperty LeftMenuMaxWidthProperty = - DependencyProperty.Register("LeftMenuMaxWidth", typeof(int), typeof(MainWindowBase), new PropertyMetadata(230)); - #endregion + #region 顶部模块区域高度 + public int MainAreaHeight + { + get { return (int)GetValue(MainAreaHeightProperty); } + set { SetValue(MainAreaHeightProperty, value); } + } - #region 顶部模块区域高度 - public int MainAreaHeight - { - get { return (int)GetValue(MainAreaHeightProperty); } - set { SetValue(MainAreaHeightProperty, value); } - } + // Using a DependencyProperty as the backing store for MainAreaHeight. This enables animation, styling, binding, etc... + public static readonly DependencyProperty MainAreaHeightProperty = + DependencyProperty.Register("MainAreaHeight", typeof(int), typeof(MainWindowBase), new PropertyMetadata(80)); + #endregion - // Using a DependencyProperty as the backing store for MainAreaHeight. This enables animation, styling, binding, etc... - public static readonly DependencyProperty MainAreaHeightProperty = - DependencyProperty.Register("MainAreaHeight", typeof(int), typeof(MainWindowBase), new PropertyMetadata(80)); - #endregion - #endregion - } + + + + #endregion } diff --git a/Vampirewal.Core/WpfTheme/WindowStyle/NotifyDefultView.xaml b/Vampirewal.Core/WpfTheme/WindowStyle/NotifyDefultView.xaml new file mode 100644 index 0000000000000000000000000000000000000000..f20b715ee4a9844383dfb163dc59a151979dd00a --- /dev/null +++ b/Vampirewal.Core/WpfTheme/WindowStyle/NotifyDefultView.xaml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + 该页为默认展示页面,请自行替换! + + + + + diff --git a/Vampirewal.Core/WpfTheme/WindowStyle/NotifyDefultView.xaml.cs b/Vampirewal.Core/WpfTheme/WindowStyle/NotifyDefultView.xaml.cs new file mode 100644 index 0000000000000000000000000000000000000000..9789b766989292aa6193c3024b0c1f0b1f4a7766 --- /dev/null +++ b/Vampirewal.Core/WpfTheme/WindowStyle/NotifyDefultView.xaml.cs @@ -0,0 +1,15 @@ + + + +namespace Vampirewal.Core.WpfTheme.WindowStyle; + +/// +/// NotifyDefultView.xaml 的交互逻辑 +/// +public partial class NotifyDefultView : UserControl +{ + public NotifyDefultView() + { + InitializeComponent(); + } +} diff --git a/Vampirewal.Core/WpfTheme/WindowStyle/NotifyWindow.xaml b/Vampirewal.Core/WpfTheme/WindowStyle/NotifyWindow.xaml new file mode 100644 index 0000000000000000000000000000000000000000..5f7204a9ddf1f7224276fda31b532cab16e443ca --- /dev/null +++ b/Vampirewal.Core/WpfTheme/WindowStyle/NotifyWindow.xaml @@ -0,0 +1,31 @@ + + + + + + + + + +