合并修改
This commit is contained in:
162
DH.Commons/Helper/AttributeHelper.cs
Normal file
162
DH.Commons/Helper/AttributeHelper.cs
Normal file
@ -0,0 +1,162 @@
|
||||
using DH.Commons.Enums;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using static DH.Commons.Enums.EnumHelper;
|
||||
|
||||
|
||||
namespace DH.Commons.Enums
|
||||
{
|
||||
/// <summary>
|
||||
/// 设备特性,指示该信息的设备类型,适用于设备信息和配置信息
|
||||
/// </summary>
|
||||
public class DeviceAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// 设备类型
|
||||
/// </summary>
|
||||
public string TypeCode { get; set; }
|
||||
|
||||
public string TypeDescription { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 特性修饰类别
|
||||
/// </summary>
|
||||
public DeviceAttributeType AttrType { get; set; }
|
||||
|
||||
public DeviceAttribute(string typeCode, string typeDesc, EnumHelper.DeviceAttributeType attrType)
|
||||
{
|
||||
TypeCode = typeCode;
|
||||
TypeDescription = typeDesc;
|
||||
AttrType = attrType;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 预置状态特性 指定该修饰信息的前置状态允许范围
|
||||
/// </summary>
|
||||
public class PreStateAttribute : Attribute
|
||||
{
|
||||
public int PreState { get; set; }
|
||||
public PreStateAttribute(int _preState)
|
||||
{
|
||||
PreState = _preState;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查当前待执行操作的前置状态要求是否合法
|
||||
/// </summary>
|
||||
/// <param name="currentState"></param>
|
||||
/// <returns></returns>
|
||||
public bool CheckPreStateValid(int currentState)
|
||||
{
|
||||
return (currentState & PreState) == currentState;
|
||||
}
|
||||
}
|
||||
|
||||
public class ColorSelectAttribute : Attribute
|
||||
{
|
||||
public string SelectedColor { get; set; }
|
||||
public ColorSelectAttribute(string selectedColor)
|
||||
{
|
||||
SelectedColor = selectedColor;
|
||||
}
|
||||
}
|
||||
|
||||
public class FontColorSelectAttribute : Attribute
|
||||
{
|
||||
public string SelectedColor { get; set; }
|
||||
public FontColorSelectAttribute(string selectedColor)
|
||||
{
|
||||
SelectedColor = selectedColor;
|
||||
}
|
||||
}
|
||||
|
||||
public enum InvokeType
|
||||
{
|
||||
/// <summary>
|
||||
/// 不公开调用
|
||||
/// </summary>
|
||||
[Description("不公开调用")]
|
||||
NoneInvoke = 0,
|
||||
/// <summary>
|
||||
/// 测试调用
|
||||
/// </summary>
|
||||
[Description("测试调用")]
|
||||
TestInvoke = 1,
|
||||
/// <summary>
|
||||
/// 标定调用
|
||||
/// </summary>
|
||||
[Description("标定调用")]
|
||||
CalibInvoke = 2,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用来修饰对外开放的调用方法的特性
|
||||
/// 调用方法参数顺序:IOperationConfig,InvokeDevice,SourceDevice
|
||||
/// </summary>
|
||||
public class ProcessMethodAttribute : Attribute
|
||||
{
|
||||
public string MethodCode { get; set; }
|
||||
public string MethodDesc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否提供人工调用测试
|
||||
/// </summary>
|
||||
public InvokeType InvokeType { get; set; }
|
||||
|
||||
public string DeviceType { get; set; }
|
||||
|
||||
public ProcessMethodAttribute(string deviceType, string code, string description, InvokeType invokeType)
|
||||
{
|
||||
DeviceType = deviceType;
|
||||
MethodCode = code;
|
||||
MethodDesc = description;
|
||||
InvokeType = invokeType;
|
||||
}
|
||||
}
|
||||
|
||||
public class SwitchDisplayAttribute : Attribute
|
||||
{
|
||||
public string SwitchName { get; set; }
|
||||
|
||||
public bool SwithOnStatus { get; set; } = true;
|
||||
|
||||
public SwitchDisplayAttribute(string name, bool status)
|
||||
{
|
||||
SwitchName = name;
|
||||
SwithOnStatus = status;
|
||||
}
|
||||
}
|
||||
|
||||
public class ElementAttribute : Attribute
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Desc { get; set; }
|
||||
|
||||
public string IconPath { get; set; }
|
||||
|
||||
public bool IsShowInToolBar { get; set; }
|
||||
|
||||
public ElementAttribute(string desc, string iconPath, bool isShowInToolBar = true, [CallerMemberName] string name = "")
|
||||
{
|
||||
Name = name;
|
||||
Desc = desc;
|
||||
IconPath = iconPath;
|
||||
IsShowInToolBar = isShowInToolBar;
|
||||
}
|
||||
}
|
||||
|
||||
public class ProcessAttribute : Attribute
|
||||
{
|
||||
public string ProcessCode { get; set; }
|
||||
public DeviceAttributeType AttrType { get; set; }
|
||||
|
||||
public ProcessAttribute(string stationCode, DeviceAttributeType attrType)
|
||||
{
|
||||
ProcessCode = stationCode;
|
||||
AttrType = attrType;
|
||||
}
|
||||
}
|
||||
}
|
280
DH.Commons/Helper/ConfigHelper.cs
Normal file
280
DH.Commons/Helper/ConfigHelper.cs
Normal file
@ -0,0 +1,280 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using AntdUI;
|
||||
using DH.Commons.Base;
|
||||
using DH.Commons.Enums;
|
||||
using DH.Commons.Models;
|
||||
|
||||
namespace DH.Commons.Helper
|
||||
{
|
||||
public static class ConfigHelper
|
||||
{
|
||||
private static readonly JsonSerializerOptions _jsonOptions = new JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
IgnoreNullValues = true
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// 配置存储根目录
|
||||
/// </summary>
|
||||
private static string ConfigsRoot => Path.Combine(
|
||||
AppDomain.CurrentDomain.BaseDirectory,
|
||||
"configs");
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前方案的主配置文件路径
|
||||
/// </summary>
|
||||
private static string CurrentConfigPath
|
||||
{
|
||||
get
|
||||
{
|
||||
ValidateCurrentScheme();
|
||||
return Path.Combine(
|
||||
ConfigsRoot,
|
||||
$"config_{SystemModel.CurrentScheme}.json");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前方案的备份目录路径
|
||||
/// </summary>
|
||||
private static string CurrentBackupDir
|
||||
{
|
||||
get
|
||||
{
|
||||
ValidateCurrentScheme();
|
||||
return Path.Combine(
|
||||
ConfigsRoot,
|
||||
$"bak_{SystemModel.CurrentScheme}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化新方案(创建空文件)
|
||||
/// </summary>
|
||||
public static void InitializeScheme(string scheme)
|
||||
{
|
||||
SystemModel.CurrentScheme = scheme;
|
||||
|
||||
// 创建空配置文件
|
||||
if (!File.Exists(CurrentConfigPath))
|
||||
{
|
||||
Directory.CreateDirectory(ConfigsRoot);
|
||||
File.WriteAllText(CurrentConfigPath, "{}");
|
||||
}
|
||||
|
||||
// 创建备份目录
|
||||
Directory.CreateDirectory(CurrentBackupDir);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存当前配置(自动备份)
|
||||
/// </summary>
|
||||
public static void SaveConfig()
|
||||
{
|
||||
ValidateCurrentScheme();
|
||||
|
||||
// 确保配置目录存在
|
||||
Directory.CreateDirectory(ConfigsRoot);
|
||||
|
||||
// 备份现有配置
|
||||
if (File.Exists(CurrentConfigPath))
|
||||
{
|
||||
var backupName = $"config_{SystemModel.CurrentScheme}_{DateTime.Now:yyyyMMddHHmmss}.json";
|
||||
var backupPath = Path.Combine(CurrentBackupDir, backupName);
|
||||
|
||||
Directory.CreateDirectory(CurrentBackupDir);
|
||||
File.Copy(CurrentConfigPath, backupPath);
|
||||
}
|
||||
//重置标签文件路径和内容
|
||||
ConfigModel.DetectionList.ForEach(config =>
|
||||
{
|
||||
GenerateLabelFile(config);
|
||||
});
|
||||
|
||||
// 序列化当前配置
|
||||
var json = JsonSerializer.Serialize(new
|
||||
{
|
||||
ConfigModel.CameraBaseList,
|
||||
ConfigModel.PLCBaseList,
|
||||
ConfigModel.DetectionList,
|
||||
ConfigModel.GlobalList,
|
||||
}, _jsonOptions);
|
||||
|
||||
// 写入新配置
|
||||
File.WriteAllText(CurrentConfigPath, json);
|
||||
}
|
||||
private static void GenerateLabelFile(DetectionConfig config)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (config.DetectionLableList == null || string.IsNullOrEmpty(config.In_lable_path))
|
||||
return;
|
||||
|
||||
// 确保目录存在
|
||||
var directory = Path.GetDirectoryName(config.In_lable_path);
|
||||
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
}
|
||||
|
||||
// 写入文件内容
|
||||
using (var writer = new StreamWriter(config.In_lable_path, false))
|
||||
{
|
||||
foreach (var label in config.DetectionLableList)
|
||||
{
|
||||
//是否假如判断标签为中文转为为英文
|
||||
//string pinyinlabel = FileHelper.ConvertHanzitoPinyinWithNumbers(label.LabelName.ToString());
|
||||
//if (FileHelper.IsAlphaNumericOnly(pinyinlabel))
|
||||
//{
|
||||
|
||||
//}
|
||||
|
||||
// 根据实际需求格式化输出
|
||||
writer.WriteLine(label.LabelName.ToString()); // 假设DetectionLable重写了ToString()
|
||||
|
||||
// 或者明确指定格式:
|
||||
// writer.WriteLine($"{label.Id},{label.Name},{label.Confidence}");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"生成标签文件失败: {ex.Message}");
|
||||
// 可以考虑记录更详细的日志
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 加载当前方案配置
|
||||
/// </summary>
|
||||
public static void LoadConfig()
|
||||
{
|
||||
ValidateCurrentScheme();
|
||||
|
||||
if (!File.Exists(CurrentConfigPath))
|
||||
{
|
||||
InitializeScheme(SystemModel.CurrentScheme);
|
||||
return;
|
||||
}
|
||||
|
||||
var json = File.ReadAllText(CurrentConfigPath);
|
||||
var data = JsonSerializer.Deserialize<ConfigData>(json, _jsonOptions);
|
||||
|
||||
ConfigModel.CameraBaseList = data?.Cameras ?? new List<CameraBase>();
|
||||
ConfigModel.DetectionList = data?.Detections ?? new List<DetectionConfig>();
|
||||
ConfigModel.PLCBaseList = data?.PLCs ?? new List<PLCBase>();
|
||||
ConfigModel.GlobalList = data?.GlobalConfigs ?? new List<GlobalConfig>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证当前方案有效性
|
||||
/// </summary>
|
||||
private static void ValidateCurrentScheme()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(SystemModel.CurrentScheme))
|
||||
throw new InvalidOperationException("当前方案未设置");
|
||||
}
|
||||
/// <summary>
|
||||
/// 派生新方案(基于当前方案创建副本)
|
||||
/// </summary>
|
||||
/// <param name="newSchemeName">新方案名称</param>
|
||||
public static void DeriveScheme(string newSchemeName)
|
||||
{
|
||||
// 验证输入
|
||||
if (string.IsNullOrWhiteSpace(newSchemeName))
|
||||
{
|
||||
throw new ArgumentException("新方案名称不能为空");
|
||||
}
|
||||
|
||||
// 验证当前方案是否有效
|
||||
ValidateCurrentScheme();
|
||||
|
||||
// 检查新方案是否已存在
|
||||
var newConfigPath = Path.Combine(ConfigsRoot, $"config_{newSchemeName}.json");
|
||||
if (File.Exists(newConfigPath))
|
||||
{
|
||||
throw new InvalidOperationException($"方案 {newSchemeName} 已存在");
|
||||
}
|
||||
|
||||
// 保存当前配置确保最新
|
||||
SaveConfig();
|
||||
|
||||
try
|
||||
{
|
||||
// 复制配置文件
|
||||
File.Copy(CurrentConfigPath, newConfigPath);
|
||||
|
||||
// 创建备份目录
|
||||
var newBackupDir = Path.Combine(ConfigsRoot, $"bak_{newSchemeName}");
|
||||
Directory.CreateDirectory(newBackupDir);
|
||||
|
||||
// 可选:自动切换新方案
|
||||
// SystemModel.CurrentScheme = newSchemeName;
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
throw new InvalidOperationException($"方案派生失败: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除指定方案的配置文件及备份目录
|
||||
/// </summary>
|
||||
/// <param name="schemeName">要删除的方案名称</param>
|
||||
/// <exception cref="ArgumentException">当方案名称为空时抛出</exception>
|
||||
/// <exception cref="IOException">文件操作失败时抛出</exception>
|
||||
public static void DeleteSchemeConfig(string schemeName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(schemeName))
|
||||
throw new ArgumentException("方案名称无效");
|
||||
|
||||
// 构造路径
|
||||
var configPath = Path.Combine(ConfigsRoot, $"config_{schemeName}.json");
|
||||
var backupDir = Path.Combine(ConfigsRoot, $"bak_{schemeName}");
|
||||
|
||||
try
|
||||
{
|
||||
// 删除配置文件
|
||||
if (File.Exists(configPath))
|
||||
{
|
||||
File.Delete(configPath);
|
||||
}
|
||||
|
||||
// 删除备份目录(递归删除)
|
||||
if (Directory.Exists(backupDir))
|
||||
{
|
||||
Directory.Delete(backupDir, true);
|
||||
}
|
||||
}
|
||||
catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException)
|
||||
{
|
||||
throw new IOException($"删除方案 {schemeName} 的配置文件失败: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 配置数据模型(内部类)
|
||||
/// </summary>
|
||||
private class ConfigData
|
||||
{
|
||||
[JsonPropertyName("cameraBaseList")]
|
||||
public List<CameraBase> Cameras { get; set; } = new List<CameraBase>();
|
||||
|
||||
[JsonPropertyName("plcBaseList")]
|
||||
public List<PLCBase> PLCs { get; set; } = new List<PLCBase>();
|
||||
|
||||
[JsonPropertyName("detectionList")]
|
||||
public List<DetectionConfig> Detections { get; set; } = new List<DetectionConfig>();
|
||||
[JsonPropertyName("globalList")]
|
||||
public List<GlobalConfig> GlobalConfigs { get; set; } = new List<GlobalConfig>();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -76,159 +76,83 @@ namespace DH.Commons.Enums
|
||||
}
|
||||
}
|
||||
|
||||
//public static System.Windows.Media.Color GetEnumSelectedMediaColor(this Enum enumObj)
|
||||
//{
|
||||
// Type t = enumObj.GetType();
|
||||
// FieldInfo f = t.GetField(enumObj.ToString());
|
||||
|
||||
// ColorSelectAttribute attr = f.GetCustomAttribute<ColorSelectAttribute>();
|
||||
// if (attr != null)
|
||||
// {
|
||||
// var prop = typeof(System.Windows.Media.Colors).GetProperties().FirstOrDefault(p => p.Name == attr.SelectedColor);
|
||||
// if (prop != null)
|
||||
// {
|
||||
// return (System.Windows.Media.Color)prop.GetValue(null);
|
||||
// }
|
||||
// }
|
||||
// return System.Windows.Media.Colors.Transparent;
|
||||
//}
|
||||
|
||||
//public static System.Drawing.Color GetEnumSelectedColor(this Enum enumObj)
|
||||
//{
|
||||
// Type t = enumObj.GetType();
|
||||
// FieldInfo f = t.GetField(enumObj.ToString());
|
||||
|
||||
// ColorSelectAttribute attr = f.GetCustomAttribute<ColorSelectAttribute>();
|
||||
// if (attr != null)
|
||||
// {
|
||||
// return System.Drawing.Color.FromName(attr.SelectedColor);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return System.Drawing.Color.Transparent;
|
||||
// }
|
||||
//}
|
||||
|
||||
//public static System.Drawing.Color GetEnumSelectedFontColor(this Enum enumObj)
|
||||
//{
|
||||
// Type t = enumObj.GetType();
|
||||
// FieldInfo f = t.GetField(enumObj.ToString());
|
||||
|
||||
// var attr = f.GetCustomAttribute<FontColorSelectAttribute>();
|
||||
// if (attr != null)
|
||||
// {
|
||||
// return System.Drawing.Color.FromName(attr.SelectedColor);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return System.Drawing.Color.Transparent;
|
||||
// }
|
||||
//}
|
||||
|
||||
//public static string GetEnumSelectedColorString(this Enum enumObj)
|
||||
//{
|
||||
// Type t = enumObj.GetType();
|
||||
// FieldInfo f = t.GetField(enumObj.ToString());
|
||||
|
||||
// ColorSelectAttribute attr = f.GetCustomAttribute<ColorSelectAttribute>();
|
||||
// if (attr != null)
|
||||
// {
|
||||
// return attr.SelectedColor;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return "Transparent";
|
||||
// }
|
||||
//}
|
||||
|
||||
// 根据描述获取枚举值(泛型方法)
|
||||
public static T GetEnumFromDescription<T>(string description) where T : Enum
|
||||
{
|
||||
Type enumType = typeof(T);
|
||||
foreach (T value in Enum.GetValues(enumType))
|
||||
{
|
||||
string desc = GetEnumDescription(value);
|
||||
if (desc == description)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
throw new ArgumentException($"在枚举 {enumType.Name} 中未找到描述为 '{description}' 的值");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当枚举牵涉到状态变换,检查现状态是否满足待转换的状态的前置状态要求
|
||||
/// 获取枚举类型的所有描述文本
|
||||
/// </summary>
|
||||
/// <param name="stateToBe"></param>
|
||||
/// <param name="currentState"></param>
|
||||
/// <returns></returns>
|
||||
//public static bool CheckPreStateValid(this Enum stateToBe, int currentState)
|
||||
//{
|
||||
// Type t = stateToBe.GetType();
|
||||
// FieldInfo f = t.GetField(stateToBe.ToString());
|
||||
/// <param name="enumType">枚举类型</param>
|
||||
/// <returns>描述文本列表</returns>
|
||||
public static List<string> GetEnumDescriptions(Type enumType)
|
||||
{
|
||||
// 验证类型是否为枚举
|
||||
if (!enumType.IsEnum)
|
||||
throw new ArgumentException("传入的类型必须是枚举类型", nameof(enumType));
|
||||
|
||||
// PreStateAttribute attr = f.GetCustomAttribute<PreStateAttribute>();
|
||||
// if (attr == null)
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return attr.CheckPreStateValid(currentState);
|
||||
// }
|
||||
//}
|
||||
var descriptions = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// 设备状态定义
|
||||
/// 未初始化和异常状态无前置状态要求
|
||||
/// 初始化操作前置状态必须是未初始化、关闭状态和异常状态
|
||||
/// 打开前置必须是初始化和暂停
|
||||
/// 关闭前置必须是打开和暂停和异常
|
||||
/// 暂停前置必须是打开
|
||||
/// </summary>
|
||||
//public enum DeviceState
|
||||
//{
|
||||
// TBD = -1,
|
||||
foreach (var value in Enum.GetValues(enumType))
|
||||
{
|
||||
var fieldInfo = enumType.GetField(value.ToString());
|
||||
var attribute = fieldInfo.GetCustomAttribute<DescriptionAttribute>();
|
||||
descriptions.Add(attribute?.Description ?? value.ToString());
|
||||
}
|
||||
|
||||
// [ColorSelect("Gray")]
|
||||
// [FontColorSelect("Black")]
|
||||
// [Description("未初始化")]
|
||||
// DSUninit = 1,
|
||||
return descriptions;
|
||||
}
|
||||
public static string GetEnumDescription1(Enum value)
|
||||
{
|
||||
var field = value.GetType().GetField(value.ToString());
|
||||
var attribute = field.GetCustomAttributes(typeof(DescriptionAttribute), false)
|
||||
.FirstOrDefault() as DescriptionAttribute;
|
||||
return attribute?.Description ?? value.ToString();
|
||||
}
|
||||
|
||||
// [ColorSelect("Gold")]
|
||||
// [FontColorSelect("White")]
|
||||
// [PreState(1 + 2 + 4 + 8 + 32)]
|
||||
// [Description("初始化")]
|
||||
// DSInit = 2,
|
||||
public static System.Drawing.Color GetEnumSelectedColor(this Enum enumObj)
|
||||
{
|
||||
Type t = enumObj.GetType();
|
||||
FieldInfo f = t.GetField(enumObj.ToString());
|
||||
|
||||
// [ColorSelect("Lime")]
|
||||
// [FontColorSelect("Black")]
|
||||
// [PreState(2 + 4 + 16)]
|
||||
// [Description("运行中")]
|
||||
// DSOpen = 4,
|
||||
ColorSelectAttribute attr = f.GetCustomAttribute<ColorSelectAttribute>();
|
||||
if (attr != null)
|
||||
{
|
||||
return System.Drawing.Color.FromName(attr.SelectedColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
return System.Drawing.Color.Transparent;
|
||||
}
|
||||
}
|
||||
|
||||
// [ColorSelect("Gray")]
|
||||
// [FontColorSelect("White")]
|
||||
// [PreState(1 + 4 + 8 + 16 + 32)]
|
||||
// [Description("关闭")]
|
||||
// DSClose = 8,
|
||||
public static System.Drawing.Color GetEnumSelectedFontColor(this Enum enumObj)
|
||||
{
|
||||
Type t = enumObj.GetType();
|
||||
FieldInfo f = t.GetField(enumObj.ToString());
|
||||
|
||||
// [ColorSelect("Gold")]
|
||||
// [FontColorSelect("White")]
|
||||
// [PreState(4 + 16)]
|
||||
// [Description("暂停")]
|
||||
// DSPause = 16,
|
||||
var attr = f.GetCustomAttribute<FontColorSelectAttribute>();
|
||||
if (attr != null)
|
||||
{
|
||||
return System.Drawing.Color.FromName(attr.SelectedColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
return System.Drawing.Color.Transparent;
|
||||
}
|
||||
}
|
||||
|
||||
// [ColorSelect("Red")]
|
||||
// [FontColorSelect("White")]
|
||||
// [Description("异常")]
|
||||
// DSExcept = 32
|
||||
//}
|
||||
|
||||
///// <summary>
|
||||
///// 工序状态
|
||||
///// </summary>
|
||||
//public enum RunState
|
||||
//{
|
||||
// [ColorSelect("Gold")]
|
||||
// [Description("空闲")]
|
||||
// Idle = 1,
|
||||
// [ColorSelect("Lime")]
|
||||
// [Description("运行中")]
|
||||
// Running = 2,
|
||||
// [ColorSelect("Gray")]
|
||||
// [Description("停止")]
|
||||
// Stop = 3,
|
||||
// [ColorSelect("Red")]
|
||||
// [Description("宕机")]
|
||||
// Down = 99,
|
||||
//}
|
||||
|
||||
[Flags]
|
||||
public enum DeviceAttributeType
|
||||
@ -361,7 +285,38 @@ namespace DH.Commons.Enums
|
||||
[Description("测量结果")]
|
||||
MeasureResult = 31,
|
||||
}
|
||||
|
||||
|
||||
public enum LogLevel
|
||||
{
|
||||
[Description("详细")]
|
||||
[ColorSelect("White")]
|
||||
[FontColorSelect("Green")]
|
||||
Detail = 2,
|
||||
[Description("信息")]
|
||||
[ColorSelect("White")]
|
||||
[FontColorSelect("Dark")]
|
||||
Information = 3,
|
||||
[Description("辅助")]
|
||||
[ColorSelect("White")]
|
||||
[FontColorSelect("Blue")]
|
||||
Assist = 4,
|
||||
[Description("动作")]
|
||||
[ColorSelect("DarkGreen")]
|
||||
[FontColorSelect("Yellow")]
|
||||
Action = 5,
|
||||
[Description("错误")]
|
||||
[ColorSelect("Orange")]
|
||||
[FontColorSelect("White")]
|
||||
Error = 6,
|
||||
[Description("警报")]
|
||||
[ColorSelect("Brown")]
|
||||
[FontColorSelect("White")]
|
||||
Warning = 7,
|
||||
[Description("异常")]
|
||||
[ColorSelect("Red")]
|
||||
[FontColorSelect("White")]
|
||||
Exception = 8,
|
||||
}
|
||||
//public enum CameraDriverType
|
||||
//{
|
||||
// Halcon,
|
||||
@ -382,6 +337,59 @@ namespace DH.Commons.Enums
|
||||
// NG = -1,
|
||||
// IGNORE = -999,
|
||||
//}
|
||||
public enum DeviceState
|
||||
{
|
||||
TBD = -1,
|
||||
|
||||
[ColorSelect("Gray")]
|
||||
[FontColorSelect("Black")]
|
||||
[Description("未初始化")]
|
||||
DSUninit = 1,
|
||||
|
||||
[ColorSelect("Gold")]
|
||||
[FontColorSelect("White")]
|
||||
[PreState(1 + 2 + 4 + 8 + 32)]
|
||||
[Description("初始化")]
|
||||
DSInit = 2,
|
||||
|
||||
[ColorSelect("Lime")]
|
||||
[FontColorSelect("Black")]
|
||||
[PreState(2 + 4 + 16)]
|
||||
[Description("运行中")]
|
||||
DSOpen = 4,
|
||||
|
||||
[ColorSelect("Gray")]
|
||||
[FontColorSelect("White")]
|
||||
[PreState(1 + 4 + 8 + 16 + 32)]
|
||||
[Description("关闭")]
|
||||
DSClose = 8,
|
||||
|
||||
[ColorSelect("Gold")]
|
||||
[FontColorSelect("White")]
|
||||
[PreState(4 + 16)]
|
||||
[Description("暂停")]
|
||||
DSPause = 16,
|
||||
|
||||
[ColorSelect("Red")]
|
||||
[FontColorSelect("White")]
|
||||
[Description("异常")]
|
||||
DSExcept = 32
|
||||
}
|
||||
public enum RunState
|
||||
{
|
||||
[ColorSelect("Gold")]
|
||||
[Description("空闲")]
|
||||
Idle = 1,
|
||||
[ColorSelect("Lime")]
|
||||
[Description("运行中")]
|
||||
Running = 2,
|
||||
[ColorSelect("Gray")]
|
||||
[Description("停止")]
|
||||
Stop = 3,
|
||||
[ColorSelect("Red")]
|
||||
[Description("宕机")]
|
||||
Down = 99,
|
||||
}
|
||||
|
||||
public enum PriorityDirection
|
||||
{
|
||||
|
507
DH.Commons/Helper/FileHelper.cs
Normal file
507
DH.Commons/Helper/FileHelper.cs
Normal file
@ -0,0 +1,507 @@
|
||||
using hyjiacan.py4n;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DH.Commons.Enums
|
||||
{
|
||||
|
||||
public static class FileHelper
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 清理两个文件夹中的文件,保留文件名交集部分,其余文件删除。
|
||||
/// </summary>
|
||||
/// <param name="imagesFolder">图片文件夹路径</param>
|
||||
/// <param name="labelsFolder">标签文件夹路径</param>
|
||||
public static void CleanupFolders(string imagesFolder, string labelsFolder)
|
||||
{
|
||||
if (!Directory.Exists(imagesFolder))
|
||||
{
|
||||
Console.WriteLine($"Images folder does not exist: {imagesFolder}");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Directory.Exists(labelsFolder))
|
||||
{
|
||||
Console.WriteLine($"Labels folder does not exist: {labelsFolder}");
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取文件名(不包含扩展名)
|
||||
var imageFiles = Directory.GetFiles(imagesFolder)
|
||||
.Select(Path.GetFileNameWithoutExtension)
|
||||
.ToHashSet();
|
||||
|
||||
var labelFiles = Directory.GetFiles(labelsFolder)
|
||||
.Select(Path.GetFileNameWithoutExtension)
|
||||
.ToHashSet();
|
||||
|
||||
// 计算交集
|
||||
var commonFiles = imageFiles.Intersect(labelFiles);
|
||||
|
||||
// 删除 images 文件夹中不在交集中的文件
|
||||
foreach (var imagePath in Directory.GetFiles(imagesFolder))
|
||||
{
|
||||
string fileNameWithoutExt = Path.GetFileNameWithoutExtension(imagePath);
|
||||
if (!commonFiles.Contains(fileNameWithoutExt))
|
||||
{
|
||||
File.Delete(imagePath);
|
||||
Console.WriteLine($"Deleted image file: {imagePath}");
|
||||
}
|
||||
}
|
||||
|
||||
// 删除 labels 文件夹中不在交集中的文件
|
||||
foreach (var labelPath in Directory.GetFiles(labelsFolder))
|
||||
{
|
||||
string fileNameWithoutExt = Path.GetFileNameWithoutExtension(labelPath);
|
||||
if (!commonFiles.Contains(fileNameWithoutExt))
|
||||
{
|
||||
File.Delete(labelPath);
|
||||
Console.WriteLine($"Deleted label file: {labelPath}");
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine("Folders cleaned successfully!");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取文件夹中所有图片文件的个数
|
||||
/// </summary>
|
||||
/// <param name="folderPath">目标文件夹路径</param>
|
||||
/// <param name="includeSubdirectories">是否包含子文件夹,默认不包含</param>
|
||||
/// <returns>图片文件总数</returns>
|
||||
public static int CountImageFiles(string folderPath, bool includeSubdirectories = false)
|
||||
{
|
||||
if (!Directory.Exists(folderPath))
|
||||
{
|
||||
throw new DirectoryNotFoundException($"The folder '{folderPath}' does not exist.");
|
||||
}
|
||||
|
||||
// 支持的图片格式
|
||||
string[] imageExtensions = { "*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif" };
|
||||
|
||||
// 搜索选项
|
||||
SearchOption searchOption = includeSubdirectories ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
|
||||
|
||||
int fileCount = 0;
|
||||
|
||||
foreach (var ext in imageExtensions)
|
||||
{
|
||||
fileCount += Directory.GetFiles(folderPath, ext, searchOption).Length;
|
||||
}
|
||||
|
||||
return fileCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除一个目录所有子目录和文件
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
public static void DeleteDirectoryAndContents(string path)
|
||||
{
|
||||
// 确保目录存在
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
// 删除目录中的文件
|
||||
string[] files = Directory.GetFiles(path);
|
||||
foreach (var file in files)
|
||||
{
|
||||
File.Delete(file);
|
||||
Console.WriteLine($"文件已删除: {file}");
|
||||
}
|
||||
|
||||
// 删除目录中的子目录
|
||||
string[] directories = Directory.GetDirectories(path);
|
||||
foreach (var directory in directories)
|
||||
{
|
||||
DeleteDirectoryAndContents(directory); // 递归删除子目录
|
||||
}
|
||||
|
||||
// 删除空目录
|
||||
Directory.Delete(path);
|
||||
Console.WriteLine($"目录已删除: {path}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("目录不存在!");
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 将一个文件夹中的所有图片文件和 JSON 文件复制到另一个文件夹中
|
||||
/// </summary>
|
||||
/// <param name="sourceDirectory"></param>
|
||||
/// <param name="destinationDirectory"></param>
|
||||
public static void CopyImageAndJsonFiles(string sourceDirectory, string destinationDirectory)
|
||||
{
|
||||
// 确保目标文件夹存在,如果不存在则创建它
|
||||
if (!Directory.Exists(destinationDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(destinationDirectory);
|
||||
}
|
||||
|
||||
// 获取源文件夹中的所有图片文件和 JSON 文件
|
||||
string[] imageFiles = Directory.GetFiles(sourceDirectory, "*.*")
|
||||
.Where(file => file.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) ||
|
||||
file.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase) ||
|
||||
file.EndsWith(".png", StringComparison.OrdinalIgnoreCase) ||
|
||||
file.EndsWith(".gif", StringComparison.OrdinalIgnoreCase) ||
|
||||
file.EndsWith(".bmp", StringComparison.OrdinalIgnoreCase) ||
|
||||
file.EndsWith(".tiff", StringComparison.OrdinalIgnoreCase) ||
|
||||
file.EndsWith(".webp", StringComparison.OrdinalIgnoreCase))
|
||||
.ToArray();
|
||||
|
||||
string[] jsonFiles = Directory.GetFiles(sourceDirectory, "*.json");
|
||||
|
||||
// 合并图片文件和 JSON 文件
|
||||
string[] filesToCopy = imageFiles.Concat(jsonFiles).ToArray();
|
||||
|
||||
foreach (string file in filesToCopy)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 获取文件名
|
||||
string fileName = Path.GetFileName(file);
|
||||
|
||||
// 拼接目标文件的完整路径
|
||||
string destinationFile = Path.Combine(destinationDirectory, fileName);
|
||||
|
||||
// 如果目标文件已存在,可以选择覆盖或跳过(这里我们选择跳过)
|
||||
if (File.Exists(destinationFile))
|
||||
{
|
||||
Console.WriteLine($"文件 {fileName} 已存在,跳过复制.");
|
||||
continue;
|
||||
}
|
||||
|
||||
// 复制文件
|
||||
File.Copy(file, destinationFile);
|
||||
Console.WriteLine($"文件 {fileName} 已成功复制到 {destinationDirectory}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"复制文件 {file} 时出错: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 遍历图片文件夹,检查对应的标签文件夹中是否有同名的 .txt 文件。
|
||||
/// 如果没有,则创建一个空的 .txt 文件。
|
||||
/// </summary>
|
||||
/// <param name="imagesDirectory">图片文件夹路径</param>
|
||||
/// <param name="labelsDirectory">标签文件夹路径</param>
|
||||
public static void ProcessImageFiles(string imagesDirectory, string labelsDirectory)
|
||||
{
|
||||
// 检查 images 目录是否存在
|
||||
if (!Directory.Exists(imagesDirectory))
|
||||
{
|
||||
throw new DirectoryNotFoundException($"目录 {imagesDirectory} 不存在.");
|
||||
}
|
||||
|
||||
// 检查 labels 目录是否存在,如果不存在则创建
|
||||
if (!Directory.Exists(labelsDirectory))
|
||||
{
|
||||
Directory.CreateDirectory(labelsDirectory);
|
||||
Console.WriteLine($"目录 {labelsDirectory} 已创建.");
|
||||
}
|
||||
|
||||
// 获取 images 目录中的所有文件(包括图片文件)
|
||||
string[] imageFiles = Directory.GetFiles(imagesDirectory, "*.*", SearchOption.TopDirectoryOnly);
|
||||
string[] validExtensions = { ".jpg", ".jpeg", ".png", ".bmp", ".gif" }; // 支持的图片格式
|
||||
|
||||
foreach (var imageFile in imageFiles)
|
||||
{
|
||||
// 检查文件扩展名是否为支持的图片格式
|
||||
string extension = Path.GetExtension(imageFile).ToLower();
|
||||
if (Array.Exists(validExtensions, ext => ext == extension))
|
||||
{
|
||||
// 获取图片文件的文件名(不包括扩展名)
|
||||
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(imageFile);
|
||||
|
||||
// 生成对应的 txt 文件路径
|
||||
string labelFilePath = Path.Combine(labelsDirectory, fileNameWithoutExtension + ".txt");
|
||||
|
||||
// 如果该 txt 文件不存在,则创建一个空白 txt 文件
|
||||
if (!File.Exists(labelFilePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
File.WriteAllText(labelFilePath, string.Empty); // 创建空白 txt 文件
|
||||
Console.WriteLine($"创建空白文件: {labelFilePath}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"无法创建文件 {labelFilePath}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 封装的函数:删除没有对应 JSON 文件的图片
|
||||
public static void DeleteUnmatchedImages(string labelsFolderPath, string imagesFolderPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 获取 labels 文件夹中的所有 JSON 文件名(去除扩展名)
|
||||
string[] jsonFiles = Directory.GetFiles(labelsFolderPath, "*.txt");
|
||||
HashSet<string> jsonFileNames = new HashSet<string>();
|
||||
|
||||
foreach (string jsonFile in jsonFiles)
|
||||
{
|
||||
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(jsonFile);
|
||||
jsonFileNames.Add(fileNameWithoutExtension);
|
||||
}
|
||||
|
||||
// 获取 images 文件夹中的所有图片文件
|
||||
string[] imageFiles = Directory.GetFiles(imagesFolderPath);
|
||||
|
||||
// 遍历图片文件,检查是否有对应的 JSON 文件
|
||||
foreach (string imageFile in imageFiles)
|
||||
{
|
||||
string imageFileNameWithoutExtension = Path.GetFileNameWithoutExtension(imageFile);
|
||||
|
||||
// 如果图片文件名不在 labels 文件夹的 JSON 文件名集合中,则删除该图片
|
||||
if (!jsonFileNames.Contains(imageFileNameWithoutExtension))
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(imageFile); // 删除图片
|
||||
Console.WriteLine($"已删除图片: {Path.GetFileName(imageFile)}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"删除文件 {Path.GetFileName(imageFile)} 时出错: {ex.Message}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"图片 {Path.GetFileName(imageFile)} 有对应的 JSON 文件,不删除。");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"操作失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将 List<string> 保存到指定文件中,格式为 "项,标签"。
|
||||
/// 标签是根据项的索引生成的。
|
||||
/// </summary>
|
||||
/// <param name="items">要保存的字符串列表</param>
|
||||
/// <param name="filePath">保存文件的路径</param>
|
||||
public static void SaveItemsToFile(List<string> items, string filePath)
|
||||
{
|
||||
// 使用 StreamWriter 写入文件
|
||||
using (StreamWriter writer = new StreamWriter(filePath))
|
||||
{
|
||||
// 遍历 items 列表
|
||||
for (int i = 0; i < items.Count; i++)
|
||||
{
|
||||
// 写入每一行,格式为 "项, 标签"
|
||||
writer.WriteLine($"{items[i]},{i}");
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void SaveItemsToFile(HashSet<string> items, string filePath)
|
||||
{
|
||||
// 使用 StreamWriter 写入文件
|
||||
using (StreamWriter writer = new StreamWriter(filePath))
|
||||
{
|
||||
// 遍历 HashSet
|
||||
int i = 0;
|
||||
foreach (string item in items)
|
||||
{
|
||||
// 写入每一行,格式为 "项, 标签"
|
||||
writer.WriteLine($"{item},{i}"); // 假设使用 item 的长度作为标签
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
static List<FileInformation> FileList = new List<FileInformation>();
|
||||
|
||||
/// <summary>
|
||||
/// 递归获取指定文件夹下所有文件
|
||||
/// </summary>
|
||||
/// <param name="dir"></param>
|
||||
/// <returns></returns>
|
||||
public static List<FileInformation> GetAllFiles(DirectoryInfo dir)
|
||||
{
|
||||
FileInfo[] allFile = dir.GetFiles();
|
||||
foreach (FileInfo fi in allFile)
|
||||
{
|
||||
FileList.Add(new FileInformation { FileName = fi.Name, FilePath = fi.FullName });
|
||||
}
|
||||
DirectoryInfo[] allDir = dir.GetDirectories();
|
||||
foreach (DirectoryInfo d in allDir)
|
||||
{
|
||||
GetAllFiles(d);
|
||||
}
|
||||
return FileList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断字符串是否纯字母
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsAlphabetOnly(string input)
|
||||
{
|
||||
return Regex.IsMatch(input, "^[a-zA-Z]+$");
|
||||
}
|
||||
/// <summary>
|
||||
/// 判断字符串是否仅包含大小写字母和数字
|
||||
/// </summary>
|
||||
/// <param name="input">待判断的字符串</param>
|
||||
/// <returns>如果字符串仅包含字母和数字,返回 true;否则返回 false</returns>
|
||||
public static bool IsAlphaNumericOnly(string input)
|
||||
{
|
||||
return Regex.IsMatch(input, "^[a-zA-Z0-9]+$");
|
||||
}
|
||||
public static string ConvertHanzitoPinyinWithNumbers(string input)
|
||||
{
|
||||
// 正则表达式匹配汉字
|
||||
string pattern = @"[\u4e00-\u9fa5]";
|
||||
Regex regex = new Regex(pattern);
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
int lastIndex = 0;
|
||||
|
||||
foreach (Match match in regex.Matches(input))
|
||||
{
|
||||
// 将非汉字部分保留为原样
|
||||
result.Append(input.Substring(lastIndex, match.Index - lastIndex));
|
||||
|
||||
// 获取汉字并转换为拼音
|
||||
string hanzi = match.Value;
|
||||
string pinyin = ConvertHanziToPinyin(hanzi);
|
||||
|
||||
// 将拼音追加到结果中
|
||||
result.Append(pinyin);
|
||||
|
||||
lastIndex = match.Index + match.Length;
|
||||
}
|
||||
|
||||
// 添加最后的非汉字部分
|
||||
result.Append(input.Substring(lastIndex));
|
||||
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
public static string ConvertHanziToPinyin(string hanzi)
|
||||
{
|
||||
// 设置拼音格式:去掉音调,拼音小写,ü保持为u:
|
||||
PinyinFormat format = PinyinFormat.WITHOUT_TONE | PinyinFormat.LOWERCASE | PinyinFormat.WITH_U_AND_COLON;
|
||||
|
||||
// 获取拼音数组
|
||||
List<PinyinItem> pinyinItems = Pinyin4Net.GetPinyinArray(hanzi, format);
|
||||
|
||||
StringBuilder pinyinBuilder = new StringBuilder();
|
||||
|
||||
foreach (var item in pinyinItems)
|
||||
{
|
||||
// 处理多音字:默认取第一个拼音
|
||||
if (item.Count > 0)
|
||||
{
|
||||
string pinyin = item[0];
|
||||
|
||||
// 特殊处理ü的情况
|
||||
pinyin = pinyin.Replace("u:", "v"); // 将u:转为v,这是常见的拼音表示法
|
||||
|
||||
pinyinBuilder.Append(pinyin);
|
||||
}
|
||||
}
|
||||
|
||||
return pinyinBuilder.ToString();
|
||||
}
|
||||
/// <summary>
|
||||
/// 汉字拼音转化
|
||||
/// </summary>
|
||||
/// <param name="hanzi"></param>
|
||||
/// <returns></returns>
|
||||
//public static string ConvertHanzitoPinyin(string hanzi)
|
||||
//{
|
||||
// PinyinFormat format = PinyinFormat.WITHOUT_TONE | PinyinFormat.LOWERCASE | PinyinFormat.WITH_U_UNICODE;
|
||||
|
||||
// // string hanzi = defectRow.LabelDescription;
|
||||
// List<PinyinItem> pylist = Pinyin4Net.GetPinyinArray(hanzi, format);
|
||||
// // 提取所有拼音并合并为一个字符串
|
||||
// List<string> pinyinStrings = new List<string>();
|
||||
// foreach (var item in pylist)
|
||||
// {
|
||||
// // 将PinyinItem中的每个拼音(List<string>)合并为一个字符串
|
||||
// string joinedPinyin = string.Join("", item); // 这里的item就是一个List<string>,其中存储了拼音
|
||||
// pinyinStrings.Add(joinedPinyin); // 添加合并后的拼音
|
||||
// }
|
||||
|
||||
// // 合并所有拼音为一个字符串
|
||||
// string allPinyin = string.Join("", pinyinStrings);
|
||||
// return allPinyin;
|
||||
//}
|
||||
/// <summary>
|
||||
/// 递归获取指定文件夹下所有文件
|
||||
/// </summary>
|
||||
/// <param name="dir"></param>
|
||||
/// <returns></returns>
|
||||
public static List<FileInformation> GetAllFiles(string dir)
|
||||
{
|
||||
DirectoryInfo directoryInfo = new(dir);
|
||||
return GetAllFiles(directoryInfo);
|
||||
}
|
||||
public static string OpenSlectDirDialog(string dirpath = "")
|
||||
{
|
||||
FolderBrowserDialog fbd = new FolderBrowserDialog();
|
||||
fbd.InitialDirectory = dirpath;
|
||||
if (fbd.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
string targetDirPath = fbd.SelectedPath;
|
||||
if (Directory.Exists(targetDirPath))
|
||||
{
|
||||
return targetDirPath;
|
||||
}
|
||||
else
|
||||
return string.Empty;
|
||||
//ImportDirImages(targetDirPath);
|
||||
}
|
||||
else
|
||||
return string.Empty;
|
||||
}
|
||||
public static string OpenSlectfileDialog(string dirpath = "")
|
||||
{
|
||||
|
||||
|
||||
|
||||
// 创建并配置 OpenFileDialog 实例
|
||||
OpenFileDialog openFileDialog = new OpenFileDialog();
|
||||
openFileDialog.Title = "选择文件"; // 对话框标题
|
||||
openFileDialog.Filter = "所有文件 (*.pt)|*.*"; // 允许选择任何类型的文件
|
||||
openFileDialog.InitialDirectory = @"C:\"; // 初始显示目录,可以根据需要修改
|
||||
|
||||
// 显示对话框
|
||||
if (openFileDialog.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
// 获取选中的文件路径
|
||||
string selectedFilePath = openFileDialog.FileName;
|
||||
Console.WriteLine("您选择的文件路径是: " + selectedFilePath);
|
||||
return selectedFilePath;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("没有选择任何文件。");
|
||||
return string.Empty;
|
||||
MessageBox.Show("没有选择任何文件。");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class FileInformation
|
||||
{
|
||||
public string FileName { get; set; }
|
||||
public string FilePath { get; set; }
|
||||
}
|
||||
}
|
107
DH.Commons/Helper/ImageSaveHelper.cs
Normal file
107
DH.Commons/Helper/ImageSaveHelper.cs
Normal file
@ -0,0 +1,107 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using DH.Commons.Helper;
|
||||
|
||||
namespace DH.Commons.Enums
|
||||
{
|
||||
public class ImageSaveHelper
|
||||
{
|
||||
public event Action<DateTime, string> OnImageSaveExceptionRaised;
|
||||
|
||||
//private string baseDirectory = "";
|
||||
//public string BaseDirectory
|
||||
//{
|
||||
// get => baseDirectory;
|
||||
// set
|
||||
// {
|
||||
// baseDirectory = value;
|
||||
// if (string.IsNullOrWhiteSpace(baseDirectory) || !Path.IsPathRooted(baseDirectory))
|
||||
// {
|
||||
// baseDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Images");
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
public bool EnableImageSave { get; set; } = true;
|
||||
|
||||
public ImageSaveHelper() { }
|
||||
public ImageSaveHelper(bool enableImageSave = true)
|
||||
{
|
||||
EnableImageSave = enableImageSave;
|
||||
}
|
||||
|
||||
|
||||
object lockObj = new object();
|
||||
////耗时操作从 _taskFactory分配线程
|
||||
//public TaskFactory _taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.LongRunning);
|
||||
readonly ConcurrentQueue<ImageSaveSet> _imageQueue = new ConcurrentQueue<ImageSaveSet>();
|
||||
Task _saveTask = null;
|
||||
readonly object _saveLock = new object();
|
||||
|
||||
public async void ImageSaveAsync(ImageSaveSet set)
|
||||
{
|
||||
if (!EnableImageSave)
|
||||
return;
|
||||
|
||||
await Task.Run(() =>
|
||||
{
|
||||
_imageQueue.Enqueue(set);
|
||||
|
||||
lock (_saveLock)
|
||||
{
|
||||
if (_saveTask == null)
|
||||
{
|
||||
_saveTask = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
while (_imageQueue.Count > 0)
|
||||
{
|
||||
if (_imageQueue.TryDequeue(out ImageSaveSet saveSet))
|
||||
{
|
||||
if (!Directory.Exists(Path.GetDirectoryName(saveSet.FullName)))
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(saveSet.FullName));
|
||||
}
|
||||
if (saveSet.SaveImage != null)
|
||||
{
|
||||
saveSet.SaveImage.Save(saveSet.FullName, saveSet.ImageFormat);
|
||||
saveSet.SaveImage.Dispose();
|
||||
}
|
||||
saveSet = null;
|
||||
}
|
||||
}
|
||||
|
||||
await Task.Delay(2000);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OnImageSaveExceptionRaised?.Invoke(DateTime.Now, $"图片保存异常:{ex.GetExceptionMessage()}");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class ImageSaveSet
|
||||
{
|
||||
public string FullName { get; set; }//带后缀 全路径
|
||||
|
||||
public Bitmap SaveImage { get; set; }
|
||||
|
||||
public ImageFormat ImageFormat { get; set; } = ImageFormat.Jpeg;
|
||||
}
|
||||
}
|
138
DH.Commons/Helper/LoggerHelper.cs
Normal file
138
DH.Commons/Helper/LoggerHelper.cs
Normal file
@ -0,0 +1,138 @@
|
||||
using DH.Commons.Helper;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using static DH.Commons.Enums.EnumHelper;
|
||||
|
||||
namespace DH.Commons.Enums
|
||||
{
|
||||
public interface ILogOutput
|
||||
{
|
||||
event Action<LogMsg> OnLogMsgOutput;
|
||||
void LogDisplay(LogMsg msg);
|
||||
}
|
||||
public interface ILogger
|
||||
{
|
||||
event Action<LogMsg> OnLog;
|
||||
LoggerHelper LoggerHelper { get; set; }
|
||||
//void LogAsync(DateTime dt, LogLevel loglevel, string msg);
|
||||
void LogAsync(LogMsg msg);
|
||||
}
|
||||
public class LoggerHelper
|
||||
{
|
||||
public event Action<DateTime, string> OnLogExceptionRaised;
|
||||
|
||||
public string LogPath { get; set; }
|
||||
public string LogPrefix { get; set; }
|
||||
|
||||
LogLevel LogLevel = LogLevel.Information;
|
||||
|
||||
public LoggerHelper() { }
|
||||
public LoggerHelper(string logPath, string logPrefix, LogLevel logLevel = LogLevel.Information)
|
||||
{
|
||||
LogPath = logPath;
|
||||
LogPrefix = logPrefix;
|
||||
|
||||
LogLevel = logLevel;
|
||||
}
|
||||
|
||||
public void SetLogLevel(LogLevel logLevel)
|
||||
{
|
||||
if (LogLevel != logLevel)
|
||||
LogLevel = logLevel;
|
||||
}
|
||||
////耗时操作从 _taskFactory分配线程
|
||||
//public TaskFactory _taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.LongRunning);
|
||||
readonly ConcurrentQueue<LogMsg> _logQueue = new ConcurrentQueue<LogMsg>();
|
||||
Task _logTask = null;
|
||||
readonly object _logLock = new object();
|
||||
|
||||
public async void LogAsync(LogMsg msg)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
_logQueue.Enqueue(msg);
|
||||
|
||||
lock (_logLock)
|
||||
{
|
||||
if (_logTask == null)
|
||||
{
|
||||
_logTask = Task.Run(async () =>
|
||||
{
|
||||
string filePath = Path.Combine(LogPath, $"{(string.IsNullOrWhiteSpace(LogPrefix) ? "Log_" : ("Log_" + LogPrefix + "_"))}{DateTime.Now.ToString("yyyyMMdd")}.txt");
|
||||
try
|
||||
{
|
||||
if (!StaticHelper.CheckFilesCanUse(filePath))
|
||||
{
|
||||
OnLogExceptionRaised?.Invoke(DateTime.Now, $"日志文件{filePath}被占用,无法写入");
|
||||
return;
|
||||
}
|
||||
using (StreamWriter writer = new StreamWriter(filePath, true, System.Text.Encoding.UTF8))
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (!Directory.Exists(LogPath))
|
||||
{
|
||||
Directory.CreateDirectory(LogPath);
|
||||
}
|
||||
|
||||
while (_logQueue.Count > 0)
|
||||
{
|
||||
if (_logQueue.TryDequeue(out LogMsg log))
|
||||
{
|
||||
if (log.LogLevel >= LogLevel)
|
||||
{
|
||||
writer.WriteLine($"{log.LogTime.ToString("yyyy-MM-dd HH:mm:ss.fff")}[{log.ThreadId}]\t{log.LogLevel.GetEnumDescription()}\t{log.Msg}");
|
||||
}
|
||||
}
|
||||
}
|
||||
writer.Flush();
|
||||
|
||||
await Task.Delay(2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//OnLogExceptionRaised?.Invoke(DateTime.Now, $"日志文件{filePath}写入异常:/*{ex.GetExceptionMessage()*/}");
|
||||
OnLogExceptionRaised?.Invoke(DateTime.Now, $"日志文件{filePath}写入异常");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void LogAsync(DateTime dt, LogLevel logLevel, string msg)
|
||||
{
|
||||
LogAsync(new LogMsg(dt, logLevel, msg));
|
||||
}
|
||||
}
|
||||
|
||||
public class LogMsg
|
||||
{
|
||||
public DateTime LogTime { get; set; }
|
||||
public LogLevel LogLevel { get; set; }
|
||||
//public string Prefix { get; set; }
|
||||
public string Msg { get; set; }
|
||||
|
||||
public string MsgSource { get; set; }
|
||||
|
||||
public int ThreadId { get; set; }
|
||||
|
||||
public LogMsg() { }
|
||||
public LogMsg(DateTime dt, LogLevel logLevel, string msg)
|
||||
{
|
||||
LogTime = dt;
|
||||
LogLevel = logLevel;
|
||||
Msg = msg;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{LogTime.ToString("HH:mm:ss.fff")}\t{MsgSource}\t{Msg}";
|
||||
}
|
||||
}
|
||||
}
|
169
DH.Commons/Helper/SchemeHelper.cs
Normal file
169
DH.Commons/Helper/SchemeHelper.cs
Normal file
@ -0,0 +1,169 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace DH.Commons.Helper
|
||||
{
|
||||
public static class SchemeHelper
|
||||
{
|
||||
private const string DefaultSchemeName = "默认方案";
|
||||
private static readonly string ConfigFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "schemes.json");
|
||||
|
||||
/// <summary>
|
||||
/// 方案配置数据结构
|
||||
/// </summary>
|
||||
private class SchemeConfig
|
||||
{
|
||||
public List<string> Schemes { get; set; } = new List<string>();
|
||||
public string CurrentScheme { get; set; } = DefaultSchemeName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化配置(首次运行时调用)
|
||||
/// </summary>
|
||||
public static void Initialize()
|
||||
{
|
||||
if (!File.Exists(ConfigFilePath))
|
||||
{
|
||||
var defaultConfig = new SchemeConfig
|
||||
{
|
||||
Schemes = new List<string> { DefaultSchemeName },
|
||||
CurrentScheme = DefaultSchemeName
|
||||
};
|
||||
SaveConfig(defaultConfig);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有方案
|
||||
/// </summary>
|
||||
public static List<string> GetAllSchemes()
|
||||
{
|
||||
var config = LoadConfig();
|
||||
return config.Schemes ?? new List<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加新方案
|
||||
/// </summary>
|
||||
public static void AddScheme(string schemeName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(schemeName))
|
||||
throw new ArgumentException("方案名称无效");
|
||||
|
||||
var config = LoadConfig();
|
||||
|
||||
if (config.Schemes.Contains(schemeName))
|
||||
throw new InvalidOperationException($"方案 {schemeName} 已存在");
|
||||
|
||||
config.Schemes.Add(schemeName);
|
||||
SaveConfig(config);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置当前方案
|
||||
/// </summary>
|
||||
public static void SetCurrentScheme(string schemeName)
|
||||
{
|
||||
var config = LoadConfig();
|
||||
|
||||
if (!config.Schemes.Contains(schemeName))
|
||||
throw new KeyNotFoundException($"方案 {schemeName} 不存在");
|
||||
|
||||
config.CurrentScheme = schemeName;
|
||||
SaveConfig(config);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前方案
|
||||
/// </summary>
|
||||
public static string GetCurrentScheme()
|
||||
{
|
||||
var config = LoadConfig();
|
||||
return !string.IsNullOrEmpty(config.CurrentScheme)
|
||||
? config.CurrentScheme
|
||||
: DefaultSchemeName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除指定方案
|
||||
/// </summary>
|
||||
public static void DeleteScheme(string schemeName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(schemeName))
|
||||
throw new ArgumentException("方案名称无效");
|
||||
|
||||
var config = LoadConfig();
|
||||
|
||||
if (!config.Schemes.Contains(schemeName))
|
||||
throw new KeyNotFoundException($"方案 {schemeName} 不存在");
|
||||
|
||||
// 如果是当前方案,需要先切换
|
||||
if (config.CurrentScheme == schemeName)
|
||||
{
|
||||
var otherScheme = config.Schemes.FirstOrDefault(s => s != schemeName);
|
||||
if (otherScheme != null)
|
||||
{
|
||||
config.CurrentScheme = otherScheme;
|
||||
}
|
||||
else
|
||||
{
|
||||
config.CurrentScheme = DefaultSchemeName;
|
||||
if (!config.Schemes.Contains(DefaultSchemeName))
|
||||
{
|
||||
config.Schemes.Add(DefaultSchemeName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
config.Schemes.Remove(schemeName);
|
||||
SaveConfig(config);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 加载配置文件
|
||||
/// </summary>
|
||||
private static SchemeConfig LoadConfig()
|
||||
{
|
||||
if (!File.Exists(ConfigFilePath))
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
string json = File.ReadAllText(ConfigFilePath);
|
||||
return JsonConvert.DeserializeObject<SchemeConfig>(json) ?? new SchemeConfig();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 如果读取失败,返回默认配置
|
||||
return new SchemeConfig
|
||||
{
|
||||
Schemes = new List<string> { DefaultSchemeName },
|
||||
CurrentScheme = DefaultSchemeName
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存配置文件
|
||||
/// </summary>
|
||||
private static void SaveConfig(SchemeConfig config)
|
||||
{
|
||||
try
|
||||
{
|
||||
string json = JsonConvert.SerializeObject(config, Formatting.Indented);
|
||||
File.WriteAllText(ConfigFilePath, json);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 处理保存失败的情况
|
||||
throw new InvalidOperationException("保存方案配置失败", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
680
DH.Commons/Helper/StaticHelper.cs
Normal file
680
DH.Commons/Helper/StaticHelper.cs
Normal file
@ -0,0 +1,680 @@
|
||||
using Microsoft.CSharp.RuntimeBinder;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Dynamic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
|
||||
namespace DH.Commons.Helper
|
||||
{
|
||||
public static class StaticHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 数值转换为byte数组 高位在前,低位在后
|
||||
/// </summary>
|
||||
/// <param name="number"></param>
|
||||
/// <param name="size"></param>
|
||||
/// <returns></returns>
|
||||
public static byte[] IntToBytes(this int number, int size = 2)
|
||||
{
|
||||
byte[] result = new byte[size];
|
||||
|
||||
int temp = size;
|
||||
while (temp > 0)
|
||||
{
|
||||
result[size - temp] = (byte)(number >> ((temp - 1) * 8) & 0xff);
|
||||
|
||||
temp--;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
public static T DeepSerializeClone<T>(this T t)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(t));
|
||||
}
|
||||
/// <summary>
|
||||
/// 字节数组转换为整数
|
||||
/// </summary>
|
||||
/// <param name="data">字节数组</param>
|
||||
/// <param name="HtL">true:数组序号低的在高位 false:数组序号低的在低位</param>
|
||||
/// <returns></returns>
|
||||
public static int BytesToInt(this byte[] data, bool HtL = true)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
int index = i;
|
||||
|
||||
if (HtL)
|
||||
{
|
||||
index = data.Length - 1 - i;
|
||||
}
|
||||
|
||||
res += data[index] << (8 * i);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取一个类指定的属性值
|
||||
/// </summary>
|
||||
/// <param name="info">object对象</param>
|
||||
/// <param name="field">属性名称</param>
|
||||
/// <returns></returns>
|
||||
public static object GetPropertyValue(object info, string field)
|
||||
{
|
||||
if (info == null) return null;
|
||||
Type t = info.GetType();
|
||||
IEnumerable<System.Reflection.PropertyInfo> property = from pi in t.GetProperties() where pi.Name.ToLower() == field.ToLower() select pi;
|
||||
return property.First().GetValue(info, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将32位整形拆分为无符号16位整形
|
||||
/// </summary>
|
||||
/// <param name="num">需要拆分的32位整形</param>
|
||||
/// <param name="bitNum">拆分为16位整形的位数 1或者2</param>
|
||||
/// <param name="HtL">true:高位在前,低位在后;false:高位在后,低位在前</param>
|
||||
/// <returns></returns>
|
||||
public static List<ushort> ParseIntToUnsignShortList(this int num, int bitNum = 2, bool HtL = false)
|
||||
{
|
||||
if (bitNum == 2)
|
||||
{
|
||||
ushort high = (ushort)(num >> 16);
|
||||
ushort low = (ushort)num;
|
||||
|
||||
if (HtL)
|
||||
{
|
||||
return new List<ushort>() { high, low };
|
||||
}
|
||||
else
|
||||
{
|
||||
return new List<ushort>() { low, high };
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (num < 0)
|
||||
{
|
||||
num = ushort.MaxValue + 1 + num;
|
||||
}
|
||||
|
||||
return new List<ushort>() { (ushort)num };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将32位整形数组拆分为无符号16位整形数组
|
||||
/// </summary>
|
||||
/// <param name="list">需要拆分的32位整形</param>
|
||||
/// <param name="bitNum">拆分为16位整形的位数 1或者2</param>
|
||||
/// <param name="HtL">true:高位在前,低位在后;false:高位在后,低位在前</param>
|
||||
/// <returns></returns>
|
||||
public static List<ushort> ParseIntToUnsignShortList(this List<int> list, int bitNum = 2, bool HtL = false)
|
||||
{
|
||||
return list.SelectMany(u => u.ParseIntToUnsignShortList(bitNum, HtL)).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将ushort的集合转换为16位带符号整形
|
||||
/// </summary>
|
||||
/// <param name="numList"></param>
|
||||
/// <param name="bitNum">合并的位数 1或者2</param>
|
||||
/// <param name="HtL">true:高位在前,低位在后;false:高位在后,低位在前</param>
|
||||
/// <returns></returns>
|
||||
public static List<int> ParseUnsignShortListToInt(this List<int> numList, int bitNum = 2, bool HtL = false)
|
||||
{
|
||||
if (bitNum == 1)
|
||||
{
|
||||
return numList.ConvertAll(n =>
|
||||
{
|
||||
int num = n;
|
||||
if (num > short.MaxValue)
|
||||
{
|
||||
num = num - ushort.MaxValue - 1;
|
||||
}
|
||||
|
||||
return num;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
List<int> list = new List<int>();
|
||||
for (int i = 0; i < numList.Count; i += 2)
|
||||
{
|
||||
int high = HtL ? numList[i] : numList[i + 1];
|
||||
int low = HtL ? numList[i + 1] : numList[i];
|
||||
list.Add((high << 16) | low);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
//public static T DeepSerializeClone<T>(this T t)
|
||||
//{
|
||||
// return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(t));
|
||||
//}
|
||||
|
||||
public static void DataFrom<T1, T2>(this T1 destT, T2 sourceT, List<string> exceptionProps = null) where T1 : class where T2 : class
|
||||
{
|
||||
if (sourceT == null)
|
||||
{
|
||||
destT = null;
|
||||
return;
|
||||
}
|
||||
|
||||
PropertyInfo[] propDest = destT.GetType().GetProperties();//.Where(p => !(p.GetMethod.IsVirtual && !p.GetMethod.IsFinal)).ToArray();
|
||||
PropertyInfo[] propSource = sourceT.GetType().GetProperties();
|
||||
|
||||
Array.ForEach(propDest, prop =>
|
||||
{
|
||||
if (exceptionProps == null || !exceptionProps.Contains(prop.Name))
|
||||
{
|
||||
if (prop.CanWrite)
|
||||
{
|
||||
PropertyInfo propS = propSource.FirstOrDefault(p => p.Name == prop.Name);
|
||||
if (propS != null && propS.CanRead)
|
||||
{
|
||||
prop.SetValue(destT, propS.GetValue(sourceT));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//RtlMoveMemory
|
||||
[DllImport("kernel32.dll", EntryPoint = "RtlMoveMemory", SetLastError = false)]
|
||||
public static extern void CopyMemory(IntPtr dest, IntPtr src, uint count);
|
||||
[HandleProcessCorruptedStateExceptions]
|
||||
//public static Bitmap CopyBitmap(this Bitmap source)
|
||||
//{
|
||||
// Bitmap clone = new Bitmap(source.Width, source.Height, source.PixelFormat);
|
||||
// try
|
||||
// {
|
||||
// int PixelSize = Bitmap.GetPixelFormatSize(source.PixelFormat) / 8;
|
||||
// if (PixelSize == 1)
|
||||
// {
|
||||
// ColorPalette cp = clone.Palette;
|
||||
// for (int i = 0; i < 256; i++)
|
||||
// {
|
||||
// cp.Entries[i] = Color.FromArgb(255, i, i, i);
|
||||
// }
|
||||
// clone.Palette = cp;
|
||||
// }
|
||||
|
||||
// Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
|
||||
// BitmapData sourceData = source.LockBits(rect, ImageLockMode.ReadWrite, source.PixelFormat);
|
||||
// BitmapData cloneData = clone.LockBits(rect, ImageLockMode.ReadWrite, source.PixelFormat);
|
||||
// if (source.Width % 4 == 0)
|
||||
// {
|
||||
// unsafe
|
||||
// {
|
||||
// CopyMemory(cloneData.Scan0, sourceData.Scan0, (uint)(sourceData.Stride * sourceData.Height));
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Parallel.For(0, source.Height, h =>
|
||||
// {
|
||||
// unsafe
|
||||
// {
|
||||
// CopyMemory(cloneData.Scan0 + h * sourceData.Stride, sourceData.Scan0 + h * sourceData.Stride, (uint)sourceData.Width);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
// clone.UnlockBits(cloneData);
|
||||
// source.UnlockBits(sourceData);
|
||||
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// return clone;
|
||||
// }
|
||||
|
||||
// return clone;
|
||||
//}
|
||||
public static Bitmap CopyBitmap(this Bitmap source)
|
||||
{
|
||||
Bitmap clone = new Bitmap(source.Width, source.Height, source.PixelFormat);
|
||||
|
||||
try
|
||||
{
|
||||
int pixelSize = Bitmap.GetPixelFormatSize(source.PixelFormat) / 8;
|
||||
if (pixelSize == 1)
|
||||
{
|
||||
ColorPalette cp = clone.Palette;
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
cp.Entries[i] = Color.FromArgb(255, i, i, i);
|
||||
}
|
||||
clone.Palette = cp;
|
||||
}
|
||||
|
||||
Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
|
||||
BitmapData sourceData = source.LockBits(rect, ImageLockMode.ReadOnly, source.PixelFormat);
|
||||
BitmapData cloneData = clone.LockBits(rect, ImageLockMode.WriteOnly, source.PixelFormat);
|
||||
|
||||
int stride = sourceData.Stride;
|
||||
int height = sourceData.Height;
|
||||
|
||||
if (stride % 4 == 0)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
CopyMemory(cloneData.Scan0, sourceData.Scan0, (uint)(stride * height));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Parallel.For(0, height, h =>
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
CopyMemory(cloneData.Scan0 + h * stride, sourceData.Scan0 + h * stride, (uint)stride);
|
||||
}
|
||||
});
|
||||
}
|
||||
source.UnlockBits(sourceData); clone.UnlockBits(cloneData);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{ // Handle or log exception if needed
|
||||
} return clone; }
|
||||
|
||||
|
||||
public static Bitmap BitmapDeepClone(Bitmap source)
|
||||
{
|
||||
Bitmap clone = new Bitmap(source.Width, source.Height, source.PixelFormat);
|
||||
|
||||
try
|
||||
{
|
||||
int PixelSize = Bitmap.GetPixelFormatSize(source.PixelFormat) / 8;
|
||||
if (PixelSize == 1)
|
||||
{
|
||||
ColorPalette cp = clone.Palette;
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
cp.Entries[i] = Color.FromArgb(255, i, i, i);
|
||||
}
|
||||
clone.Palette = cp;
|
||||
}
|
||||
Rectangle rect = new Rectangle(0, 0, source.Width, source.Height);
|
||||
BitmapData source_bitmap = source.LockBits(rect, ImageLockMode.ReadWrite, source.PixelFormat);
|
||||
BitmapData destination_bitmap = clone.LockBits(rect, ImageLockMode.ReadWrite, clone.PixelFormat);
|
||||
|
||||
int depth_width = source_bitmap.Width * PixelSize;
|
||||
|
||||
unsafe
|
||||
{
|
||||
byte* source_ptr = (byte*)source_bitmap.Scan0;
|
||||
byte* destination_ptr = (byte*)destination_bitmap.Scan0;
|
||||
|
||||
int offset = source_bitmap.Stride - depth_width;
|
||||
|
||||
for (int i = 0; i < source_bitmap.Height; i++)
|
||||
{
|
||||
for (int j = 0; j < depth_width; j++, source_ptr++, destination_ptr++)
|
||||
{
|
||||
*destination_ptr = *source_ptr;
|
||||
}
|
||||
|
||||
source_ptr += offset;
|
||||
destination_ptr += offset;
|
||||
}
|
||||
}
|
||||
|
||||
source.UnlockBits(source_bitmap);
|
||||
clone.UnlockBits(destination_bitmap);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static Bitmap HConnectBitmap(this Bitmap map1, Bitmap map2)
|
||||
{
|
||||
Bitmap connectImage = null;
|
||||
if (map1 == null || map2 == null)
|
||||
return null;
|
||||
//横向拼接
|
||||
int width = map1.Width + map2.Width;
|
||||
//高度不变
|
||||
int height = Math.Max(map1.Height, map2.Height);
|
||||
connectImage = new Bitmap(width, height);
|
||||
using (Graphics graph = Graphics.FromImage(connectImage))
|
||||
{
|
||||
graph.DrawImage(connectImage, width, height);
|
||||
graph.Clear(System.Drawing.Color.White);
|
||||
graph.DrawImage(map1, 0, 0);
|
||||
graph.DrawImage(map2, map1.Width, 0);
|
||||
}
|
||||
return connectImage;
|
||||
}
|
||||
|
||||
public static IntPtr FloatToIntptr(float[] bytes)
|
||||
{
|
||||
GCHandle hObject = GCHandle.Alloc(bytes, GCHandleType.Pinned);
|
||||
return hObject.AddrOfPinnedObject();
|
||||
}
|
||||
|
||||
// 将Btimap类转换为byte[]类函数
|
||||
public static byte[] GetBGRValues(Bitmap bmp, out int stride)
|
||||
{
|
||||
var rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
|
||||
var bmpData = bmp.LockBits(rect, ImageLockMode.ReadOnly, bmp.PixelFormat);
|
||||
stride = bmpData.Stride;
|
||||
var rowBytes = bmpData.Width * Image.GetPixelFormatSize(bmp.PixelFormat) / 8;
|
||||
var imgBytes = bmp.Height * rowBytes;
|
||||
byte[] rgbValues = new byte[imgBytes];
|
||||
IntPtr ptr = bmpData.Scan0;
|
||||
for (var i = 0; i < bmp.Height; i++)
|
||||
{
|
||||
Marshal.Copy(ptr, rgbValues, i * rowBytes, rowBytes);
|
||||
ptr += bmpData.Stride;
|
||||
}
|
||||
bmp.UnlockBits(bmpData);
|
||||
return rgbValues;
|
||||
}
|
||||
/// <summary>
|
||||
/// 缺陷灰度图转彩色图像函数
|
||||
/// </summary>
|
||||
/// <param name="src">灰度图</param>
|
||||
/// <returns>返回构造的伪彩色图像</returns>
|
||||
public static Bitmap GrayMapToColorMap(this Bitmap src, Dictionary<int, Color> indexColorDict = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
//Stopwatch sw = new Stopwatch();
|
||||
//sw.Start();
|
||||
|
||||
Bitmap dest = new Bitmap(src.Width, src.Height, PixelFormat.Format32bppArgb);
|
||||
|
||||
int destHeight = dest.Height;
|
||||
int destWidth = dest.Width;
|
||||
|
||||
Rectangle rect = new Rectangle(0, 0, destWidth, destHeight);
|
||||
BitmapData bmpDataDest = dest.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
|
||||
BitmapData bmpDataSrc = src.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed);
|
||||
int strideDest = bmpDataDest.Stride;
|
||||
|
||||
int strideSrc = bmpDataSrc.Stride;
|
||||
unsafe
|
||||
{
|
||||
byte* pDest = (byte*)bmpDataDest.Scan0.ToPointer();
|
||||
byte* pSrc = (byte*)bmpDataSrc.Scan0.ToPointer();
|
||||
|
||||
Parallel.For(0, destHeight, y =>
|
||||
{
|
||||
Parallel.For(0, destWidth, x =>
|
||||
{
|
||||
int pixel = pSrc[y * strideSrc + x];
|
||||
int startIndex = y * strideDest + x * 4;
|
||||
if (pixel >= 0 && pixel <= 63)
|
||||
{
|
||||
Color color = Color.Red;
|
||||
if (indexColorDict != null && indexColorDict.ContainsKey(pixel))
|
||||
{
|
||||
color = indexColorDict[pixel];
|
||||
}
|
||||
|
||||
byte R = color.R;
|
||||
byte G = color.G;
|
||||
byte B = color.B;
|
||||
|
||||
pDest[startIndex] = B;
|
||||
pDest[startIndex + 1] = G;
|
||||
pDest[startIndex + 2] = R;
|
||||
pDest[startIndex + 3] = 100;
|
||||
}
|
||||
else
|
||||
{
|
||||
pDest[startIndex] = 255;
|
||||
pDest[startIndex + 1] = 255;
|
||||
pDest[startIndex + 2] = 255;
|
||||
pDest[startIndex + 3] = 0;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
dest.UnlockBits(bmpDataDest);
|
||||
src.UnlockBits(bmpDataSrc);
|
||||
|
||||
//sw.Stop();
|
||||
//Console.WriteLine($"转换耗时:{sw.ElapsedMilliseconds}");
|
||||
|
||||
return dest;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Sort<T>(this ObservableCollection<T> collection) where T : IComparable<T>
|
||||
{
|
||||
List<T> sortedList = collection.OrderByDescending(x => x).ToList();//这里用降序
|
||||
for (int i = 0; i < sortedList.Count(); i++)
|
||||
{
|
||||
collection.Move(collection.IndexOf(sortedList[i]), i);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得字符串中开始和结束字符串中间的值
|
||||
/// </summary>
|
||||
/// <param name="sourse"></param>
|
||||
/// <param name="startstr"></param>
|
||||
/// <param name="endstr"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetMidString(string sourse, string startstr, string endstr)
|
||||
{
|
||||
string result = string.Empty;
|
||||
int startindex, endindex;
|
||||
try
|
||||
{
|
||||
startindex = sourse.IndexOf(startstr);
|
||||
if (startindex == -1)
|
||||
return result;
|
||||
string tmpstr = sourse.Substring(startindex + startstr.Length);
|
||||
endindex = tmpstr.IndexOf(endstr);
|
||||
if (endindex == -1)
|
||||
return result;
|
||||
result = tmpstr.Remove(endindex);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得字符串中开始和结束字符串中间的值
|
||||
/// </summary>
|
||||
/// <param name="t">字符串</param>
|
||||
/// <param name="k">开始</param>
|
||||
/// <param name="j">结束</param>
|
||||
/// <returns></returns>
|
||||
private static string GetMidString2(string sourse, string startstr, string endstr) //截取指定文本,和易语言的取文本中间差不多
|
||||
{
|
||||
try //异常捕捉
|
||||
{
|
||||
var kn = sourse.IndexOf(startstr, StringComparison.Ordinal) + startstr.Length;
|
||||
var jn = sourse.IndexOf(endstr, kn, StringComparison.Ordinal);
|
||||
return sourse.Substring(kn, jn - kn);
|
||||
}
|
||||
catch //如果发现未知的错误,比如上面的代码出错了,就执行下面这句代码
|
||||
{
|
||||
return ""; //返回空
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 布尔类型转换为整型
|
||||
public static int ToInt(this object obj)
|
||||
{
|
||||
if (Convert.ToBoolean(obj) == true)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 整型转换为布尔类型
|
||||
public static bool ToBool(this object obj)
|
||||
{
|
||||
if (Convert.ToInt32(obj) == 1)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
public static object GetProperty(this object o, string member)
|
||||
{
|
||||
if (o == null) throw new ArgumentNullException("o");
|
||||
if (member == null) throw new ArgumentNullException("member");
|
||||
Type scope = o.GetType();
|
||||
IDynamicMetaObjectProvider provider = o as IDynamicMetaObjectProvider;
|
||||
if (provider != null)
|
||||
{
|
||||
ParameterExpression param = Expression.Parameter(typeof(object));
|
||||
DynamicMetaObject mobj = provider.GetMetaObject(param);
|
||||
GetMemberBinder binder = (GetMemberBinder)Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, member, scope, new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(0, null) });
|
||||
DynamicMetaObject ret = mobj.BindGetMember(binder);
|
||||
BlockExpression final = Expression.Block(
|
||||
Expression.Label(CallSiteBinder.UpdateLabel),
|
||||
ret.Expression
|
||||
);
|
||||
LambdaExpression lambda = Expression.Lambda(final, param);
|
||||
Delegate del = lambda.Compile();
|
||||
return del.DynamicInvoke(o);
|
||||
}
|
||||
else
|
||||
{
|
||||
return o.GetType().GetProperty(member, BindingFlags.Public | BindingFlags.Instance).GetValue(o, null);
|
||||
}
|
||||
}
|
||||
|
||||
#region 检测文件状态及操作方式选择
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern IntPtr _lopen(string lpPathName, int iReadWrite);
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern bool CloseHandle(IntPtr hObject);
|
||||
private const int OF_READWRITE = 2;
|
||||
private const int OF_SHARE_DENY_NONE = 0x40;
|
||||
private static readonly IntPtr HFILE_ERROR = new IntPtr(-1);
|
||||
/// <summary>
|
||||
/// 检测文件是否只读或被使用
|
||||
/// </summary>
|
||||
/// <param name="FileNames">要检测的文件</param>
|
||||
/// <returns>true可用,false在用或只读</returns>
|
||||
public static bool CheckFilesCanUse(string fileName)
|
||||
{
|
||||
if (!File.Exists(fileName))
|
||||
return true;//文件不存在
|
||||
if ((File.GetAttributes(fileName) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
|
||||
return false; //文件只读
|
||||
IntPtr vHandle = _lopen(fileName, OF_READWRITE | OF_SHARE_DENY_NONE);
|
||||
if (vHandle == HFILE_ERROR)
|
||||
{
|
||||
CloseHandle(vHandle);
|
||||
return false; //文件被占用
|
||||
}
|
||||
|
||||
CloseHandle(vHandle); //文件没被占用
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定文件夹下所有的文件名称
|
||||
/// </summary>
|
||||
/// <param name="folderName">指定文件夹名称,绝对路径</param>
|
||||
/// <param name="fileFilter">文件类型过滤,根据文件后缀名,如:*,*.txt,*.xls</param>
|
||||
/// <param name="isContainSubFolder">是否包含子文件夹</param>
|
||||
/// <returns>ArrayList数组,为所有需要的文件路径名称</returns>
|
||||
public static List<FileInfo> GetAllFilesByFolder(string folderName, string fileFilter, bool isContainSubFolder = false)
|
||||
{
|
||||
List<FileInfo> resList = new List<FileInfo>();
|
||||
try
|
||||
{
|
||||
DirectoryInfo currDir = new DirectoryInfo(folderName);//当前目录
|
||||
FileInfo[] currFiles = currDir.GetFiles(fileFilter);//当前目录文件
|
||||
foreach (FileInfo file in currFiles)
|
||||
{
|
||||
if (fileFilter.ToLower().IndexOf(file.Extension.ToLower()) >= 0)
|
||||
{
|
||||
resList.Add(file);
|
||||
}
|
||||
}
|
||||
if (isContainSubFolder)
|
||||
{
|
||||
string[] subFolders = Directory.GetDirectories(folderName);
|
||||
foreach (string subFolder in subFolders)
|
||||
{
|
||||
resList.AddRange(GetAllFilesByFolder(subFolder, fileFilter));//递归
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
return resList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定文件夹下所有的文件名称,不过滤文件类型
|
||||
/// </summary>
|
||||
/// <param name="folderName">指定文件夹名称,绝对路径</param>
|
||||
/// <param name="isContainSubFolder">是否包含子文件夹</param>
|
||||
/// <returns>ArrayList数组,为所有需要的文件路径名称</returns>
|
||||
public static List<FileInfo> GetAllFilesByFolder(string folderName, bool isContainSubFolder)
|
||||
{
|
||||
return GetAllFilesByFolder(folderName, "*", isContainSubFolder);
|
||||
}
|
||||
}
|
||||
|
||||
public class Compare<T, C> : IEqualityComparer<T>
|
||||
{
|
||||
private Func<T, C> _getField;
|
||||
public Compare(Func<T, C> getfield)
|
||||
{
|
||||
_getField = getfield;
|
||||
}
|
||||
public bool Equals(T x, T y)
|
||||
{
|
||||
return EqualityComparer<C>.Default.Equals(_getField(x), _getField(y));
|
||||
}
|
||||
public int GetHashCode(T obj)
|
||||
{
|
||||
return EqualityComparer<C>.Default.GetHashCode(_getField(obj));
|
||||
}
|
||||
}
|
||||
|
||||
public static class ObjectExtensions
|
||||
{
|
||||
public static IEnumerable<T> DistinctBy<T, C>(this IEnumerable<T> source, Func<T, C> getfield)
|
||||
{
|
||||
return source.Distinct(new Compare<T, C>(getfield));
|
||||
}
|
||||
|
||||
public static IQueryable<T> DistinctBy<T, C>(this IQueryable<T> source, Func<T, C> getfield)
|
||||
{
|
||||
return source.Distinct(new Compare<T, C>(getfield));
|
||||
}
|
||||
}
|
||||
}
|
120
DH.Commons/Helper/SystemConfigHelper.cs
Normal file
120
DH.Commons/Helper/SystemConfigHelper.cs
Normal file
@ -0,0 +1,120 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace DH.Commons.Helper
|
||||
{
|
||||
/// <summary>
|
||||
/// 配置文件操作工具类(自动定位主程序配置)
|
||||
/// </summary>
|
||||
public static class SystemConfigHelper
|
||||
{
|
||||
private static Configuration _mainConfig;
|
||||
private static readonly object _lock = new object();
|
||||
|
||||
/// <summary>
|
||||
/// 获取主程序配置对象
|
||||
/// </summary>
|
||||
private static Configuration MainConfiguration
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_mainConfig == null)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (_mainConfig == null)
|
||||
{
|
||||
// 获取主程序路径
|
||||
string exePath = Assembly.GetEntryAssembly().Location;
|
||||
var configFile = exePath + ".config";
|
||||
|
||||
// 加载主程序配置
|
||||
var fileMap = new ExeConfigurationFileMap
|
||||
{
|
||||
ExeConfigFilename = configFile
|
||||
};
|
||||
_mainConfig = ConfigurationManager.OpenMappedExeConfiguration(
|
||||
fileMap,
|
||||
ConfigurationUserLevel.None
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return _mainConfig;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查配置项是否存在
|
||||
/// </summary>
|
||||
public static bool KeyExists(string key)
|
||||
{
|
||||
return MainConfiguration.AppSettings.Settings[key] != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取配置项(带类型自动转换)
|
||||
/// </summary>
|
||||
public static T GetValue<T>(string key, T defaultValue = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
var setting = MainConfiguration.AppSettings.Settings[key];
|
||||
if (setting == null) return defaultValue;
|
||||
|
||||
return (T)Convert.ChangeType(setting.Value, typeof(T));
|
||||
}
|
||||
catch
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入配置项(自动保存)
|
||||
/// </summary>
|
||||
public static void SetValue(string key, object value)
|
||||
{
|
||||
var settings = MainConfiguration.AppSettings.Settings;
|
||||
var stringValue = value?.ToString() ?? string.Empty;
|
||||
|
||||
if (settings[key] == null)
|
||||
{
|
||||
settings.Add(key, stringValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
settings[key].Value = stringValue;
|
||||
}
|
||||
|
||||
SaveChanges();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除指定配置项
|
||||
/// </summary>
|
||||
public static void RemoveKey(string key)
|
||||
{
|
||||
if (KeyExists(key))
|
||||
{
|
||||
MainConfiguration.AppSettings.Settings.Remove(key);
|
||||
SaveChanges();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存配置修改
|
||||
/// </summary>
|
||||
private static void SaveChanges()
|
||||
{
|
||||
MainConfiguration.Save(ConfigurationSaveMode.Modified);
|
||||
ConfigurationManager.RefreshSection("appSettings");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user