diff --git a/SunnyUI/Charts/UIDoughnutChart.cs b/SunnyUI/Charts/UIDoughnutChart.cs
index a44cb47d..9ec5716e 100644
--- a/SunnyUI/Charts/UIDoughnutChart.cs
+++ b/SunnyUI/Charts/UIDoughnutChart.cs
@@ -249,9 +249,9 @@ namespace Sunny.UI
{
Angle angle = Angles[pieIndex][azIndex];
PointF pf = angle.Center;
- if (Drawing.CalcDistance(e.Location, pf) > angle.Outer) continue;
- if (Drawing.CalcDistance(e.Location, pf) < angle.Inner) continue;
- double az = Drawing.CalcAngle(e.Location, pf);
+ if (e.Location.CalcDistance(pf) > angle.Outer) continue;
+ if (e.Location.CalcDistance(pf) < angle.Inner) continue;
+ double az = e.Location.CalcAngle(pf);
if (az >= angle.Start && az <= angle.Start + angle.Sweep)
{
SetPieAndAzIndex(pieIndex, azIndex);
diff --git a/SunnyUI/Charts/UIPieChart.cs b/SunnyUI/Charts/UIPieChart.cs
index 152e83c2..ae7d5809 100644
--- a/SunnyUI/Charts/UIPieChart.cs
+++ b/SunnyUI/Charts/UIPieChart.cs
@@ -274,9 +274,9 @@ namespace Sunny.UI
if (!e.Location.InRect(rect)) continue;
PointF pf = new PointF(rect.Left + rect.Width / 2.0f, rect.Top + rect.Height / 2.0f);
- if (Drawing.CalcDistance(e.Location, pf) * 2 > rect.Width) continue;
+ if (e.Location.CalcDistance(pf) * 2 > rect.Width) continue;
- double az = Drawing.CalcAngle(e.Location, pf);
+ double az = e.Location.CalcAngle(pf);
for (int azIndex = 0; azIndex < Option.Series[pieIndex].Data.Count; azIndex++)
{
Angle angle = Angles[pieIndex][azIndex];
diff --git a/SunnyUI/Common/UBaseConfig.cs b/SunnyUI/Common/UBaseConfig.cs
new file mode 100644
index 00000000..377a69d6
--- /dev/null
+++ b/SunnyUI/Common/UBaseConfig.cs
@@ -0,0 +1,743 @@
+/******************************************************************************
+ * SunnyUI 开源控件库、工具类库、扩展类库、多页面开发框架。
+ * CopyRight (C) 2012-2023 ShenYongHua(沈永华).
+ * QQ群:56829229 QQ:17612584 EMail:SunnyUI@QQ.Com
+ *
+ * Blog: https://www.cnblogs.com/yhuse
+ * Gitee: https://gitee.com/yhuse/SunnyUI
+ * GitHub: https://github.com/yhuse/SunnyUI
+ *
+ * SunnyUI.Common.dll can be used for free under the MIT license.
+ * If you use this code, please keep this note.
+ * 如果您使用此代码,请保留此说明。
+ ******************************************************************************
+ * 文件名称: UBaseConfig.cs
+ * 文件说明: 配置文件基类
+ * 当前版本: V3.1
+ * 创建日期: 2020-01-01
+ *
+ * 2020-01-01: V2.2.0 增加文件说明
+******************************************************************************/
+
+using System;
+using System.Collections;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Reflection;
+using System.Xml.Serialization;
+
+namespace Sunny.UI
+{
+ ///
+ /// 配置文件基类
+ ///
+ /// 类型
+ public abstract class BaseConfig where TConfig : BaseConfig, new()
+ {
+ ///
+ /// 实体对象
+ ///
+ protected static TConfig current;
+
+ ///
+ /// 配置文件描述
+ ///
+ public static string Description
+ {
+ get
+ {
+ var fileanddesc = ConfigHelper.GetConfigFile();
+ return fileanddesc.Item2;
+ }
+ }
+
+ ///
+ /// 配置文件名
+ ///
+ public static string ConfigFile
+ {
+ get
+ {
+ var fileanddesc = ConfigHelper.GetConfigFile();
+ return fileanddesc.Item1;
+ }
+ }
+
+ ///
+ /// 当前可执行文件路径,末尾包括\
+ ///
+ /// 结果
+ private static string CurrentDir()
+ {
+ return Environment.CurrentDirectory.DealPath();
+ }
+
+ ///
+ /// 当前实例。通过置空可以使其重新加载。
+ ///
+ public static TConfig Current
+ {
+ get
+ {
+ if (current != null)
+ {
+ return current;
+ }
+
+ // 现在没有对象,尝试加载,若返回null则实例化一个新的
+ current = CreateNew();
+ if (!current.Load(CurrentDir() + ConfigFile))
+ {
+ try
+ {
+ // 根据配置,有可能不保存,直接返回默认
+ current.Save();
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex.Message);
+ }
+ }
+
+ return current;
+ }
+
+ set => current = value;
+ }
+
+ private static TConfig CreateNew()
+ {
+ TConfig config = new TConfig();
+ config.SetDefault();
+ return config;
+ }
+
+ /// 保存到配置文件中去
+ public void Save()
+ {
+ Save(null);
+ }
+
+ ///
+ /// 加载指定配置文件
+ ///
+ /// 结果
+ public bool Load()
+ {
+ return Load(null);
+ }
+
+ ///
+ /// 加密
+ ///
+ /// 字符串
+ /// 加密后字符串
+ public string Encrypt(string str)
+ {
+ Random random = new Random();
+ var value = random.Next(100000, 999999);
+ string tmp = str + value.ToString();
+ return tmp.DesEncrypt();
+ }
+
+ ///
+ /// 解密
+ ///
+ /// 字符串
+ /// 解密后字符串
+ public string Decrypt(string str)
+ {
+ string result = str.DesDecrypt();
+ return result.Left(result.Length - 6);
+ }
+
+ /// 加载指定配置文件
+ /// 文件名
+ /// 结果
+ public abstract bool Load(string filename);
+
+ /// 保存到配置文件中去
+ /// 文件名
+ public abstract void Save(string filename);
+
+ ///
+ /// 设置默认值
+ ///
+ public virtual void SetDefault()
+ {
+ }
+ }
+
+ ///
+ /// 忽略此属性的配置存储
+ ///
+ [AttributeUsage(AttributeTargets.Property)]
+ public class MapperIgnoreAttribute : Attribute
+ {
+ }
+
+ ///
+ /// 忽略此属性的配置存储
+ ///
+ [AttributeUsage(AttributeTargets.Property)]
+ public class IgnoreAttribute : Attribute
+ {
+ }
+
+ ///
+ /// 配置文件帮助类
+ ///
+ public static class ConfigHelper
+ {
+ ///
+ /// 类型是否能够转为指定基类
+ ///
+ /// 类型
+ /// 基类
+ /// 是否能够转为指定基类
+ public static bool As(this Type type, Type baseType)
+ {
+ if (type == null)
+ {
+ return false;
+ }
+
+ // 如果基类是泛型定义
+ if (baseType.IsGenericTypeDefinition && type.IsGenericType && !type.IsGenericTypeDefinition)
+ {
+ type = type.GetGenericTypeDefinition();
+ }
+
+ if (type == baseType)
+ {
+ return true;
+ }
+
+ if (baseType.IsAssignableFrom(type))
+ {
+ return true;
+ }
+
+ var rs = false;
+
+ // 接口
+ if (baseType.IsInterface)
+ {
+ if (type.GetInterface(baseType.FullName) != null)
+ {
+ rs = true;
+ }
+ else
+ foreach (var e in type.GetInterfaces())
+ {
+ if (e.IsGenericType && baseType.IsGenericTypeDefinition ? e.GetGenericTypeDefinition() == baseType : e == baseType)
+ {
+ rs = true;
+ break;
+ }
+ }
+ }
+
+ // 判断是否子类时,支持只反射加载的程序集
+ if (!rs && type.Assembly.ReflectionOnly)
+ {
+ // 反射加载时,需要特殊处理接口
+ while (!rs && type != typeof(object))
+ {
+ if (type == null)
+ {
+ continue;
+ }
+
+ if (type.FullName == baseType.FullName && type.AssemblyQualifiedName == baseType.AssemblyQualifiedName)
+ {
+ rs = true;
+ }
+
+ type = type.BaseType;
+ }
+ }
+
+ return rs;
+ }
+
+ /// 是否泛型字典
+ /// 类型
+ /// 是否泛型字典
+ public static bool IsDictionary(this Type type) => type != null && type.IsGenericType && type.As(typeof(IDictionary<,>));
+
+ /// 是否泛型列表
+ /// 类型
+ /// 是否泛型列表
+ public static bool IsList(this Type type)
+ {
+ return type != null && type.IsGenericType && type.As(typeof(IList<>));
+ //return Array.IndexOf(type.GetInterfaces(), typeof(IEnumerable)) > -1;
+ }
+
+ /// 获取成员绑定的显示名,优先DisplayName,然后Description
+ /// member
+ /// 显示名
+ public static string DisplayName(this PropertyInfo member)
+ {
+ var att = member.GetCustomAttribute();
+ if (att != null && !att.DisplayName.IsNullOrWhiteSpace())
+ {
+ return att.DisplayName;
+ }
+
+ return "";
+ }
+
+ /// 获取成员绑定的显示名,优先DisplayName,然后Description
+ /// member
+ /// 显示名
+ public static string Description(this PropertyInfo member)
+ {
+ var att2 = member.GetCustomAttribute();
+ if (att2 != null && !att2.Description.IsNullOrWhiteSpace())
+ {
+ return att2.Description;
+ }
+
+ return "";
+ }
+
+ ///
+ /// 获取需要的属性,删除忽略的属性
+ ///
+ /// 类型
+ /// 属性列表
+ public static List GetNeedProperties(this Type type)
+ {
+ var list = type.GetProperties();
+ List result = new List();
+ foreach (var info in list)
+ {
+ if (info.GetCustomAttribute() != null)
+ {
+ continue;
+ }
+
+ if (info.GetCustomAttribute() != null)
+ {
+ continue;
+ }
+
+ if (info.GetCustomAttribute() != null)
+ {
+ continue;
+ }
+
+ if (info.GetCustomAttribute() != null)
+ {
+ continue;
+ }
+
+ result.Add(info);
+ }
+
+ return result;
+ }
+
+ ///
+ /// 获取配置文件路径
+ ///
+ /// 类型
+ /// 文件名
+ public static Tuple GetConfigFile()
+ {
+ string filename;
+ string description = "配置文件";
+ var att = typeof(TConfig).GetCustomAttribute();
+ if (att == null || att.FileName.IsNullOrWhiteSpace())
+ {
+ filename = $"{typeof(TConfig).Name}.cfg";
+ }
+ else
+ {
+ filename = att.FileName;
+
+ if (!att.Description.IsNullOrEmpty())
+ {
+ description = att.Description;
+ }
+ }
+
+ return new Tuple(filename, description);
+ }
+
+ ///
+ /// 初始化属性
+ ///
+ /// 配置类
+ /// 类型
+ /// 节点
+ /// ApplicationException
+ public static ConcurrentDictionary InitIdents(TConfig config)
+ {
+ ConcurrentDictionary idents = new ConcurrentDictionary();
+ var list = config.GetType().GetNeedProperties();
+ foreach (PropertyInfo info in list)
+ {
+ Ident ident = new Ident
+ {
+ Key = info.Name,
+ Show = true,
+ Description = info.Description(),
+ IsList = info.PropertyType.IsList()
+ };
+
+ var section = info.GetCustomAttribute();
+ ident.Section = section != null ? section.Section : "";
+
+ var propertyatt = info.GetCustomAttribute();
+ ident.Caption = propertyatt != null ? propertyatt.Caption : "";
+ ident.Unit = propertyatt != null ? propertyatt.Unit : "";
+ ident.Description = propertyatt != null ? propertyatt.Description : "";
+
+ var indexatt = info.GetCustomAttribute();
+ ident.Index = indexatt?.Index ?? short.MaxValue + idents.Count;
+ ident.Show = indexatt == null || indexatt.Show;
+
+ if (ident.Description.IsNullOrEmpty())
+ {
+ ident.Description = info.DisplayName() ?? info.Description();
+ }
+
+ if (ident.Description.IsNullOrEmpty())
+ {
+ ident.Description = "";
+ }
+
+ if (!idents.ContainsKey(ident.Key))
+ {
+ idents.TryAdd(ident.Key, ident);
+ }
+ }
+
+ return idents;
+ }
+
+ ///
+ /// 类型默认值
+ ///
+ /// 类型
+ /// 默认值
+ public static object DefaultValue(Type targetType)
+ {
+ return targetType.IsValueType ? Activator.CreateInstance(targetType) : null;
+ }
+
+ ///
+ /// 读取对象数值
+ ///
+ /// 配置文件
+ /// 节点
+ /// 类型
+ /// ApplicationException
+ public static void LoadConfigValue(TConfig config, ConcurrentDictionary idents)
+ {
+ var list = config.GetType().GetNeedProperties();
+ foreach (PropertyInfo info in list)
+ {
+ object defaultobj = info.GetValue(config, null);
+ Type type = info.PropertyType;
+
+ if (type == typeof(string))
+ {
+ object value = idents[info.Name].Value;
+ info.SetValue(config, Convert.ChangeType(value == null ? defaultobj : value, type), null);
+ continue;
+ }
+
+ if (ConvertEx.CanConvent(type))
+ {
+ object value = ConvertEx.StringToObject(idents[info.Name].Value, type, defaultobj);
+ info.SetValue(config, Convert.ChangeType(value, type), null);
+ continue;
+ }
+
+ if (type.IsList())
+ {
+ Type[] genericTypes = type.GetGenericArguments();
+ if (genericTypes.Length != 1)
+ {
+ throw new ApplicationException("转换出错: " + type.FullName);
+ }
+
+ Type childtype = genericTypes[0];
+ Type typeDataList = typeof(List<>).MakeGenericType(childtype);
+ MethodInfo methodInfo = typeDataList.GetMethod("Add", BindingFlags.Public | BindingFlags.Instance);
+ if (methodInfo == null)
+ {
+ continue;
+ }
+
+ object listvalue = typeDataList.InvokeMember(null, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.CreateInstance, null, null, new object[] { });
+
+ foreach (string strvalue in idents[info.Name].Values)
+ {
+ if (childtype == typeof(string))
+ {
+ object value = strvalue;
+ methodInfo.Invoke(listvalue, new[] { value });
+ }
+ else if (ConvertEx.CanConvent(childtype))
+ {
+ object value = ConvertEx.StringToObject(strvalue, childtype, DefaultValue(childtype));
+ methodInfo.Invoke(listvalue, new[] { value });
+ }
+ }
+
+ info.SetValue(config, listvalue, null);
+ continue;
+ }
+
+ throw new ApplicationException("不支持此类型: " + type.FullName);
+ }
+ }
+
+ ///
+ /// 设置对象数值
+ ///
+ /// 配置文件
+ /// 节点
+ /// 类型
+ /// ApplicationException
+ public static void SaveConfigValue(TConfig config, ConcurrentDictionary idents)
+ {
+ var list = config.GetType().GetNeedProperties();
+ foreach (PropertyInfo info in list)
+ {
+ object obj = info.GetValue(config, null);
+ Type type = info.PropertyType;
+
+ if (ConvertEx.CanConvent(type))
+ {
+ string value = ConvertEx.ObjectToString(obj, type);
+ idents[info.Name].Value = value;
+ continue;
+ }
+
+ if (type.IsList())
+ {
+ Type[] genericTypes = type.GetGenericArguments();
+ if (genericTypes.Length != 1)
+ {
+ throw new ApplicationException("转换出错: " + type.FullName);
+ }
+
+ Type childtype = genericTypes[0];
+ IEnumerable en = obj as IEnumerable;
+ if (en == null)
+ {
+ throw new ApplicationException("转换出错: " + type.FullName);
+ }
+
+ idents[info.Name].Values.Clear();
+ foreach (object child in en)
+ {
+ if (ConvertEx.CanConvent(childtype))
+ {
+ idents[info.Name].Values.Add(ConvertEx.ObjectToString(child, childtype));
+ }
+ else
+ {
+ throw new ApplicationException("不支持此类型: " + type.FullName);
+ }
+ }
+
+ continue;
+ }
+
+ throw new ApplicationException("不支持此类型: " + type.FullName);
+ }
+ }
+ }
+
+ /// 配置文件特性
+ [AttributeUsage(AttributeTargets.Class)]
+ public class ConfigFileAttribute : Attribute
+ {
+ ///
+ /// 配置文件名
+ ///
+ public string FileName { get; }
+
+ ///
+ /// 描述
+ ///
+ public string Description { get; }
+
+ ///
+ /// 配置文件
+ ///
+ public ConfigFileAttribute() : this(string.Empty, string.Empty)
+ {
+ }
+
+ /// 配置文件
+ /// 文件名
+ /// 描述
+ public ConfigFileAttribute(string fileName, string description = "")
+ {
+ FileName = fileName;
+ Description = description;
+ }
+ }
+
+ ///
+ /// 数据节点
+ ///
+ public class Ident
+ {
+ ///
+ /// 节
+ ///
+ public string Section { get; set; }
+
+ ///
+ /// 键
+ ///
+ public string Key { get; set; }
+
+ ///
+ /// 值
+ ///
+ public string Value { get; set; }
+
+ ///
+ /// 描述
+ ///
+ public string Description { get; set; }
+
+ ///
+ /// 名称
+ ///
+ public string Caption { get; set; }
+
+ ///
+ /// 单位
+ ///
+ public string Unit { get; set; }
+
+ ///
+ /// 序号
+ ///
+ public int Index { get; set; }
+
+ ///
+ /// 是否显示
+ ///
+ public bool Show { get; set; }
+
+ ///
+ /// ToString()
+ ///
+ /// String
+ public override string ToString()
+ {
+ return Index + " [" + Section + "] " + Key + " = ?";
+ }
+
+ ///
+ /// 是否是列表类型
+ ///
+ public bool IsList { get; set; }
+
+ ///
+ /// 列表值
+ ///
+ public List Values = new List();
+ }
+
+ ///
+ /// 配置属性节点特性
+ ///
+ [AttributeUsage(AttributeTargets.Property)]
+ public class ConfigSectionAttribute : Attribute
+ {
+ ///
+ /// 节
+ ///
+ public string Section { get; }
+
+ /// 属性节点特性
+ /// 节
+ public ConfigSectionAttribute(string section)
+ {
+ Section = section;
+ }
+ }
+
+ ///
+ /// 配置属性描述特性
+ ///
+ [AttributeUsage(AttributeTargets.Property)]
+ public class ConfigPropertyAttribute : Attribute
+ {
+ ///
+ /// 标题
+ ///
+ public string Caption { get; }
+
+ ///
+ /// 单位
+ ///
+ public string Unit { get; }
+
+ ///
+ /// 描述
+ ///
+ public string Description { get; }
+
+ ///
+ /// 配置文件属性
+ ///
+ /// 标题
+ /// 单位
+ /// 描述
+ public ConfigPropertyAttribute(string caption, string description = "", string unit = "")
+ {
+ Caption = caption;
+ Unit = unit;
+ Description = description;
+ }
+ }
+
+ ///
+ /// 忽略此属性的配置存储
+ ///
+ [AttributeUsage(AttributeTargets.Property)]
+ public class ConfigIgnoreAttribute : Attribute
+ {
+ }
+
+ ///
+ /// 配置序号描述特性
+ ///
+ [AttributeUsage(AttributeTargets.Property)]
+ public class ConfigIndexAttribute : Attribute
+ {
+ ///
+ /// 序号
+ ///
+ public int Index { get; }
+
+ ///
+ /// 是否显示
+ ///
+ public bool Show { get; }
+
+ /// 配置序号特性
+ /// 序号
+ /// 是否显示
+ public ConfigIndexAttribute(int index, bool show = true)
+ {
+ Index = index;
+ Show = show;
+ }
+ }
+}
\ No newline at end of file
diff --git a/SunnyUI/Common/UConvertEx.cs b/SunnyUI/Common/UConvertEx.cs
new file mode 100644
index 00000000..e95d7ba5
--- /dev/null
+++ b/SunnyUI/Common/UConvertEx.cs
@@ -0,0 +1,371 @@
+/******************************************************************************
+ * SunnyUI 开源控件库、工具类库、扩展类库、多页面开发框架。
+ * CopyRight (C) 2012-2023 ShenYongHua(沈永华).
+ * QQ群:56829229 QQ:17612584 EMail:SunnyUI@QQ.Com
+ *
+ * Blog: https://www.cnblogs.com/yhuse
+ * Gitee: https://gitee.com/yhuse/SunnyUI
+ * GitHub: https://github.com/yhuse/SunnyUI
+ *
+ * SunnyUI.Common.dll can be used for free under the MIT license.
+ * If you use this code, please keep this note.
+ * 如果您使用此代码,请保留此说明。
+ ******************************************************************************
+ * 文件名称: UConvertEx.cs
+ * 文件说明: 对象转换扩展类
+ * 当前版本: V3.1
+ * 创建日期: 2020-01-01
+ *
+ * 2020-11-20: V3.0.0 增加文件说明
+******************************************************************************/
+
+using System;
+using System.Drawing;
+
+namespace Sunny.UI
+{
+ ///
+ /// 对象转换扩展类
+ ///
+ public static class ConvertEx
+ {
+ ///
+ /// 可以对象和字符串互相转换的类型
+ ///
+ /// 类型
+ /// 结果
+ public static bool CanConvent(Type type)
+ {
+ bool result = false;
+ TypeCode typeCode = Type.GetTypeCode(type);
+ switch (typeCode)
+ {
+ case TypeCode.String:
+ case TypeCode.Char:
+ case TypeCode.SByte:
+ case TypeCode.Byte:
+ case TypeCode.Int16:
+ case TypeCode.UInt16:
+ case TypeCode.Int32:
+ case TypeCode.UInt32:
+ case TypeCode.Int64:
+ case TypeCode.UInt64:
+ case TypeCode.Single:
+ case TypeCode.Double:
+ case TypeCode.Decimal:
+ case TypeCode.Boolean:
+ case TypeCode.DateTime:
+ result = true;
+ break;
+
+ case TypeCode.Object:
+ if (type == typeof(Point) ||
+ type == typeof(PointF) ||
+ type == typeof(Color) ||
+ type == typeof(Size) ||
+ type == typeof(SizeF))
+ {
+ result = true;
+ }
+
+ break;
+ }
+
+ return result;
+ }
+
+ ///
+ /// 字符串转对象
+ ///
+ /// 字符串
+ /// 类型
+ /// 默认对象
+ /// 对象
+ public static object StringToObject(string str, Type type, object defaultobj)
+ {
+ object obj = defaultobj;
+
+ if (type == typeof(string))
+ {
+ return str;
+ }
+
+ if (str.IsNullOrEmpty())
+ {
+ return defaultobj;
+ }
+
+ TypeCode typeCode = Type.GetTypeCode(type);
+ switch (typeCode)
+ {
+ case TypeCode.Char:
+ obj = str.ToChar((char)defaultobj);
+ break;
+
+ case TypeCode.SByte:
+ obj = str.ToSByte((sbyte)defaultobj);
+ break;
+
+ case TypeCode.Byte:
+ obj = str.ToByte((byte)defaultobj);
+ break;
+
+ case TypeCode.Int16:
+ obj = str.ToShort((short)defaultobj);
+ break;
+
+ case TypeCode.UInt16:
+ obj = str.ToUShort((ushort)defaultobj);
+ break;
+
+ case TypeCode.Int32:
+ obj = str.ToInt((int)defaultobj);
+ break;
+
+ case TypeCode.UInt32:
+ obj = str.ToUInt((uint)defaultobj);
+ break;
+
+ case TypeCode.Int64:
+ obj = str.ToLong((long)defaultobj);
+ break;
+
+ case TypeCode.UInt64:
+ obj = str.ToULong((ulong)defaultobj);
+ break;
+
+ case TypeCode.Single:
+ obj = str.ToFloat((float)defaultobj);
+ break;
+
+ case TypeCode.Double:
+ obj = str.ToDouble((double)defaultobj);
+ break;
+
+ case TypeCode.Decimal:
+ obj = str.ToDecimal((decimal)defaultobj);
+ break;
+
+ case TypeCode.Boolean:
+ if (str.ToUpper().Equals(bool.TrueString.ToUpper()))
+ {
+ obj = true;
+ }
+
+ if (str.ToUpper().Equals(bool.FalseString.ToUpper()))
+ {
+ obj = false;
+ }
+
+ break;
+
+ case TypeCode.DateTime:
+ try
+ {
+ DateTime dt = str.ToDateTime(DateTimeEx.DateTimeFormat);
+ obj = dt;
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ }
+
+ break;
+
+ case TypeCode.Object:
+ obj = StringToObjectEx(str, type, defaultobj);
+ break;
+
+ default:
+ throw new ApplicationException("不支持此类型: " + type.FullName);
+ }
+
+ if (type == typeof(DateTime))
+ {
+ }
+
+ return obj;
+ }
+
+ ///
+ /// 字符串转对象扩展
+ ///
+ /// 字符串
+ /// 类型
+ /// 默认对象
+ /// 对象
+ private static object StringToObjectEx(string str, Type type, object defaultobj)
+ {
+ object obj = defaultobj;
+
+ if (type == typeof(Point))
+ {
+ string[] strs = str.ToUpper().Replace("X:", "").Replace("Y:", "").Trim().Split(";");
+
+ if (strs.Length == 2)
+ {
+ if (int.TryParse(strs[0], out var x) && int.TryParse(strs[1], out var y))
+ {
+ obj = new Point(x, y);
+ }
+ }
+ }
+ else if (type == typeof(PointF))
+ {
+ string[] strs = str.ToUpper().Replace("X:", "").Replace("Y:", "").Trim().Split(";");
+
+ if (strs.Length == 2)
+ {
+ if (float.TryParse(strs[0], out var x) && float.TryParse(strs[1], out var y))
+ {
+ obj = new PointF(x, y);
+ }
+ }
+ }
+ else if (type == typeof(Color))
+ {
+ string[] strs = str.ToUpper().Replace("A:", "").Replace("R:", "").Replace("G:", "").Replace("B:", "").Trim().Split(";");
+
+ if (strs.Length == 4)
+ {
+ if (int.TryParse(strs[0], out var a) && int.TryParse(strs[1], out var r) && int.TryParse(strs[2], out var g) && int.TryParse(strs[3], out var b))
+ {
+ if (a.InRange(0, 255) && r.InRange(0, 255) && g.InRange(0, 255) && b.InRange(0, 255))
+ {
+ obj = Color.FromArgb(a, r, g, b);
+ }
+ }
+ }
+ }
+ else if (type == typeof(Size))
+ {
+ string[] strs = str.ToUpper().Replace("W:", "").Replace("H:", "").Trim().Split(";");
+
+ if (strs.Length == 2)
+ {
+ if (int.TryParse(strs[0], out var x) && int.TryParse(strs[1], out var y))
+ {
+ obj = new Size(x, y);
+ }
+ }
+ }
+ else if (type == typeof(SizeF))
+ {
+ string[] strs = str.ToUpper().Replace("W:", "").Replace("H:", "").Trim().Split(";");
+
+ if (strs.Length == 2)
+ {
+ if (float.TryParse(strs[0], out var x) && float.TryParse(strs[1], out var y))
+ {
+ obj = new SizeF(x, y);
+ }
+ }
+ }
+ else
+ {
+ throw new ApplicationException("不支持此类型: " + type.FullName);
+ }
+
+ return obj;
+ }
+
+ ///
+ /// 对象转字符串
+ ///
+ /// 对象
+ /// 类型
+ /// 字符串
+ public static string ObjectToString(object obj, Type type)
+ {
+ string value;
+
+ TypeCode typeCode = Type.GetTypeCode(type);
+ switch (typeCode)
+ {
+ case TypeCode.String:
+ if (obj == null)
+ {
+ obj = "";
+ }
+
+ value = obj.ToString();
+ break;
+
+ case TypeCode.Char:
+ case TypeCode.SByte:
+ case TypeCode.Byte:
+ case TypeCode.Int16:
+ case TypeCode.UInt16:
+ case TypeCode.Int32:
+ case TypeCode.UInt32:
+ case TypeCode.Int64:
+ case TypeCode.UInt64:
+ case TypeCode.Single:
+ case TypeCode.Double:
+ case TypeCode.Decimal:
+ value = obj.ToString();
+ break;
+
+ case TypeCode.Boolean:
+ value = (bool)obj ? bool.TrueString : bool.FalseString;
+ break;
+
+ case TypeCode.DateTime:
+ value = ((DateTime)obj).ToString(DateTimeEx.DateTimeFormat);
+ break;
+
+ case TypeCode.Object:
+ value = ObjectToStringEx(obj, type);
+ break;
+
+ default:
+ throw new ApplicationException("不支持此类型: " + type.FullName);
+ }
+
+ return value;
+ }
+
+ ///
+ /// 对象转字符串扩展
+ ///
+ /// 对象
+ /// 类型
+ /// 字符串
+ private static string ObjectToStringEx(object obj, Type type)
+ {
+ string value;
+
+ if (type == typeof(Point))
+ {
+ Point point = (Point)obj;
+ value = "X:" + point.X + "; Y:" + point.Y;
+ }
+ else if (type == typeof(PointF))
+ {
+ PointF point = (PointF)obj;
+ value = "X:" + point.X + "; Y:" + point.Y;
+ }
+ else if (type == typeof(Color))
+ {
+ Color color = (Color)obj;
+ value = "A:" + color.A + "; R:" + color.R + "; G:" + color.G + "; B:" + color.B;
+ }
+ else if (type == typeof(Size))
+ {
+ Size size = (Size)obj;
+ value = "W:" + size.Width + "; H:" + size.Height;
+ }
+ else if (type == typeof(SizeF))
+ {
+ SizeF size = (SizeF)obj;
+ value = "W:" + size.Width + "; H:" + size.Height;
+ }
+ else
+ {
+ throw new ApplicationException("不支持此类型: " + type.FullName);
+ }
+
+ return value;
+ }
+ }
+}
diff --git a/SunnyUI/Common/UDateTimeInt64.cs b/SunnyUI/Common/UDateTimeInt64.cs
new file mode 100644
index 00000000..c9dba06d
--- /dev/null
+++ b/SunnyUI/Common/UDateTimeInt64.cs
@@ -0,0 +1,382 @@
+/******************************************************************************
+ * SunnyUI 开源控件库、工具类库、扩展类库、多页面开发框架。
+ * CopyRight (C) 2012-2023 ShenYongHua(沈永华).
+ * QQ群:56829229 QQ:17612584 EMail:SunnyUI@QQ.Com
+ *
+ * Blog: https://www.cnblogs.com/yhuse
+ * Gitee: https://gitee.com/yhuse/SunnyUI
+ * GitHub: https://github.com/yhuse/SunnyUI
+ *
+ * SunnyUI.dll can be used for free under the GPL-3.0 license.
+ * If you use this code, please keep this note.
+ * 如果您使用此代码,请保留此说明。
+ ******************************************************************************
+ * 文件名称: UDateTimeInt64.cs
+ * 文件说明: 日期长整型
+ * 当前版本: V2.2
+ * 创建日期: 2020-09-23
+ *
+ * 2020-09-23: V2.2.8 增加文件说明
+ * 2020-10-10: V2.2.8 增加与Double互转
+******************************************************************************/
+
+using System;
+
+namespace Sunny.UI
+{
+ ///
+ /// 日期与长整形和浮点型互转
+ /// Value:长整形,为1970年1月1日0时起的毫秒数
+ /// DoubleValue:双精度浮点数,1970年1月1日0时起的天数
+ ///
+ public struct DateTimeInt64 : IComparable, IEquatable, IEquatable, IEquatable
+ {
+ public long Value { get; set; }
+
+ public const long Jan1st1970Ticks = 621355968000000000; //Jan1st1970.Ticks;
+ public const long Dec31th9999Ticks = 3155378975999990000; //DateTime.MaxValue.Ticks;
+ public const string DefaultFormatString = DateTimeEx.DateTimeFormatEx;
+ public const double MillisecondsPerDay = 86400000.0;
+
+ ///
+ /// 返回当前时间的毫秒数, 这个毫秒其实就是自1970年1月1日0时起的毫秒数
+ ///
+ public static long CurrentDateTimeToTicks()
+ {
+ return (DateTime.UtcNow.Ticks - Jan1st1970Ticks) / 10000;
+ }
+
+ public double DoubleValue
+ {
+ get { return Value * 1.0 / MillisecondsPerDay; }
+ set { Value = (long)(value * MillisecondsPerDay); }
+ }
+
+ ///
+ /// 返回指定时间的毫秒数, 这个毫秒其实就是自1970年1月1日0时起的毫秒数
+ ///
+ public static long DateTimeToTicks(DateTime datetime)
+ {
+ return (datetime.ToUniversalTime().Ticks - Jan1st1970Ticks) / 10000;
+ }
+
+ ///
+ /// 从一个代表自1970年1月1日0时起的毫秒数,转换为DateTime (北京时间)
+ ///
+ public static DateTime TicksToDateTime(long ticks)
+ {
+#pragma warning disable CS0618 // 类型或成员已过时
+ return TimeZone.CurrentTimeZone.ToLocalTime(TicksToUTCDateTime(ticks));
+#pragma warning restore CS0618 // 类型或成员已过时
+ }
+
+ ///
+ /// 从一个代表自1970年1月1日0时起的毫秒数,转换为DateTime (UTC时间)
+ ///
+ public static DateTime TicksToUTCDateTime(long ticks)
+ {
+ return new DateTime(ticks * 10000 + Jan1st1970Ticks);
+ }
+
+ public DateTimeInt64(long ticks)
+ {
+ ticks = MakeValidDate(ticks);
+ Value = ticks;
+ }
+
+ public DateTimeInt64(double doubleTicks)
+ {
+ doubleTicks = MakeValidDate((long)(doubleTicks * MillisecondsPerDay));
+ Value = (long)doubleTicks;
+ }
+
+ public DateTimeInt64(DateTime dateTime)
+ {
+ Value = DateTimeToTicks(dateTime);
+ }
+
+ public DateTimeInt64(int year, int month, int day)
+ {
+ Value = DateTimeToTicks(new DateTime(year, month, day));
+ }
+
+ public DateTimeInt64(int year, int month, int day, int hour, int minute, int second)
+ {
+ Value = DateTimeToTicks(new DateTime(year, month, day, hour, minute, second));
+ }
+
+ public DateTimeInt64(int year, int month, int day, int hour, int minute, int second, int millisecond)
+ {
+ Value = DateTimeToTicks(new DateTime(year, month, day, hour, minute, second, millisecond));
+ }
+
+ public DateTimeInt64(DateTimeInt64 dtValue)
+ {
+ Value = dtValue.Value;
+ }
+
+ public bool IsValidDate
+ {
+ get { return Value >= 0 && Value <= Dec31th9999Ticks - Jan1st1970Ticks; }
+ }
+
+ public DateTime DateTime
+ {
+ get { return TicksToDateTime(Value); }
+ set { Value = DateTimeToTicks(value); }
+ }
+
+ public static bool CheckValidDate(long ticks)
+ {
+ return ticks >= 0 && ticks <= Dec31th9999Ticks - Jan1st1970Ticks;
+ }
+
+ public static long MakeValidDate(long ticks)
+ {
+ if (ticks < 0)
+ ticks = 0;
+ if (ticks > Dec31th9999Ticks - Jan1st1970Ticks)
+ ticks = Dec31th9999Ticks - Jan1st1970Ticks;
+
+ return ticks;
+ }
+
+ public void AddMilliseconds(double milliseconds)
+ {
+ Value = DateTimeToTicks(DateTime.AddMilliseconds(milliseconds));
+ }
+
+ public void AddSeconds(double seconds)
+ {
+ Value = DateTimeToTicks(DateTime.AddSeconds(seconds));
+ }
+
+ public void AddMinutes(double minutes)
+ {
+ Value = DateTimeToTicks(DateTime.AddMinutes(minutes));
+ }
+
+ public void AddHours(double hours)
+ {
+ Value = DateTimeToTicks(DateTime.AddHours(hours));
+ }
+
+ public void AddDays(double days)
+ {
+ Value = DateTimeToTicks(DateTime.AddDays(days));
+ }
+
+ public void AddMonths(int months)
+ {
+ Value = DateTimeToTicks(DateTime.AddMonths(months));
+ }
+
+ public void AddYears(int years)
+ {
+ Value = DateTimeToTicks(DateTime.AddYears(years));
+ }
+
+ public static long operator -(DateTimeInt64 dtValue1, DateTimeInt64 dtValue2)
+ {
+ return dtValue1.Value - dtValue2.Value;
+ }
+
+ public static long operator +(DateTimeInt64 dtValue1, DateTimeInt64 dtValue2)
+ {
+ return dtValue1.Value + dtValue2.Value;
+ }
+
+ public static DateTimeInt64 operator -(DateTimeInt64 dtValue1, long dtValue2)
+ {
+ dtValue1.Value -= dtValue2;
+ return dtValue1;
+ }
+
+ public static DateTimeInt64 operator +(DateTimeInt64 dtValue1, long dtValue2)
+ {
+ dtValue1.Value += dtValue2;
+ return dtValue1;
+ }
+
+ public static DateTimeInt64 operator ++(DateTimeInt64 dtValue)
+ {
+ dtValue.AddDays(1);
+ return dtValue;
+ }
+
+ public static DateTimeInt64 operator --(DateTimeInt64 dtValue)
+ {
+ dtValue.AddDays(-1);
+ return dtValue;
+ }
+
+ public static implicit operator long(DateTimeInt64 dtValue)
+ {
+ return dtValue.Value;
+ }
+
+ public static implicit operator DateTimeInt64(long ticks)
+ {
+ return new DateTimeInt64(ticks);
+ }
+
+ public static implicit operator DateTimeInt64(DateTime dt)
+ {
+ return new DateTimeInt64(dt);
+ }
+
+ public static implicit operator DateTime(DateTimeInt64 dt)
+ {
+ return dt.DateTime;
+ }
+
+ public static implicit operator double(DateTimeInt64 dtValue)
+ {
+ return dtValue.DoubleValue;
+ }
+
+ public static implicit operator DateTimeInt64(double ticks)
+ {
+ return new DateTimeInt64(ticks);
+ }
+
+ public static bool operator ==(DateTimeInt64 dtValue1, DateTimeInt64 dtValue2)
+ {
+ return dtValue1.Value == dtValue2.Value;
+ }
+
+ public static bool operator !=(DateTimeInt64 dtValue1, DateTimeInt64 dtValue2)
+ {
+ return dtValue1.Value != dtValue2.Value;
+ }
+
+ public static bool operator ==(DateTimeInt64 dtValue, long ticks)
+ {
+ return dtValue.Value == ticks;
+ }
+
+ public static bool operator !=(DateTimeInt64 dtValue, long ticks)
+ {
+ return dtValue.Value != ticks;
+ }
+
+ public static bool operator <(DateTimeInt64 dtValue1, DateTimeInt64 dtValue2)
+ {
+ return dtValue1.Value < dtValue2.Value;
+ }
+
+ public static bool operator >(DateTimeInt64 dtValue1, DateTimeInt64 dtValue2)
+ {
+ return dtValue1.Value > dtValue2.Value;
+ }
+
+ public static bool operator <=(DateTimeInt64 dtValue1, DateTimeInt64 dtValue2)
+ {
+ return dtValue1.Value <= dtValue2.Value;
+ }
+
+ public static bool operator >=(DateTimeInt64 dtValue1, DateTimeInt64 dtValue2)
+ {
+ return dtValue1.Value >= dtValue2.Value;
+ }
+
+ public static bool operator <(DateTimeInt64 dtValue, long ticks)
+ {
+ return dtValue.Value < ticks;
+ }
+
+ public static bool operator >(DateTimeInt64 dtValue, long ticks)
+ {
+ return dtValue.Value > ticks;
+ }
+
+ public static bool operator <=(DateTimeInt64 dtValue, long ticks)
+ {
+ return dtValue.Value <= ticks;
+ }
+
+ public static bool operator >=(DateTimeInt64 dtValue, long ticks)
+ {
+ return dtValue.Value >= ticks;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is DateTimeInt64 dtValue)
+ {
+ return dtValue.Value == Value;
+ }
+ else if (obj is long longValue)
+ {
+ return longValue == Value;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public override int GetHashCode()
+ {
+ return Value.GetHashCode();
+ }
+
+ int IComparable.CompareTo(object obj)
+ {
+ if (!(obj is DateTimeInt64)) throw new ArgumentException();
+ return (Value).CompareTo(((DateTimeInt64)obj).Value);
+ }
+
+ public string ToString(long ticks)
+ {
+ return ToString(ticks, DefaultFormatString);
+ }
+
+ public override string ToString()
+ {
+ return ToString(Value, DefaultFormatString);
+ }
+
+ public string ToString(string fmtStr)
+ {
+ return ToString(Value, fmtStr);
+ }
+
+ public static string ToString(long dtValue, string fmtStr)
+ {
+ DateTime dt = TicksToDateTime(dtValue);
+ return dt.ToString(fmtStr);
+ }
+
+ public bool Equals(DateTimeInt64 dtValue)
+ {
+ return Value == dtValue.Value;
+ }
+
+ public bool Equals(long ticks)
+ {
+ return Value == ticks;
+ }
+
+ public bool Equals(DateTime datetime)
+ {
+ return Value == (new DateTimeInt64(datetime)).Value;
+ }
+
+ public string DateTimeString => DateTime.DateTimeString();
+
+ public string DateString => DateTime.DateString();
+
+ public string TimeString => DateTime.TimeString();
+
+ public string HourMinuteString => DateTime.ToString("HH:mm");
+
+ public int Year => DateTime.Year;
+ public int Month => DateTime.Month;
+ public int Day => DateTime.Day;
+ public int Hour => DateTime.Hour;
+ public int Minute => DateTime.Minute;
+ public int Second => DateTime.Second;
+ public int Millisecond => DateTime.Millisecond;
+ }
+}
\ No newline at end of file
diff --git a/SunnyUI/Common/UIniFile.cs b/SunnyUI/Common/UIniFile.cs
index 29641df8..365e0e4a 100644
--- a/SunnyUI/Common/UIniFile.cs
+++ b/SunnyUI/Common/UIniFile.cs
@@ -22,7 +22,6 @@
* 2023-08-11: v3.4.1 增加了文件绝对路径判断和文件夹是否存在判断
******************************************************************************/
-using Sunny.UI.Win32;
using System;
using System.Collections.Specialized;
using System.ComponentModel;
@@ -31,6 +30,7 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
+using Sunny.UI.Win32;
namespace Sunny.UI
{
@@ -299,29 +299,6 @@ namespace Sunny.UI
///
public class IniFile : IniBase
{
- ///
- /// 写Byte数组
- ///
- /// section
- /// key
- /// value
- public void Write(string section, string key, byte[] value)
- {
- Write(section, key, value.ToHexString());
- }
-
- ///
- /// 读Byte数组
- ///
- /// section
- /// key
- /// Normal
- /// 结果
- public byte[] ReadBytes(string section, string key, byte[] Default)
- {
- return Read(section, key, Default.ToHexString()).ToHexBytes();
- }
-
///
/// 写Char
///
diff --git a/SunnyUI/Common/UIniFileEx.cs b/SunnyUI/Common/UIniFileEx.cs
new file mode 100644
index 00000000..a9227a0b
--- /dev/null
+++ b/SunnyUI/Common/UIniFileEx.cs
@@ -0,0 +1,790 @@
+/******************************************************************************
+ * SunnyUI 开源控件库、工具类库、扩展类库、多页面开发框架。
+ * CopyRight (C) 2012-2023 ShenYongHua(沈永华).
+ * QQ群:56829229 QQ:17612584 EMail:SunnyUI@QQ.Com
+ *
+ * Blog: https://www.cnblogs.com/yhuse
+ * Gitee: https://gitee.com/yhuse/SunnyUI
+ * GitHub: https://github.com/yhuse/SunnyUI
+ *
+ * SunnyUI.dll can be used for free under the GPL-3.0 license.
+ * If you use this code, please keep this note.
+ * 如果您使用此代码,请保留此说明。
+ ******************************************************************************
+ * 文件名称: UIniFileEx.cs
+ * 文件说明: INI 文件读取类(不用WinAPI)
+ * 当前版本: V3.1
+ * 创建日期: 2021-10-27
+ *
+ * 2021-10-27: V2.2.0 增加文件说明
+******************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.ComponentModel;
+using System.Drawing;
+using System.Globalization;
+using System.IO;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace Sunny.UI
+{
+ public class IniFileEx
+ {
+ private readonly Dictionary data = new Dictionary();
+
+ private static readonly Regex regRemoveEmptyLines =
+ new Regex
+ (
+ @"(\s*;[\d\D]*?\r?\n)+|\r?\n(\s*\r?\n)*",
+ RegexOptions.Multiline | RegexOptions.Compiled
+ );
+
+ private static readonly Regex regParseIniData =
+ new Regex
+ (
+ @"
+ (?
+ ^\s*\[(?[^\]]+)?\]\s*$
+ )
+ |
+ (?
+ ^\s*(?[^(\s*\=\s*)]+)?\s*\=\s*(?[\d\D]*)$
+ )",
+ RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace
+ );
+
+ public IniFileEx(string fileName) : this(fileName, Encoding.Default) { }
+
+ public IniFileEx(string fileName, Encoding encoding)
+ {
+ FileName = fileName;
+ Encoding = encoding;
+ using FileStream fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
+ ReadIniData(fs, encoding);
+ }
+
+ ///
+ /// 文件名
+ ///
+ [Description("文件名")]
+ public string FileName { get; set; } //INI文件名
+
+ public Encoding Encoding { get; set; }
+
+ private void ReadIniData(Stream stream, Encoding encoding)
+ {
+ string lastSection = string.Empty;
+ data.Add(lastSection, new NameValueCollection());
+ if (stream != null && encoding != null)
+ {
+ using StreamReader reader = new StreamReader(stream, encoding);
+ string iniData = reader.ReadToEnd();
+
+ iniData = regRemoveEmptyLines.Replace(iniData, "\n");
+ string[] lines = iniData.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
+
+ foreach (string s in lines)
+ {
+ Match m = regParseIniData.Match(s);
+ if (m.Success)
+ {
+ if (m.Groups["IsSection"].Length > 0)
+ {
+ string sName = m.Groups["SectionName"].Value.ToLowerInvariant();
+ if (lastSection != sName)
+ {
+ lastSection = sName;
+ if (!data.ContainsKey(sName))
+ {
+ data.Add(sName, new NameValueCollection());
+ }
+ }
+ }
+ else if (m.Groups["IsKeyValue"].Length > 0)
+ {
+ data[lastSection].Add(m.Groups["Key"].Value, m.Groups["Value"].Value);
+ }
+ }
+ }
+ }
+ }
+
+ public NameValueCollection this[string section]
+ {
+ get
+ {
+ section = section.ToLowerInvariant();
+ if (!data.ContainsKey(section))
+ data.Add(section, new NameValueCollection());
+ return data[section];
+ }
+ }
+
+ public string this[string section, string key]
+ {
+ get => this[section][key];
+ set => this[section][key] = value;
+ }
+
+ public object this[string section, string key, Type t]
+ {
+ get
+ {
+ if (t == null || t == (Type)Type.Missing)
+ return this[section][key];
+ return GetValue(section, key, null, t);
+ }
+ set
+ {
+ if (t == null || t == (Type)Type.Missing)
+ this[section][key] = string.Empty;
+ else
+ SetValue(section, key, value);
+ }
+ }
+
+ public string[] KeyNames(string section)
+ {
+ return this[section].AllKeys;
+ }
+
+ public string[] SectionValues(string section)
+ {
+ return this[section].GetValues(0);
+ }
+
+ private object GetValue(string section, string key, object defaultValue, Type t)
+ {
+ section = section.ToLowerInvariant();
+ key = key.ToLowerInvariant();
+ if (!data.ContainsKey(section)) return defaultValue;
+ string v = data[section][key];
+ if (string.IsNullOrEmpty(v)) return defaultValue;
+ TypeConverter conv = TypeDescriptor.GetConverter(t);
+ if (!conv.CanConvertFrom(typeof(string))) return defaultValue;
+
+ try
+ {
+ return conv.ConvertFrom(v);
+ }
+ catch
+ {
+ return defaultValue;
+ }
+ }
+
+ private T GetValue(string section, string key, T defaultValue)
+ {
+ return (T)GetValue(section, key, defaultValue, typeof(T));
+ }
+
+ private void SetValue(string section, string key, object value)
+ {
+ if (value == null)
+ {
+ this[section][key] = string.Empty;
+ }
+ else
+ {
+ TypeConverter conv = TypeDescriptor.GetConverter(value);
+ if (!conv.CanConvertTo(typeof(string)))
+ {
+ this[section][key] = value.ToString();
+ }
+ else
+ {
+ this[section][key] = (string)conv.ConvertTo(value, typeof(string));
+ }
+ }
+
+ UpdateFile();
+ }
+
+ public void Write(string section, string key, string value)
+ {
+ SetValue(section, key, value);
+ }
+
+ public string Read(string section, string key, string Default)
+ {
+ return GetValue(section, key, Default);
+ }
+
+ ///
+ /// 读取指定的Section的所有Value到列表中
+ ///
+ /// section
+ public NameValueCollection GetSectionValues(string section)
+ {
+ return this[section];
+ }
+
+ public void UpdateFile()
+ {
+ Save();
+ }
+
+ public void Save()
+ {
+ Save(FileName, Encoding);
+ }
+
+ public void Save(string fileName, Encoding encoding)
+ {
+ using FileStream fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
+ Save(fs, encoding);
+ }
+
+ private void Save(Stream stream, Encoding encoding)
+ {
+ using StreamWriter sw = new StreamWriter(stream, encoding);
+ foreach (var cur in data)
+ {
+ if (!string.IsNullOrEmpty(cur.Key))
+ {
+ sw.WriteLine("[{0}]", cur.Key);
+ }
+
+ NameValueCollection col = cur.Value;
+ foreach (string key in col.Keys)
+ {
+ if (!string.IsNullOrEmpty(key))
+ {
+ string value = col[key];
+ if (!string.IsNullOrEmpty(value))
+ sw.WriteLine("{0}={1}", key, value);
+ }
+ }
+ }
+
+ sw.Flush();
+ }
+
+ public bool HasSection(string section)
+ {
+ return data.ContainsKey(section.ToLowerInvariant());
+ }
+
+ public bool HasKey(string section, string key)
+ {
+ return
+ data.ContainsKey(section) &&
+ !string.IsNullOrEmpty(data[section][key]);
+ }
+
+ ///
+ /// 写结构
+ ///
+ /// section
+ /// key
+ /// value
+ /// T
+ public void WriteStruct(string section, string key, T value) where T : struct
+ {
+ Write(section, key, value.ToBytes());
+ }
+
+ ///
+ /// 读结构
+ ///
+ /// T
+ /// section
+ /// key
+ /// Normal
+ /// 结果
+ public T ReadStruct(string section, string key, T Default) where T : struct
+ {
+ //得到结构体的大小
+ int size = StructEx.Size(Default);
+ byte[] bytes = Read(section, key, "").ToHexBytes();
+ return size > bytes.Length ? Default : bytes.ToStruct();
+ }
+
+ ///
+ /// 写Byte数组
+ ///
+ /// section
+ /// key
+ /// value
+ public void Write(string section, string key, byte[] value)
+ {
+ Write(section, key, value.ToHexString());
+ }
+
+ ///
+ /// 读Byte数组
+ ///
+ /// section
+ /// key
+ /// Normal
+ /// 结果
+ public byte[] ReadBytes(string section, string key, byte[] Default)
+ {
+ return Read(section, key, Default.ToHexString()).ToHexBytes();
+ }
+
+ ///
+ /// 写Char
+ ///
+ /// section
+ /// key
+ /// value
+ public void Write(string section, string key, char value)
+ {
+ Write(section, key, value.ToString());
+ }
+
+ ///
+ /// 读Char
+ ///
+ /// section
+ /// key
+ /// Normal
+ /// 结果
+ public char ReadChar(string section, string key, char Default = ' ')
+ {
+ return Read(section, key, Default.ToString()).ToChar(Default);
+ }
+
+ ///
+ /// 写Decimal
+ ///
+ /// section
+ /// key
+ /// value
+ public void Write(string section, string key, decimal value)
+ {
+ Write(section, key, value.ToString(CultureInfo.InvariantCulture));
+ }
+
+ ///
+ /// 读Decimal
+ ///
+ /// section
+ /// key
+ /// Normal
+ /// 结果
+ public decimal ReadDecimal(string section, string key, decimal Default = 0)
+ {
+ return Read(section, key, Default.ToString(CultureInfo.InvariantCulture)).ToDecimal(Default);
+ }
+
+ ///
+ /// 写整数
+ ///
+ /// section
+ /// key
+ /// value
+ public void Write(string section, string key, short value)
+ {
+ Write(section, key, value.ToString());
+ }
+
+ ///
+ /// 读整数
+ ///
+ /// section
+ /// key
+ /// Normal
+ /// 结果
+ public short ReadShort(string section, string key, short Default = 0)
+ {
+ return Read(section, key, Default.ToString()).ToShort(Default);
+ }
+
+ ///
+ /// 写整数
+ ///
+ /// section
+ /// key
+ /// value
+ public void Write(string section, string key, ushort value)
+ {
+ Write(section, key, value.ToString());
+ }
+
+ ///
+ /// 读整数
+ ///
+ /// section
+ /// key
+ /// Normal
+ /// 结果
+ public ushort ReadUShort(string section, string key, ushort Default = 0)
+ {
+ return Read(section, key, Default.ToString()).ToUShort(Default);
+ }
+
+ ///
+ /// 写整数
+ ///
+ /// section
+ /// key
+ /// value
+ public void Write(string section, string key, int value)
+ {
+ Write(section, key, value.ToString());
+ }
+
+ ///
+ /// 读整数
+ ///
+ /// section
+ /// key
+ /// Normal
+ /// 结果
+ public int ReadInt(string section, string key, int Default = 0)
+ {
+ return Read(section, key, Default.ToString()).ToInt(Default);
+ }
+
+ ///
+ /// 写整数
+ ///
+ /// section
+ /// key
+ /// value
+ public void Write(string section, string key, uint value)
+ {
+ Write(section, key, value.ToString());
+ }
+
+ ///
+ /// 读整数
+ ///
+ /// section
+ /// key
+ /// Normal
+ /// 结果
+ public uint ReadUInt(string section, string key, uint Default = 0)
+ {
+ return Read(section, key, Default.ToString()).ToUInt(Default);
+ }
+
+ ///
+ /// 写整数
+ ///
+ /// section
+ /// key
+ /// value
+ public void Write(string section, string key, ulong value)
+ {
+ Write(section, key, value.ToString());
+ }
+
+ ///
+ /// 读整数
+ ///
+ /// section
+ /// key
+ /// Normal
+ /// 结果
+ public ulong ReadULong(string section, string key, ulong Default = 0)
+ {
+ return Read(section, key, Default.ToString()).ToULong(Default);
+ }
+
+ ///
+ /// 写整数
+ ///
+ /// section
+ /// key
+ /// value
+ public void Write(string section, string key, long value)
+ {
+ Write(section, key, value.ToString());
+ }
+
+ ///
+ /// 读整数
+ ///
+ /// section
+ /// key
+ /// Normal
+ /// 结果
+ public long ReadLong(string section, string key, long Default = 0)
+ {
+ return Read(section, key, Default.ToString()).ToLong(Default);
+ }
+
+ ///
+ /// 写布尔
+ ///
+ /// section
+ /// key
+ /// value
+ public void Write(string section, string key, bool value)
+ {
+ Write(section, key, value ? bool.TrueString : bool.FalseString);
+ }
+
+ ///
+ /// 读布尔
+ ///
+ /// section
+ /// key
+ /// Normal
+ /// 结果
+ public bool ReadBool(string section, string key, bool Default = false)
+ {
+ string str = Read(section, key, Default.ToString());
+ if (string.Equals(str, bool.TrueString, StringComparison.CurrentCultureIgnoreCase))
+ {
+ return true;
+ }
+
+ if (string.Equals(str, bool.FalseString, StringComparison.CurrentCultureIgnoreCase))
+ {
+ return false;
+ }
+
+ return Default;
+ }
+
+ ///
+ /// 写Double
+ ///
+ /// section
+ /// key
+ /// value
+ public void Write(string section, string key, double value)
+ {
+ Write(section, key, value.ToString(CultureInfo.InvariantCulture));
+ }
+
+ ///
+ /// 读Double
+ ///
+ /// section
+ /// key
+ /// Normal
+ /// 结果
+ public double ReadDouble(string section, string key, double Default = 0)
+ {
+ return Read(section, key, Default.ToString(CultureInfo.InvariantCulture)).ToDouble(Default);
+ }
+
+ ///
+ /// 写Float
+ ///
+ /// section
+ /// key
+ /// value
+ public void Write(string section, string key, float value)
+ {
+ Write(section, key, value.ToString(CultureInfo.InvariantCulture));
+ }
+
+ ///
+ /// 读Float
+ ///
+ /// section
+ /// key
+ /// Normal
+ /// 结果
+ public float ReadFloat(string section, string key, float Default = 0)
+ {
+ return Read(section, key, Default.ToString(CultureInfo.InvariantCulture)).ToFloat(Default);
+ }
+
+ ///
+ /// 写Byte
+ ///
+ /// section
+ /// key
+ /// value
+ public void Write(string section, string key, byte value)
+ {
+ Write(section, key, value.ToString());
+ }
+
+ ///
+ /// 读Byte
+ ///
+ /// section
+ /// key
+ /// Normal
+ /// 结果
+ public byte ReadByte(string section, string key, byte Default = 0)
+ {
+ return Read(section, key, Default.ToString()).ToByte(Default);
+ }
+
+ ///
+ /// 写SByte
+ ///
+ /// section
+ /// key
+ /// value
+ public void Write(string section, string key, sbyte value)
+ {
+ Write(section, key, value.ToString());
+ }
+
+ ///
+ /// 读Byte
+ ///
+ /// section
+ /// key
+ /// Normal
+ /// 结果
+ public sbyte ReadSByte(string section, string key, sbyte Default = 0)
+ {
+ return Read(section, key, Default.ToString()).ToSByte(Default);
+ }
+
+ ///
+ /// 写DateTime
+ ///
+ /// section
+ /// key
+ /// value
+ public void Write(string section, string key, DateTime value)
+ {
+ Write(section, key, value.ToString(DateTimeEx.DateTimeFormat));
+ }
+
+ ///
+ /// 读DateTime
+ ///
+ /// section
+ /// key
+ /// Normal
+ /// 结果
+ public DateTime ReadDateTime(string section, string key, DateTime Default)
+ {
+ string str = Read(section, key, Default.ToString(CultureInfo.InvariantCulture));
+ try
+ {
+ return str.ToDateTime(DateTimeEx.DateTimeFormat);
+ }
+ catch (Exception)
+ {
+ return Default;
+ }
+ }
+
+ ///
+ /// 写Point
+ ///
+ /// section
+ /// key
+ /// value
+ public void Write(string section, string key, Point value)
+ {
+ Write(section, key, ConvertEx.ObjectToString(value, typeof(Point)));
+ }
+
+ ///
+ /// 读Point
+ ///
+ /// section
+ /// key
+ /// Normal
+ /// 结果
+ public Point ReadPoint(string section, string key, Point Default)
+ {
+ string str = Read(section, key, "");
+ return (Point)ConvertEx.StringToObject(str, typeof(Point), Default);
+ }
+
+ ///
+ /// 写PointF
+ ///
+ /// section
+ /// key
+ /// value
+ public void Write(string section, string key, PointF value)
+ {
+ Write(section, key, ConvertEx.ObjectToString(value, typeof(PointF)));
+ }
+
+ ///
+ /// 读PointF
+ ///
+ /// section
+ /// key
+ /// Normal
+ /// 结果
+ public PointF ReadPointF(string section, string key, PointF Default)
+ {
+ string str = Read(section, key, "");
+ return (PointF)ConvertEx.StringToObject(str, typeof(PointF), Default);
+ }
+
+ ///
+ /// 写Size
+ ///
+ /// section
+ /// key
+ /// value
+ public void Write(string section, string key, Size value)
+ {
+ Write(section, key, ConvertEx.ObjectToString(value, typeof(Size)));
+ }
+
+ ///
+ /// 读Size
+ ///
+ /// section
+ /// key
+ /// Normal
+ /// 结果
+ public Size ReadSize(string section, string key, Size Default)
+ {
+ string str = Read(section, key, "");
+ return (Size)ConvertEx.StringToObject(str, typeof(Size), Default);
+ }
+
+ ///
+ /// 写SizeF
+ ///
+ /// section
+ /// key
+ /// value
+ public void Write(string section, string key, SizeF value)
+ {
+ Write(section, key, ConvertEx.ObjectToString(value, typeof(SizeF)));
+ }
+
+ ///
+ /// 读SizeF
+ ///
+ /// section
+ /// key
+ /// Normal
+ /// 结果
+ public SizeF ReadSizeF(string section, string key, SizeF Default)
+ {
+ string str = Read(section, key, "");
+ return (SizeF)ConvertEx.StringToObject(str, typeof(SizeF), Default);
+ }
+
+ ///
+ /// 写Color
+ ///
+ /// section
+ /// key
+ /// value
+ public void Write(string section, string key, Color value)
+ {
+ Write(section, key, ConvertEx.ObjectToString(value, typeof(Color)));
+ }
+
+ ///
+ /// 读Color
+ ///
+ /// section
+ /// key
+ /// Normal
+ /// 结果
+ public Color ReadColor(string section, string key, Color Default)
+ {
+ string str = Read(section, key, "");
+ return (Color)ConvertEx.StringToObject(str, typeof(Color), Default);
+ }
+ }
+}
diff --git a/SunnyUI/Common/UMapper.cs b/SunnyUI/Common/UMapper.cs
new file mode 100644
index 00000000..38fcf21c
--- /dev/null
+++ b/SunnyUI/Common/UMapper.cs
@@ -0,0 +1,203 @@
+/******************************************************************************
+ * SunnyUI 开源控件库、工具类库、扩展类库、多页面开发框架。
+ * CopyRight (C) 2012-2023 ShenYongHua(沈永华).
+ * QQ群:56829229 QQ:17612584 EMail:SunnyUI@QQ.Com
+ *
+ * Blog: https://www.cnblogs.com/yhuse
+ * Gitee: https://gitee.com/yhuse/SunnyUI
+ * GitHub: https://github.com/yhuse/SunnyUI
+ *
+ * SunnyUI.dll can be used for free under the GPL-3.0 license.
+ * If you use this code, please keep this note.
+ * 如果您使用此代码,请保留此说明。
+ ******************************************************************************
+ * 文件名称: UMapper.cs
+ * 文件说明: 轻量级的对象映射框架,可以映射值类型(包括Struct),和以值类型构成的List和数组。
+ * 当前版本: V3.1
+ * 创建日期: 2021-09-30
+ *
+ * 2021-09-30: V3.0.7 增加文件说明
+******************************************************************************/
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+
+namespace Sunny.UI
+{
+ ///
+ /// 轻量级的对象映射框架
+ ///
+ public static class Mapper
+ {
+ private static void Execute(T1 source, T2 dest)
+ where T1 : class, new()
+ where T2 : class, new()
+ {
+ if (source == null || dest == null)
+ {
+ return;
+ }
+
+ var listSource = source.GetType().GetNeedProperties().ToDictionary(prop => prop.Name);
+ var listDest = dest.GetType().GetNeedProperties().ToDictionary(prop => prop.Name);
+
+ foreach (var item in listDest)
+ {
+ if (listSource.NotContainsKey(item.Key)) continue;
+
+ var sourceInfo = listSource[item.Key];
+ Type sourceType = sourceInfo.PropertyType;
+ object sourceValue = sourceInfo.GetValue(source, null);
+
+ var destInfo = item.Value;
+ Type destType = item.Value.PropertyType;
+
+ if (!sourceType.Equals(destType)) continue;
+ if (sourceType.IsValueType)
+ {
+ //Console.WriteLine("ValueType: " + item.Key + ", " + sourceType.FullName);
+ destInfo.SetValue(dest, sourceValue, null);
+ }
+ else
+ {
+ if (sourceType == typeof(string))
+ {
+ //Console.WriteLine("String: " + item.Key + ", " + sourceType.FullName);
+ destInfo.SetValue(dest, sourceValue, null);
+ continue;
+ }
+
+ if (sourceType.IsList())
+ {
+ //Console.WriteLine("List: " + item.Key + ", " + sourceType.FullName);
+ Type[] sourceTypes = sourceType.GetGenericArguments();
+ Type[] destTypes = destType.GetGenericArguments();
+ if (sourceTypes.Length != 1) continue;
+ if (destTypes.Length != 1) continue;
+ if (!sourceTypes[0].Equals(destTypes[0])) continue;
+
+ if (sourceValue == null)
+ {
+ destInfo.SetValue(dest, null, null);
+ }
+ else
+ {
+ Type typeDataList = typeof(List<>).MakeGenericType(destTypes[0]);
+ MethodInfo AddInfo = typeDataList.GetMethod("Add", BindingFlags.Public | BindingFlags.Instance);
+ if (AddInfo == null) continue;
+
+ if (sourceTypes[0].IsValueType || sourceTypes[0] == typeof(string))
+ {
+ object listvalue = typeDataList.InvokeMember(null, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.CreateInstance, null, null, new object[] { });
+ IEnumerable sourceList = sourceValue as IEnumerable;
+ foreach (var listItem in sourceList)
+ {
+ AddInfo.Invoke(listvalue, new[] { listItem });
+ }
+
+ destInfo.SetValue(dest, listvalue, null);
+ }
+ else
+ {
+ //暂时不考虑
+ }
+ }
+
+ continue;
+ }
+
+ if (sourceType.IsArray)
+ {
+ //Console.WriteLine("Array: " + item.Key + ", " + sourceType.FullName);
+ if (sourceValue == null)
+ {
+ destInfo.SetValue(dest, null, null);
+ }
+ else
+ {
+ ICollection sourceList = sourceValue as ICollection;
+ Type type = sourceType.GetElementType();
+ var array = Array.CreateInstance(type, sourceList.Count);
+
+ int index = 0;
+ foreach (var listItem in sourceList)
+ {
+ array.SetValue(listItem, index++);
+ }
+
+ destInfo.SetValue(dest, array, null);
+ }
+
+ continue;
+ }
+
+ if (sourceType.IsDictionary())
+ {
+
+ continue;
+ }
+
+ //类没有无参构造函数的话,创建有问题
+ //if (sourceType.IsClass)
+ //{
+ // if (sourceValue == null)
+ // {
+ // destInfo.SetValue(dest, null, null);
+ // }
+ // else
+ // {
+ // object obj = Activator.CreateInstance(sourceType, null);
+ // obj.MapperFrom(sourceValue);
+ // destInfo.SetValue(dest, obj, null);
+ // }
+ //
+ // continue;
+ //}
+ }
+ }
+ }
+
+ ///
+ /// T1映射到T2
+ ///
+ /// T1
+ /// T2
+ /// 源
+ /// 目标
+ public static void MapperTo(this T1 source, T2 dest)
+ where T1 : class, new()
+ where T2 : class, new()
+ {
+ Execute(source, dest);
+ }
+
+ ///
+ /// T1从T2映射
+ ///
+ /// T1
+ /// T2
+ /// 源
+ /// 目标
+ public static void MapperFrom(this T1 dest, T2 source)
+ where T1 : class, new()
+ where T2 : class, new()
+ {
+ Execute(source, dest);
+ }
+
+ ///
+ /// 获取数组的类类型
+ ///
+ /// 类型
+ /// 类类型
+ public static Type GetArrayElementType(this Type t)
+ {
+ if (!t.IsArray) return null;
+ string name = t.FullName.Replace("[]", string.Empty);
+ return t.Assembly.GetType(name);
+ }
+ }
+}
diff --git a/SunnyUI/Common/UThunder.cs b/SunnyUI/Common/UThunder.cs
index a9b2720d..956cb1d7 100644
--- a/SunnyUI/Common/UThunder.cs
+++ b/SunnyUI/Common/UThunder.cs
@@ -22,9 +22,9 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
-using System.Windows.Forms;
#pragma warning disable 1591
@@ -32,7 +32,7 @@ namespace Sunny.UI
{
public class Thunder : IDisposable
{
- private readonly Timer timer;
+ private readonly System.Windows.Forms.Timer timer;
private bool Exit;
public delegate void OnTaskInfoChange(object sender, ThunderTask task);
@@ -52,7 +52,7 @@ namespace Sunny.UI
public Thunder()
{
InitSuccess = ThunderDll.Init();
- timer = new Timer();
+ timer = new System.Windows.Forms.Timer();
timer.Interval = 1000;
timer.Tick += Timer_Tick;
timer.Start();
@@ -512,7 +512,7 @@ namespace Sunny.UI
public override string ToString()
{
- return Status.DisplayText() + ",已完成:" + (Percent * 100.0f).ToString("F2") + "%,速度:" + Speed + "KB/s";
+ return Status.Description() + ",已完成:" + (Percent * 100.0f).ToString("F2") + "%,速度:" + Speed + "KB/s";
}
}
@@ -524,43 +524,43 @@ namespace Sunny.UI
///
/// 无
///
- [DisplayText("无")]
+ [Description("无")]
NOITEM = 0,
///
/// 错误
///
- [DisplayText("错误")]
+ [Description("错误")]
TSC_ERROR,
///
/// 暂停
///
- [DisplayText("暂停")]
+ [Description("暂停")]
TSC_PAUSE,
///
/// 下载
///
- [DisplayText("下载中")]
+ [Description("下载中")]
TSC_DOWNLOAD,
///
/// 完成
///
- [DisplayText("完成")]
+ [Description("完成")]
TSC_COMPLETE,
///
/// 停止开始
///
- [DisplayText("已开始")]
+ [Description("已开始")]
TSC_STARTENDING,
///
/// 停止完成
///
- [DisplayText("已停止")]
+ [Description("已停止")]
TSC_STOPENDING
}
diff --git a/SunnyUI/Common/UXmlConfig.cs b/SunnyUI/Common/UXmlConfig.cs
new file mode 100644
index 00000000..d74176e5
--- /dev/null
+++ b/SunnyUI/Common/UXmlConfig.cs
@@ -0,0 +1,163 @@
+/******************************************************************************
+ * SunnyUI 开源控件库、工具类库、扩展类库、多页面开发框架。
+ * CopyRight (C) 2012-2023 ShenYongHua(沈永华).
+ * QQ群:56829229 QQ:17612584 EMail:SunnyUI@QQ.Com
+ *
+ * Blog: https://www.cnblogs.com/yhuse
+ * Gitee: https://gitee.com/yhuse/SunnyUI
+ * GitHub: https://github.com/yhuse/SunnyUI
+ *
+ * SunnyUI.Common.dll can be used for free under the MIT license.
+ * If you use this code, please keep this note.
+ * 如果您使用此代码,请保留此说明。
+ ******************************************************************************
+ * 文件名称: UXmlConfig.cs
+ * 文件说明: XML 配置文件类
+ * 当前版本: V3.1
+ * 创建日期: 2020-01-01
+ *
+ * 2020-01-01: V2.2.0 增加文件说明
+******************************************************************************/
+
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Xml;
+
+namespace Sunny.UI
+{
+ ///
+ /// XML 配置文件类
+ ///
+ /// 类型
+ public class XmlConfig : BaseConfig where TConfig : XmlConfig, new()
+ {
+ #region 加载
+ ///
+ /// 当前可执行文件路径,末尾包括\
+ ///
+ /// 结果
+ private static string CurrentDir()
+ {
+ return Environment.CurrentDirectory.DealPath();
+ }
+
+ /// 加载指定配置文件
+ /// 文件名
+ /// 结果
+ public override bool Load(string filename)
+ {
+ if (filename.IsNullOrWhiteSpace())
+ {
+ filename = CurrentDir() + ConfigFile;
+ }
+
+ if (filename.IsNullOrWhiteSpace())
+ {
+ throw new ApplicationException($"未指定{typeof(TConfig).Name}的配置文件路径!");
+ }
+
+ if (!File.Exists(filename))
+ {
+ return false;
+ }
+
+ try
+ {
+ ConcurrentDictionary idents = ConfigHelper.InitIdents(current);
+
+ XmlDocument doc = new XmlDocument();
+ doc.Load(filename);
+ XmlElement root = doc.DocumentElement; //获取根节点
+ foreach (Ident ident in idents.Values)
+ {
+ if (root != null)
+ {
+ var elements = root.GetElementsByTagName(ident.Key);
+ if (elements.Count == 1)
+ {
+ if (ident.IsList)
+ {
+ ident.Values.Clear();
+ foreach (XmlNode node in elements[0].ChildNodes)
+ {
+ ident.Values.Add(node.InnerText);
+ }
+ }
+ else
+ {
+ ident.Value = elements[0].InnerText;
+ }
+ }
+ }
+ }
+
+ ConfigHelper.LoadConfigValue(current, idents);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex.Message);
+ return false;
+ }
+ }
+
+ /// 保存到配置文件中去
+ /// 文件名
+ public override void Save(string filename)
+ {
+ if (filename.IsNullOrWhiteSpace())
+ {
+ filename = CurrentDir() + ConfigFile;
+ }
+
+ if (filename.IsNullOrWhiteSpace())
+ {
+ throw new ApplicationException($"未指定{typeof(TConfig).Name}的配置文件路径!");
+ }
+
+ ConcurrentDictionary idents = ConfigHelper.InitIdents(current);
+ ConfigHelper.SaveConfigValue(Current, idents);
+
+ List strs = new List { " ", " " };
+
+ strs.Add("<" + GetType().Name + ">");
+
+ SortedList slist = new SortedList();
+ foreach (var ident in idents.Values)
+ {
+ slist.Add(ident.Index, ident);
+ }
+
+ foreach (var ident in slist.Values)
+ {
+ if (!ident.Description.IsNullOrEmpty())
+ {
+ strs.Add(" ");
+ }
+
+ if (!ident.IsList)
+ {
+ strs.Add(" <" + ident.Key + ">" + ident.Value + "" + ident.Key + ">");
+ }
+ else
+ {
+ strs.Add(" <" + ident.Key + ">");
+ foreach (string value in ident.Values)
+ {
+ strs.Add(" " + value + "");
+ }
+
+ strs.Add(" " + ident.Key + ">");
+ }
+ }
+
+ strs.Add("" + GetType().Name + ">");
+ File.WriteAllLines(filename, strs.ToArray(), Encoding.UTF8);
+ }
+
+ #endregion 加载
+ }
+}
\ No newline at end of file
diff --git a/SunnyUI/Controls/UIRoundMeter.cs b/SunnyUI/Controls/UIRoundMeter.cs
index 87cc45b6..7fb758af 100644
--- a/SunnyUI/Controls/UIRoundMeter.cs
+++ b/SunnyUI/Controls/UIRoundMeter.cs
@@ -22,7 +22,6 @@
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
-using Sunny.UI.Properties;
namespace Sunny.UI
{
@@ -45,7 +44,7 @@ namespace Sunny.UI
Custom,
///
- /// The GPS
+ /// The Gps
///
Gps,
@@ -133,14 +132,14 @@ namespace Sunny.UI
if (value == TMeterType.Gps)
{
- BackgroundImage = Resources.gps1;
- AngleImage = Resources.gps_postion;
+ BackgroundImage = Sunny.UI.Properties.Resources.gps1;
+ AngleImage = Sunny.UI.Properties.Resources.gps_postion;
}
if (value == TMeterType.Wind)
{
- BackgroundImage = Resources.wind;
- AngleImage = Resources.wind_postion;
+ BackgroundImage = Sunny.UI.Properties.Resources.wind;
+ AngleImage = Sunny.UI.Properties.Resources.wind_postion;
}
Invalidate();
diff --git a/SunnyUI/Controls/UIVerificationCode.cs b/SunnyUI/Controls/UIVerificationCode.cs
index 94183d30..f5968fcb 100644
--- a/SunnyUI/Controls/UIVerificationCode.cs
+++ b/SunnyUI/Controls/UIVerificationCode.cs
@@ -97,10 +97,39 @@ namespace Sunny.UI
{
base.OnPaintFill(g, path);
- using var bmp = CreateImage(RandomEx.RandomChars(CodeLength));
+ using var bmp = CreateImage(RandomChars(CodeLength));
g.DrawImage(bmp, Width / 2 - bmp.Width / 2, 1);
}
+ private const string CHARS_62 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+
+ ///
+ /// 生成字母和数字的随机字符串
+ ///
+ /// 长度
+ /// 结果
+ private static string RandomChars(int length = 10)
+ {
+ return RandomBase(CHARS_62.ToCharArray(), length);
+ }
+
+ private static string RandomBase(char[] pattern, int length)
+ {
+ if (pattern.IsNullOrEmpty())
+ {
+ throw new ArgumentNullException();
+ }
+
+ string result = "";
+ for (int i = 0; i < length; i++)
+ {
+ Random random = new Random(DateTime.Now.Millisecond);
+ result += pattern[random.Next(0, pattern.Length)];
+ }
+
+ return result;
+ }
+
///
/// 绘制前景颜色
///
diff --git a/SunnyUI/Forms/UILoginForm.cs b/SunnyUI/Forms/UILoginForm.cs
index 0ee362db..722e0aaa 100644
--- a/SunnyUI/Forms/UILoginForm.cs
+++ b/SunnyUI/Forms/UILoginForm.cs
@@ -20,7 +20,6 @@
* 2023-04-19: V3.3.5 增加可选择显示时激活的控件
******************************************************************************/
-using Sunny.UI.Properties;
using System;
using System.ComponentModel;
@@ -96,12 +95,12 @@ namespace Sunny.UI
{
loginImage = value;
- if (loginImage == UILoginImage.Login1) BackgroundImage = Resources.Login1;
- if (loginImage == UILoginImage.Login2) BackgroundImage = Resources.Login2;
- if (loginImage == UILoginImage.Login3) BackgroundImage = Resources.Login3;
- if (loginImage == UILoginImage.Login4) BackgroundImage = Resources.Login4;
- if (loginImage == UILoginImage.Login5) BackgroundImage = Resources.Login5;
- if (loginImage == UILoginImage.Login6) BackgroundImage = Resources.Login6;
+ if (loginImage == UILoginImage.Login1) BackgroundImage = Sunny.UI.Properties.Resources.Login1;
+ if (loginImage == UILoginImage.Login2) BackgroundImage = Sunny.UI.Properties.Resources.Login2;
+ if (loginImage == UILoginImage.Login3) BackgroundImage = Sunny.UI.Properties.Resources.Login3;
+ if (loginImage == UILoginImage.Login4) BackgroundImage = Sunny.UI.Properties.Resources.Login4;
+ if (loginImage == UILoginImage.Login5) BackgroundImage = Sunny.UI.Properties.Resources.Login5;
+ if (loginImage == UILoginImage.Login6) BackgroundImage = Sunny.UI.Properties.Resources.Login6;
}
}
}
diff --git a/SunnyUI/Style/UIMenuStyle.cs b/SunnyUI/Style/UIMenuStyle.cs
index 44e7baa8..386f4fca 100644
--- a/SunnyUI/Style/UIMenuStyle.cs
+++ b/SunnyUI/Style/UIMenuStyle.cs
@@ -19,6 +19,7 @@
* 2020-01-01: V2.2.0 增加文件说明
******************************************************************************/
+using System.ComponentModel;
using System.Drawing;
namespace Sunny.UI
@@ -31,19 +32,19 @@ namespace Sunny.UI
///
/// 自定义
///
- [DisplayText("Custom")]
+ [Description("Custom")]
Custom,
///
/// 黑
///
- [DisplayText("Black")]
+ [Description("Black")]
Black,
///
/// 白
///
- [DisplayText("White")]
+ [Description("White")]
White
}
@@ -59,7 +60,7 @@ namespace Sunny.UI
public override string ToString()
{
- return Style.DisplayText();
+ return Style.Description();
}
}
diff --git a/SunnyUI/Style/UIStyle.cs b/SunnyUI/Style/UIStyle.cs
index bcf8b8a3..57d14f74 100644
--- a/SunnyUI/Style/UIStyle.cs
+++ b/SunnyUI/Style/UIStyle.cs
@@ -25,6 +25,7 @@
******************************************************************************/
using System.Collections.Generic;
+using System.ComponentModel;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
@@ -55,85 +56,85 @@ namespace Sunny.UI
///
/// 继承的全局主题
///
- [DisplayText("继承的全局主题")]
+ [Description("继承的全局主题")]
Inherited = -1,
///
/// 自定义
///
- [DisplayText("Custom")]
+ [Description("Custom")]
Custom = 0,
///
/// 蓝
///
- [DisplayText("Blue")]
+ [Description("Blue")]
Blue = 1,
///
/// 绿
///
- [DisplayText("Green")]
+ [Description("Green")]
Green = 2,
///
/// 橙
///
- [DisplayText("Orange")]
+ [Description("Orange")]
Orange = 3,
///
/// 红
///
- [DisplayText("Red")]
+ [Description("Red")]
Red = 4,
///
/// 灰
///
- [DisplayText("Gray")]
+ [Description("Gray")]
Gray = 5,
///
/// 紫
///
- [DisplayText("Purple")]
+ [Description("Purple")]
Purple = 6,
///
/// LayuiGreen
///
- [DisplayText("LayuiGreen")]
+ [Description("LayuiGreen")]
LayuiGreen = 7,
///
/// LayuiRed
///
- [DisplayText("LayuiRed")]
+ [Description("LayuiRed")]
LayuiRed = 8,
///
/// LayuiOrange
///
- [DisplayText("LayuiOrange")]
+ [Description("LayuiOrange")]
LayuiOrange = 9,
///
/// 深蓝
///
- [DisplayText("DarkBlue")]
+ [Description("DarkBlue")]
DarkBlue = 101,
///
/// 黑
///
- [DisplayText("Black")]
+ [Description("Black")]
Black = 102,
///
/// 多彩的
///
- [DisplayText("Colorful")]
+ [Description("Colorful")]
Colorful = 999
}
diff --git a/SunnyUI/Style/UIStyleColor.cs b/SunnyUI/Style/UIStyleColor.cs
index 50ae6006..63bcbff6 100644
--- a/SunnyUI/Style/UIStyleColor.cs
+++ b/SunnyUI/Style/UIStyleColor.cs
@@ -419,7 +419,7 @@ namespace Sunny.UI
public override string ToString()
{
- return Name.DisplayText();
+ return Name.Description();
}
public virtual bool BuiltIn => true;
diff --git a/SunnyUI/Style/UTranslate.cs b/SunnyUI/Style/UTranslate.cs
index 54f39b45..cad4c42e 100644
--- a/SunnyUI/Style/UTranslate.cs
+++ b/SunnyUI/Style/UTranslate.cs
@@ -210,10 +210,11 @@ namespace Sunny.UI
string thisFullName = form.GetType().FullName;
string section = "Info";
- string inifile = Dir.CurrentDir() + "Language\\" + thisFullName + ".ini";
- if (!File.Exists(inifile)) return;
+ string fullName = Dir.CurrentDir() + "Language\\" + thisFullName + ".ini";
+ if (!File.Exists(fullName)) return;
IniFile ini = new IniFile(Dir.CurrentDir() + "Language\\" + thisFullName + ".ini", System.Text.Encoding.UTF8);
- int count = ini.ReadInt("Controls", "Count", 0);
+ string readString = ini.ReadString("Controls", "Count", "");
+ if (!int.TryParse(readString, out int count)) return;
if (count == 0) return;
string key = UIStyles.CultureInfo.LCID.ToString() + ".Name";
diff --git a/SunnyUI/SunnyUI.csproj b/SunnyUI/SunnyUI.csproj
index 76470461..5ebdf9d4 100644
--- a/SunnyUI/SunnyUI.csproj
+++ b/SunnyUI/SunnyUI.csproj
@@ -72,7 +72,7 @@
-
+