加入若干pgsql的接口
This commit is contained in:
@@ -1,171 +1,380 @@
|
||||
using Npgsql;
|
||||
using System.Diagnostics;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Npgsql;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.SQLite;
|
||||
using System.Linq;
|
||||
|
||||
namespace Ramitta
|
||||
{
|
||||
public partial class PostgreSql
|
||||
public class PostgreSQL : IDisposable
|
||||
{
|
||||
private readonly string _connectionString;
|
||||
private NpgsqlConnection db;
|
||||
private bool disposed = false;
|
||||
|
||||
public PostgreSql(string connectionString)
|
||||
// 构造函数,初始化数据库连接
|
||||
public PostgreSQL(string connectionString, bool readOnly = false)
|
||||
{
|
||||
_connectionString = connectionString;
|
||||
var connString = connectionString;
|
||||
if (readOnly)
|
||||
{
|
||||
if (!connString.Contains("CommandTimeout"))
|
||||
{
|
||||
connString += ";CommandTimeout=0";
|
||||
}
|
||||
}
|
||||
|
||||
// 执行查询操作,返回查询结果
|
||||
public async Task<List<Dictionary<string, object>>> ExecuteQueryAsync(string query, Dictionary<string, object> parameters = null)
|
||||
db = new NpgsqlConnection(connString);
|
||||
db.Open();
|
||||
}
|
||||
|
||||
// 创建表:根据表名和字段定义创建表
|
||||
public void CreateTable(string tableName, Dictionary<string, string> columns)
|
||||
{
|
||||
// 构建列定义的字符串
|
||||
var columnsDefinition = string.Join(", ", columns.Select(c => $"\"{c.Key}\" {MapDataType(c.Value)}"));
|
||||
string createTableQuery = $"CREATE TABLE IF NOT EXISTS \"{tableName}\" ({columnsDefinition});";
|
||||
|
||||
using (var cmd = new NpgsqlCommand(createTableQuery, db))
|
||||
{
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
|
||||
// 数据类型映射(SQLite到PostgreSQL)
|
||||
private string MapDataType(string sqliteType)
|
||||
{
|
||||
return sqliteType.ToUpper() switch
|
||||
{
|
||||
"INTEGER" => "INTEGER",
|
||||
"TEXT" => "TEXT",
|
||||
"REAL" => "REAL",
|
||||
"BLOB" => "BYTEA",
|
||||
"NUMERIC" => "NUMERIC",
|
||||
"BOOLEAN" => "BOOLEAN",
|
||||
"DATE" => "DATE",
|
||||
"DATETIME" => "TIMESTAMP",
|
||||
"TIMESTAMP" => "TIMESTAMP",
|
||||
_ => "TEXT" // 默认映射为TEXT
|
||||
};
|
||||
}
|
||||
|
||||
// 获取数据库中所有表名
|
||||
public List<string> GetAllTableNames()
|
||||
{
|
||||
List<string> tableNames = new List<string>();
|
||||
|
||||
string query = "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';";
|
||||
|
||||
using (var cmd = new NpgsqlCommand(query, db))
|
||||
using (var reader = cmd.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
string tableName = reader.GetString(0);
|
||||
tableNames.Add(tableName);
|
||||
}
|
||||
}
|
||||
|
||||
return tableNames;
|
||||
}
|
||||
|
||||
// 向已存在的表中添加新列
|
||||
public void AddColumn(string tableName, string columnName, string columnType)
|
||||
{
|
||||
// 检查表是否存在
|
||||
if (!TableExists(tableName))
|
||||
{
|
||||
throw new ArgumentException($"表 '{tableName}' 不存在");
|
||||
}
|
||||
|
||||
// 检查列是否已存在
|
||||
if (ColumnExists(tableName, columnName))
|
||||
{
|
||||
Console.WriteLine($"列 '{columnName}' 在表 '{tableName}' 中已存在");
|
||||
return;
|
||||
}
|
||||
|
||||
// 构建添加列的SQL语句
|
||||
string addColumnQuery = $"ALTER TABLE \"{tableName}\" ADD COLUMN \"{columnName}\" {MapDataType(columnType)};";
|
||||
|
||||
using (var cmd = new NpgsqlCommand(addColumnQuery, db))
|
||||
{
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
Console.WriteLine($"已向表 '{tableName}' 添加列 '{columnName}'");
|
||||
}
|
||||
|
||||
// 检查表是否存在
|
||||
private bool TableExists(string tableName)
|
||||
{
|
||||
string query = "SELECT count(*) FROM information_schema.tables WHERE table_schema = 'public' AND table_name = @tableName;";
|
||||
|
||||
using (var cmd = new NpgsqlCommand(query, db))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@tableName", tableName);
|
||||
var result = cmd.ExecuteScalar();
|
||||
return Convert.ToInt64(result) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查列是否已存在
|
||||
private bool ColumnExists(string tableName, string columnName)
|
||||
{
|
||||
string query = "SELECT column_name FROM information_schema.columns WHERE table_schema = 'public' AND table_name = @tableName;";
|
||||
|
||||
using (var cmd = new NpgsqlCommand(query, db))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@tableName", tableName);
|
||||
using (var reader = cmd.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
if (reader["column_name"].ToString().Equals(columnName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 批量添加多个列
|
||||
public void AddColumns(string tableName, Dictionary<string, string> columns)
|
||||
{
|
||||
foreach (var column in columns)
|
||||
{
|
||||
AddColumn(tableName, column.Key, column.Value);
|
||||
}
|
||||
}
|
||||
|
||||
// 插入数据:向指定表插入一条记录
|
||||
// 参数: tableName - 表名
|
||||
// 参数: columnValues - 字段和对应值的字典
|
||||
// 例如: InsertData("Users", new Dictionary<string, object> { {"Name", "John"}, {"Age", 30} });
|
||||
public void InsertData(string tableName, Dictionary<string, object> columnValues)
|
||||
{
|
||||
// 构建列名字符串(添加引号防止保留关键字冲突)
|
||||
var columns = string.Join(", ", columnValues.Keys.Select(k => $"\"{k}\""));
|
||||
|
||||
// 判断是否需要 JSON 转换,并构建参数占位符
|
||||
var parameters = columnValues.Keys.Select(k =>
|
||||
{
|
||||
var value = columnValues[k];
|
||||
if (value is JObject || value is JArray) // 判断是否是 JObject 或 JArray
|
||||
{
|
||||
return $"@{k}::json";
|
||||
}
|
||||
return $"@{k}";
|
||||
});
|
||||
|
||||
// 构建插入语句
|
||||
string insertQuery = $"INSERT INTO \"{tableName}\" ({columns}) VALUES ({string.Join(", ", parameters)})";
|
||||
|
||||
// 使用 NpgsqlCommand 而不是 SQLiteCommand
|
||||
using (var cmd = new NpgsqlCommand(insertQuery, db))
|
||||
{
|
||||
foreach (var kvp in columnValues)
|
||||
{
|
||||
if (kvp.Value is JObject jObj)
|
||||
{
|
||||
// JObject 转为字符串
|
||||
cmd.Parameters.AddWithValue("@" + kvp.Key, jObj.ToString());
|
||||
}
|
||||
else if (kvp.Value is JArray jArray)
|
||||
{
|
||||
// JArray 转为字符串
|
||||
cmd.Parameters.AddWithValue("@" + kvp.Key, jArray.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
// 处理 null 值
|
||||
cmd.Parameters.AddWithValue("@" + kvp.Key, kvp.Value ?? DBNull.Value);
|
||||
}
|
||||
}
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
|
||||
// 查询数据:执行任意查询语句并返回结果
|
||||
public List<Dictionary<string, object>> SelectData(string query, Dictionary<string, object> parameters = null)
|
||||
{
|
||||
var result = new List<Dictionary<string, object>>();
|
||||
|
||||
using (var conn = new NpgsqlConnection(_connectionString))
|
||||
{
|
||||
try
|
||||
{
|
||||
await conn.OpenAsync();
|
||||
Debug.WriteLine("Database connection established.");
|
||||
|
||||
using (var cmd = new NpgsqlCommand(query, conn))
|
||||
using (var cmd = new NpgsqlCommand(query, db))
|
||||
{
|
||||
// 添加查询参数(如果有的话)
|
||||
if (parameters != null)
|
||||
{
|
||||
foreach (var param in parameters)
|
||||
foreach (var kvp in parameters)
|
||||
{
|
||||
cmd.Parameters.AddWithValue(param.Key, param.Value ?? DBNull.Value);
|
||||
cmd.Parameters.AddWithValue("@" + kvp.Key, kvp.Value ?? DBNull.Value);
|
||||
}
|
||||
}
|
||||
|
||||
using (var reader = await cmd.ExecuteReaderAsync())
|
||||
using (var reader = cmd.ExecuteReader())
|
||||
{
|
||||
while (await reader.ReadAsync())
|
||||
while (reader.Read())
|
||||
{
|
||||
var row = new Dictionary<string, object>();
|
||||
for (int i = 0; i < reader.FieldCount; i++)
|
||||
{
|
||||
row[reader.GetName(i)] = await reader.IsDBNullAsync(i) ? null : reader.GetValue(i);
|
||||
row[reader.GetName(i)] = reader.GetValue(i);
|
||||
}
|
||||
result.Add(row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Debug.WriteLine($"Query executed: {query}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine($"Error executing query: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 执行插入、更新、删除操作
|
||||
public async Task<int> ExecuteNonQueryAsync(string query, Dictionary<string, object> parameters = null)
|
||||
// 更新数据:根据条件更新指定表中的记录
|
||||
public void UpdateData(string tableName, Dictionary<string, object> columnValues, string condition)
|
||||
{
|
||||
using (var conn = new NpgsqlConnection(_connectionString))
|
||||
// 构建SET子句
|
||||
var setClause = string.Join(", ", columnValues.Keys.Select(k => $"\"{k}\" = @{k}"));
|
||||
string updateQuery = $"UPDATE \"{tableName}\" SET {setClause} WHERE {condition}";
|
||||
|
||||
using (var cmd = new NpgsqlCommand(updateQuery, db))
|
||||
{
|
||||
foreach (var kvp in columnValues)
|
||||
{
|
||||
cmd.Parameters.AddWithValue("@" + kvp.Key, kvp.Value ?? DBNull.Value);
|
||||
}
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
|
||||
// 删除数据:根据条件删除指定表中的记录
|
||||
public void DeleteData(string tableName, string condition)
|
||||
{
|
||||
string deleteQuery = $"DELETE FROM \"{tableName}\" WHERE {condition}";
|
||||
|
||||
using (var cmd = new NpgsqlCommand(deleteQuery, db))
|
||||
{
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
|
||||
// 支持事务操作:允许在同一个事务中执行多个操作
|
||||
public void ExecuteTransaction(Action transactionActions)
|
||||
{
|
||||
using (var transaction = db.BeginTransaction())
|
||||
{
|
||||
try
|
||||
{
|
||||
await conn.OpenAsync();
|
||||
Debug.WriteLine("Database connection established.");
|
||||
|
||||
using (var cmd = new NpgsqlCommand(query, conn))
|
||||
transactionActions.Invoke(); // 执行多个操作
|
||||
transaction.Commit(); // 提交事务
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
if (parameters != null)
|
||||
transaction.Rollback(); // 回滚事务
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 删除所有表
|
||||
public void DropAllTables()
|
||||
{
|
||||
// 获取所有表名
|
||||
string getTablesQuery = "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';";
|
||||
var tables = SelectData(getTablesQuery);
|
||||
|
||||
foreach (var table in tables)
|
||||
{
|
||||
string tableName = table["table_name"].ToString();
|
||||
string dropTableQuery = $"DROP TABLE IF EXISTS \"{tableName}\" CASCADE;";
|
||||
|
||||
using (var cmd = new NpgsqlCommand(dropTableQuery, db))
|
||||
{
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int ExecuteBatchInsert(string tableName, List<string> columns, string columnsStr, List<Dictionary<string, object>> batch, int batchIndex)
|
||||
{
|
||||
var valueParams = new List<string>();
|
||||
var parameters = new Dictionary<string, object>();
|
||||
|
||||
for (int i = 0; i < batch.Count; i++)
|
||||
{
|
||||
var paramNames = columns.Select(col => $"@p{batchIndex}_{i}_{col}").ToList();
|
||||
valueParams.Add($"({string.Join(", ", paramNames)})");
|
||||
|
||||
foreach (var col in columns)
|
||||
{
|
||||
parameters[$"p{batchIndex}_{i}_{col}"] = batch[i][col] ?? DBNull.Value;
|
||||
}
|
||||
}
|
||||
|
||||
string insertQuery = $"INSERT INTO \"{tableName}\" ({columnsStr}) VALUES {string.Join(", ", valueParams)}";
|
||||
|
||||
using (var transaction = db.BeginTransaction())
|
||||
using (var cmd = new NpgsqlCommand(insertQuery, db, transaction))
|
||||
{
|
||||
foreach (var param in parameters)
|
||||
{
|
||||
cmd.Parameters.AddWithValue(param.Key, param.Value ?? DBNull.Value);
|
||||
cmd.Parameters.AddWithValue(param.Key, param.Value);
|
||||
}
|
||||
|
||||
int result = cmd.ExecuteNonQuery();
|
||||
transaction.Commit();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
var rowsAffected = await cmd.ExecuteNonQueryAsync();
|
||||
Debug.WriteLine($"Executed query: {query}, Rows affected: {rowsAffected}");
|
||||
return rowsAffected;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
// 修改主方法
|
||||
public int BulkInsert(string tableName, List<Dictionary<string, object>> dataList)
|
||||
{
|
||||
Debug.WriteLine($"Error executing non-query: {ex.Message}");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (dataList == null || dataList.Count == 0)
|
||||
return 0;
|
||||
|
||||
int insertedCount = 0;
|
||||
var columns = dataList[0].Keys.ToList();
|
||||
var columnsStr = string.Join(", ", columns.Select(c => $"\"{c}\""));
|
||||
int batchSize = 500;
|
||||
int batchIndex = 0;
|
||||
|
||||
for (int i = 0; i < dataList.Count; i += batchSize)
|
||||
{
|
||||
var batch = dataList.Skip(i).Take(batchSize).ToList();
|
||||
insertedCount += ExecuteBatchInsert(tableName, columns, columnsStr, batch, batchIndex);
|
||||
batchIndex++;
|
||||
}
|
||||
|
||||
// 执行插入操作,返回生成的主键
|
||||
public async Task<int> ExecuteInsertAsync(string query, Dictionary<string, object> parameters = null, string returnColumn = "id")
|
||||
{
|
||||
using (var conn = new NpgsqlConnection(_connectionString))
|
||||
{
|
||||
try
|
||||
{
|
||||
await conn.OpenAsync();
|
||||
Debug.WriteLine("Database connection established.");
|
||||
|
||||
using (var cmd = new NpgsqlCommand(query, conn))
|
||||
{
|
||||
if (parameters != null)
|
||||
{
|
||||
foreach (var param in parameters)
|
||||
{
|
||||
cmd.Parameters.AddWithValue(param.Key, param.Value ?? DBNull.Value);
|
||||
}
|
||||
return insertedCount;
|
||||
}
|
||||
|
||||
cmd.CommandText += $" RETURNING {returnColumn};";
|
||||
|
||||
var result = await cmd.ExecuteScalarAsync();
|
||||
Debug.WriteLine($"Executed insert, inserted ID: {result}");
|
||||
return result != null ? Convert.ToInt32(result) : -1;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
// 释放资源,关闭数据库连接
|
||||
public void Dispose()
|
||||
{
|
||||
Debug.WriteLine($"Error executing insert: {ex.Message}");
|
||||
return -1;
|
||||
if (!disposed)
|
||||
{
|
||||
if (db != null && db.State == ConnectionState.Open)
|
||||
{
|
||||
db.Close();
|
||||
db.Dispose();
|
||||
}
|
||||
disposed = true;
|
||||
}
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
// 执行事务操作
|
||||
public async Task<bool> ExecuteTransactionAsync(List<string> queries, List<Dictionary<string, object>> parametersList)
|
||||
// 析构函数,调用Dispose释放资源
|
||||
~PostgreSQL()
|
||||
{
|
||||
using (var conn = new NpgsqlConnection(_connectionString))
|
||||
{
|
||||
try
|
||||
{
|
||||
await conn.OpenAsync();
|
||||
Debug.WriteLine("Database connection established.");
|
||||
using (var transaction = await conn.BeginTransactionAsync())
|
||||
{
|
||||
for (int i = 0; i < queries.Count; i++)
|
||||
{
|
||||
using (var cmd = new NpgsqlCommand(queries[i], conn, transaction))
|
||||
{
|
||||
var parameters = parametersList[i];
|
||||
if (parameters != null)
|
||||
{
|
||||
foreach (var param in parameters)
|
||||
{
|
||||
cmd.Parameters.AddWithValue(param.Key, param.Value ?? DBNull.Value);
|
||||
}
|
||||
Dispose();
|
||||
}
|
||||
|
||||
await cmd.ExecuteNonQueryAsync();
|
||||
}
|
||||
}
|
||||
|
||||
await transaction.CommitAsync();
|
||||
Debug.WriteLine("Transaction committed.");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
// PostgreSQL特有的方法:创建连接字符串的便捷方法
|
||||
public static string BuildConnectionString(string host, string database, string username, string password, int port = 5432)
|
||||
{
|
||||
Debug.WriteLine($"Error executing transaction: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return $"Host={host};Port={port};Database={database};Username={username};Password={password}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Data;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Data;
|
||||
using System.Data.SQLite;
|
||||
using static NPOI.HSSF.Util.HSSFColor;
|
||||
|
||||
@@ -263,6 +264,60 @@ namespace Ramitta
|
||||
}
|
||||
}
|
||||
|
||||
public int ExecuteBatchInsert(string tableName, List<string> columns, string columnsStr, List<Dictionary<string, object>> batch, int batchIndex)
|
||||
{
|
||||
var valueParams = new List<string>();
|
||||
var parameters = new Dictionary<string, object>();
|
||||
|
||||
for (int i = 0; i < batch.Count; i++)
|
||||
{
|
||||
var paramNames = columns.Select(col => $"@p{batchIndex}_{i}_{col}").ToList();
|
||||
valueParams.Add($"({string.Join(", ", paramNames)})");
|
||||
|
||||
foreach (var col in columns)
|
||||
{
|
||||
parameters[$"p{batchIndex}_{i}_{col}"] = batch[i][col] ?? DBNull.Value;
|
||||
}
|
||||
}
|
||||
|
||||
string insertQuery = $"INSERT INTO {tableName} ({columnsStr}) VALUES {string.Join(", ", valueParams)}";
|
||||
|
||||
using (var transaction = db.BeginTransaction())
|
||||
using (var cmd = new SQLiteCommand(insertQuery, db, transaction))
|
||||
{
|
||||
foreach (var param in parameters)
|
||||
{
|
||||
cmd.Parameters.AddWithValue(param.Key, param.Value);
|
||||
}
|
||||
|
||||
int result = cmd.ExecuteNonQuery();
|
||||
transaction.Commit();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// 修改主方法
|
||||
public int BulkInsert(string tableName, List<Dictionary<string, object>> dataList)
|
||||
{
|
||||
if (dataList == null || dataList.Count == 0)
|
||||
return 0;
|
||||
|
||||
int insertedCount = 0;
|
||||
var columns = dataList[0].Keys.ToList();
|
||||
var columnsStr = string.Join(", ", columns);
|
||||
int batchSize = 500;
|
||||
int batchIndex = 0; // 添加批次索引
|
||||
|
||||
for (int i = 0; i < dataList.Count; i += batchSize)
|
||||
{
|
||||
var batch = dataList.Skip(i).Take(batchSize).ToList();
|
||||
insertedCount += ExecuteBatchInsert(tableName, columns, columnsStr, batch, batchIndex);
|
||||
batchIndex++; // 递增批次索引
|
||||
}
|
||||
|
||||
return insertedCount;
|
||||
}
|
||||
|
||||
// 释放资源,关闭数据库连接
|
||||
// 确保数据库连接在对象销毁时被正确关闭
|
||||
public void Dispose()
|
||||
|
||||
280
Ramitta/Excel.cs
280
Ramitta/Excel.cs
@@ -1,6 +1,9 @@
|
||||
using NPOI.SS.UserModel;
|
||||
using NPOI.SS.Formula.Functions;
|
||||
using NPOI.SS.UserModel;
|
||||
using NPOI.XSSF.UserModel;
|
||||
using System.DirectoryServices;
|
||||
using System.IO;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Ramitta.lib
|
||||
{
|
||||
@@ -15,7 +18,7 @@ namespace Ramitta.lib
|
||||
var result = new List<Dictionary<string, string>>();
|
||||
|
||||
// 打开 Excel 文件
|
||||
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
|
||||
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
{
|
||||
var workbook = new XSSFWorkbook(fs);
|
||||
ISheet sheet = null;
|
||||
@@ -87,7 +90,7 @@ namespace Ramitta.lib
|
||||
var result = new Dictionary<string, List<string>>();
|
||||
|
||||
// 打开 Excel 文件
|
||||
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
|
||||
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
{
|
||||
var workbook = new XSSFWorkbook(fs);
|
||||
ISheet sheet = null;
|
||||
@@ -186,6 +189,90 @@ namespace Ramitta.lib
|
||||
|
||||
return cell;
|
||||
}
|
||||
public static ICell? getRowCell(IRow row, object cellIndex)
|
||||
{
|
||||
int actualCellIndex = 0;
|
||||
if (cellIndex is int intIndex)
|
||||
{
|
||||
// 如果输入是数字,直接使用
|
||||
actualCellIndex = intIndex;
|
||||
}
|
||||
else if (cellIndex is string strIndex)
|
||||
{
|
||||
actualCellIndex = ColToIndex(strIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (row == null) return null;
|
||||
|
||||
ICell cell = row.GetCell(actualCellIndex);
|
||||
if (cell == null) return null;
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取单元格的字符串值,如果是公式则先计算
|
||||
/// </summary>
|
||||
/// <param name="cell">NPOI单元格对象</param>
|
||||
/// <returns>单元格的值字符串,如果为空返回null</returns>
|
||||
public static string? getFormula(ICell cell)
|
||||
{
|
||||
if (cell == null)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
// 如果是公式单元格
|
||||
if (cell.CellType == CellType.Formula)
|
||||
{
|
||||
// 获取公式计算器
|
||||
if (cell.Sheet?.Workbook != null)
|
||||
{
|
||||
var evaluator = cell.Sheet.Workbook.GetCreationHelper().CreateFormulaEvaluator();
|
||||
var cellValue = evaluator.Evaluate(cell);
|
||||
|
||||
// 将计算结果转为字符串
|
||||
if (cellValue == null) return null;
|
||||
|
||||
switch (cellValue.CellType)
|
||||
{
|
||||
case CellType.String:
|
||||
return cellValue.StringValue?.Trim();
|
||||
case CellType.Numeric:
|
||||
return cellValue.NumberValue.ToString();
|
||||
case CellType.Boolean:
|
||||
return cellValue.BooleanValue.ToString();
|
||||
case CellType.Error:
|
||||
return "#ERROR";
|
||||
case CellType.Blank:
|
||||
return null;
|
||||
default:
|
||||
return cellValue.FormatAsString()?.Trim();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 没有计算器,获取单元格的字符串表示
|
||||
return cell.ToString()?.Trim();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 非公式单元格,直接获取字符串表示
|
||||
return cell.ToString()?.Trim();
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// 计算出错时返回空
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static String? getRowCellStr(ISheet sheet, int rowIndex, object cellIndex)
|
||||
{
|
||||
@@ -207,6 +294,149 @@ namespace Ramitta.lib
|
||||
var cellValue = getRowCell(sheet, rowIndex, actualCellIndex)?.ToString();
|
||||
return string.IsNullOrWhiteSpace(cellValue) ? null : cellValue;
|
||||
}
|
||||
public static String? getRowCellStr(IRow row, object cellIndex,bool Formula=false)
|
||||
{
|
||||
int actualCellIndex = 0;
|
||||
if (cellIndex is int intIndex)
|
||||
{
|
||||
// 如果输入是数字,直接使用
|
||||
actualCellIndex = intIndex;
|
||||
}
|
||||
else if (cellIndex is string strIndex)
|
||||
{
|
||||
actualCellIndex = ColToIndex(strIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Formula) {
|
||||
return getFormula(getRowCell(row, actualCellIndex));
|
||||
} else {
|
||||
var cellValue = getRowCell(row, actualCellIndex)?.ToString();
|
||||
return string.IsNullOrWhiteSpace(cellValue) ? null : cellValue;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
public static float? getRowCellFloat(ISheet sheet, int rowIndex, object cellIndex)
|
||||
{
|
||||
int actualCellIndex = 0;
|
||||
if (cellIndex is int intIndex)
|
||||
{
|
||||
actualCellIndex = intIndex;
|
||||
}
|
||||
else if (cellIndex is string strIndex)
|
||||
{
|
||||
actualCellIndex = ColToIndex(strIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var cell = getRowCell(sheet, rowIndex, actualCellIndex);
|
||||
if (cell == null) return null;
|
||||
|
||||
// 获取单元格的实际值(不是公式本身)
|
||||
string cellValue;
|
||||
if (cell.CellType == CellType.Formula)
|
||||
{
|
||||
// 如果是公式,获取公式计算后的值
|
||||
cellValue = cell.NumericCellValue.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
cellValue = cell.ToString();
|
||||
}
|
||||
|
||||
// 解析为float
|
||||
if (float.TryParse(cellValue, out float result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
public static float? getRowCellFloat(IRow row, object cellIndex)
|
||||
{
|
||||
int actualCellIndex = 0;
|
||||
if (cellIndex is int intIndex)
|
||||
{
|
||||
actualCellIndex = intIndex;
|
||||
}
|
||||
else if (cellIndex is string strIndex)
|
||||
{
|
||||
actualCellIndex = ColToIndex(strIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var cell = getRowCell(row, actualCellIndex);
|
||||
if (cell == null) return null;
|
||||
|
||||
// 获取单元格的实际值(不是公式本身)
|
||||
string cellValue;
|
||||
if (cell.CellType == CellType.Formula)
|
||||
{
|
||||
// 如果是公式,获取公式计算后的值
|
||||
cellValue = cell.NumericCellValue.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
cellValue = cell.ToString();
|
||||
}
|
||||
|
||||
// 解析为float
|
||||
if (float.TryParse(cellValue, out float result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static double? getRowCellDouble(IRow row, object cellIndex)
|
||||
{
|
||||
int actualCellIndex = 0;
|
||||
if (cellIndex is int intIndex)
|
||||
{
|
||||
actualCellIndex = intIndex;
|
||||
}
|
||||
else if (cellIndex is string strIndex)
|
||||
{
|
||||
actualCellIndex = ColToIndex(strIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var cell = getRowCell(row, actualCellIndex);
|
||||
if (cell == null) return null;
|
||||
|
||||
// 获取单元格的实际值(不是公式本身)
|
||||
string cellValue;
|
||||
if (cell.CellType == CellType.Formula)
|
||||
{
|
||||
// 如果是公式,获取公式计算后的值
|
||||
cellValue = cell.NumericCellValue.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
cellValue = cell.ToString();
|
||||
}
|
||||
|
||||
if (double.TryParse(cellValue, out double result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// 简短版本
|
||||
// 列名字转为列号
|
||||
@@ -214,5 +444,49 @@ namespace Ramitta.lib
|
||||
{
|
||||
return col.ToUpper().Aggregate(0, (cur, ch) => cur * 26 + (ch - 'A'));
|
||||
}
|
||||
|
||||
public static ICellStyle CreateStyle(
|
||||
IWorkbook workbook,
|
||||
bool Border = true,
|
||||
short? fontSize = null,
|
||||
bool isBold = false,
|
||||
bool isItalic = false,
|
||||
string fontName = "宋体",
|
||||
HorizontalAlignment hAlign = HorizontalAlignment.Left, // 水平对齐
|
||||
VerticalAlignment vAlign = VerticalAlignment.Center) // 垂直对齐) // 新增:字体名称,默认为宋体
|
||||
{
|
||||
ICellStyle style = workbook.CreateCellStyle();
|
||||
|
||||
if (Border)
|
||||
{
|
||||
// 设置边框
|
||||
style.BorderTop = BorderStyle.Thin;
|
||||
style.BorderBottom = BorderStyle.Thin;
|
||||
style.BorderLeft = BorderStyle.Thin;
|
||||
style.BorderRight = BorderStyle.Thin;
|
||||
}
|
||||
// 设置对齐方式
|
||||
style.Alignment = hAlign;
|
||||
style.VerticalAlignment = vAlign;
|
||||
|
||||
// 创建字体
|
||||
IFont font = workbook.CreateFont();
|
||||
|
||||
// 设置字体名称
|
||||
font.FontName = fontName;
|
||||
|
||||
// 设置字号
|
||||
if (fontSize.HasValue)
|
||||
font.FontHeightInPoints = fontSize.Value;
|
||||
|
||||
// 设置粗体斜体
|
||||
font.IsBold = isBold;
|
||||
font.IsItalic = isItalic;
|
||||
|
||||
|
||||
style.SetFont(font);
|
||||
return style;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using NPOI.SS.UserModel;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
@@ -42,6 +43,7 @@ namespace Ramitta.lib
|
||||
obj.UpdateLayout();
|
||||
// 处理Dispatcher队列中的其他挂起的操作,确保UI更新
|
||||
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new Action(delegate { }));
|
||||
|
||||
});
|
||||
}
|
||||
public static SolidColorBrush GenerateRandomColor(SolidColorBrush color = null, bool? requireLightColor = null)
|
||||
@@ -221,6 +223,38 @@ namespace Ramitta.lib
|
||||
}
|
||||
return pngEncoder;
|
||||
}
|
||||
|
||||
public static void 刷新子表(string selectedFile, ComboBox combox)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 使用NPOI打开Excel文件
|
||||
using (FileStream fileStream = new FileStream(selectedFile, FileMode.Open, FileAccess.Read,FileShare.ReadWrite))
|
||||
{
|
||||
IWorkbook workbook = WorkbookFactory.Create(fileStream);
|
||||
|
||||
// 清空现有项
|
||||
combox.Items.Clear();
|
||||
|
||||
// 遍历所有sheet并添加到下拉框
|
||||
for (int i = 0; i < workbook.NumberOfSheets; i++)
|
||||
{
|
||||
string sheetName = workbook.GetSheetName(i);
|
||||
combox.Items.Add(sheetName);
|
||||
}
|
||||
|
||||
// 自动选择最后一个sheet
|
||||
if (combox != null && combox.Items != null && combox.Items.Count > 0)
|
||||
{
|
||||
combox.SelectedIndex = combox.Items.Count - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//DebugBar(Debugtag, $"读取Excel文件时出错:{ex.Message}", 错误红色);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 任务操作
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<TargetFramework>net8.0-windows7.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWPF>true</UseWPF>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<SupportedOSPlatformVersion>7.0</SupportedOSPlatformVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||
<PackageReference Include="HelixToolkit" Version="3.1.2" />
|
||||
<PackageReference Include="HelixToolkit.Wpf" Version="3.1.2" />
|
||||
<PackageReference Include="Neo4j.Driver" Version="5.28.3" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="Npgsql" Version="9.0.4" />
|
||||
|
||||
583
Ramitta/RegistryOperations.cs
Normal file
583
Ramitta/RegistryOperations.cs
Normal file
@@ -0,0 +1,583 @@
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ramitta.lib
|
||||
{
|
||||
/// <summary>
|
||||
/// 注册表操作类 - 提供完整的注册表增删改查功能
|
||||
/// </summary>
|
||||
public static class RegistryOperations
|
||||
{
|
||||
#region 枚举定义
|
||||
|
||||
/// <summary>
|
||||
/// 注册表值类型
|
||||
/// </summary>
|
||||
public enum RegValueKind
|
||||
{
|
||||
String = 1,
|
||||
ExpandString = 2,
|
||||
Binary = 3,
|
||||
DWord = 4,
|
||||
MultiString = 7,
|
||||
QWord = 11
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册表根键类型
|
||||
/// </summary>
|
||||
public enum RegRootKey
|
||||
{
|
||||
ClassesRoot,
|
||||
CurrentUser,
|
||||
LocalMachine,
|
||||
Users,
|
||||
CurrentConfig
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 私有方法
|
||||
|
||||
/// <summary>
|
||||
/// 解析完整注册表路径
|
||||
/// </summary>
|
||||
private static (RegRootKey rootKey, string relativePath) ParseFullPath(string fullPath)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(fullPath))
|
||||
throw new ArgumentException("注册表路径不能为空");
|
||||
|
||||
string[] parts = fullPath.Split('\\');
|
||||
if (parts.Length < 1)
|
||||
throw new ArgumentException("无效的注册表路径格式");
|
||||
|
||||
string rootStr = parts[0].ToUpper();
|
||||
string relativePath = parts.Length > 1 ? string.Join("\\", parts.Skip(1)) : "";
|
||||
|
||||
return rootStr switch
|
||||
{
|
||||
"HKEY_CLASSES_ROOT" or "HKCR" => (RegRootKey.ClassesRoot, relativePath),
|
||||
"HKEY_CURRENT_USER" or "HKCU" => (RegRootKey.CurrentUser, relativePath),
|
||||
"HKEY_LOCAL_MACHINE" or "HKLM" => (RegRootKey.LocalMachine, relativePath),
|
||||
"HKEY_USERS" or "HKU" => (RegRootKey.Users, relativePath),
|
||||
"HKEY_CURRENT_CONFIG" or "HKCC" => (RegRootKey.CurrentConfig, relativePath),
|
||||
_ => throw new ArgumentException($"不支持的注册表根键: {parts[0]}")
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取RegistryKey根键
|
||||
/// </summary>
|
||||
private static RegistryKey GetRootRegistryKey(RegRootKey rootKey)
|
||||
{
|
||||
return rootKey switch
|
||||
{
|
||||
RegRootKey.ClassesRoot => Registry.ClassesRoot,
|
||||
RegRootKey.CurrentUser => Registry.CurrentUser,
|
||||
RegRootKey.LocalMachine => Registry.LocalMachine,
|
||||
RegRootKey.Users => Registry.Users,
|
||||
RegRootKey.CurrentConfig => Registry.CurrentConfig,
|
||||
_ => throw new ArgumentException($"不支持的根键类型: {rootKey}")
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换值类型
|
||||
/// </summary>
|
||||
private static RegistryValueKind ToRegistryValueKind(RegValueKind valueKind)
|
||||
{
|
||||
return valueKind switch
|
||||
{
|
||||
RegValueKind.String => RegistryValueKind.String,
|
||||
RegValueKind.ExpandString => RegistryValueKind.ExpandString,
|
||||
RegValueKind.Binary => RegistryValueKind.Binary,
|
||||
RegValueKind.DWord => RegistryValueKind.DWord,
|
||||
RegValueKind.MultiString => RegistryValueKind.MultiString,
|
||||
RegValueKind.QWord => RegistryValueKind.QWord,
|
||||
_ => RegistryValueKind.Unknown
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 查询操作
|
||||
|
||||
/// <summary>
|
||||
/// 检查注册表项是否存在
|
||||
/// </summary>
|
||||
/// <param name="fullPath">完整注册表路径</param>
|
||||
/// <returns>是否存在</returns>
|
||||
public static bool KeyExists(string fullPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
var (rootKey, relativePath) = ParseFullPath(fullPath);
|
||||
using RegistryKey root = GetRootRegistryKey(rootKey);
|
||||
using RegistryKey key = root.OpenSubKey(relativePath);
|
||||
return key != null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查注册表值是否存在
|
||||
/// </summary>
|
||||
/// <param name="fullPath">完整注册表路径</param>
|
||||
/// <param name="valueName">值名称</param>
|
||||
/// <returns>是否存在</returns>
|
||||
public static bool ValueExists(string fullPath, string valueName)
|
||||
{
|
||||
try
|
||||
{
|
||||
var (rootKey, relativePath) = ParseFullPath(fullPath);
|
||||
using RegistryKey root = GetRootRegistryKey(rootKey);
|
||||
using RegistryKey key = root.OpenSubKey(relativePath);
|
||||
return key?.GetValue(valueName) != null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取注册表值
|
||||
/// </summary>
|
||||
/// <param name="fullPath">完整注册表路径</param>
|
||||
/// <param name="valueName">值名称</param>
|
||||
/// <param name="defaultValue">默认值</param>
|
||||
/// <returns>读取到的值,如果不存在返回默认值</returns>
|
||||
public static object ReadValue(string fullPath, string valueName, object defaultValue = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var (rootKey, relativePath) = ParseFullPath(fullPath);
|
||||
using RegistryKey root = GetRootRegistryKey(rootKey);
|
||||
using RegistryKey key = root.OpenSubKey(relativePath);
|
||||
|
||||
return key?.GetValue(valueName, defaultValue) ?? defaultValue;
|
||||
}
|
||||
catch (SecurityException ex)
|
||||
{
|
||||
throw new UnauthorizedAccessException($"没有权限读取注册表路径: {fullPath}", ex);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException($"读取注册表值时发生错误: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取字符串值
|
||||
/// </summary>
|
||||
public static string ReadString(string fullPath, string valueName, string defaultValue = "")
|
||||
{
|
||||
return ReadValue(fullPath, valueName, defaultValue) as string ?? defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取整数值(DWORD)
|
||||
/// </summary>
|
||||
public static int ReadDWord(string fullPath, string valueName, int defaultValue = 0)
|
||||
{
|
||||
object value = ReadValue(fullPath, valueName, defaultValue);
|
||||
return value is int intValue ? intValue : defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取长整数值(QWORD)
|
||||
/// </summary>
|
||||
public static long ReadQWord(string fullPath, string valueName, long defaultValue = 0)
|
||||
{
|
||||
object value = ReadValue(fullPath, valueName, defaultValue);
|
||||
return value is long longValue ? longValue : defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取二进制值
|
||||
/// </summary>
|
||||
public static byte[] ReadBinary(string fullPath, string valueName, byte[] defaultValue = null)
|
||||
{
|
||||
object value = ReadValue(fullPath, valueName, defaultValue);
|
||||
return value as byte[] ?? defaultValue ?? Array.Empty<byte>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取多字符串值
|
||||
/// </summary>
|
||||
public static string[] ReadMultiString(string fullPath, string valueName, string[] defaultValue = null)
|
||||
{
|
||||
object value = ReadValue(fullPath, valueName, defaultValue);
|
||||
return value as string[] ?? defaultValue ?? Array.Empty<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有子键名称
|
||||
/// </summary>
|
||||
public static string[] GetSubKeyNames(string fullPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
var (rootKey, relativePath) = ParseFullPath(fullPath);
|
||||
using RegistryKey root = GetRootRegistryKey(rootKey);
|
||||
using RegistryKey key = root.OpenSubKey(relativePath);
|
||||
|
||||
return key?.GetSubKeyNames() ?? Array.Empty<string>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException($"获取子键列表失败: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有值名称
|
||||
/// </summary>
|
||||
public static string[] GetValueNames(string fullPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
var (rootKey, relativePath) = ParseFullPath(fullPath);
|
||||
using RegistryKey root = GetRootRegistryKey(rootKey);
|
||||
using RegistryKey key = root.OpenSubKey(relativePath);
|
||||
|
||||
return key?.GetValueNames() ?? Array.Empty<string>();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException($"获取值名称列表失败: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取值的数据类型
|
||||
/// </summary>
|
||||
public static RegValueKind? GetValueKind(string fullPath, string valueName)
|
||||
{
|
||||
try
|
||||
{
|
||||
var (rootKey, relativePath) = ParseFullPath(fullPath);
|
||||
using RegistryKey root = GetRootRegistryKey(rootKey);
|
||||
using RegistryKey key = root.OpenSubKey(relativePath);
|
||||
|
||||
if (key == null) return null;
|
||||
|
||||
RegistryValueKind kind = key.GetValueKind(valueName);
|
||||
return (RegValueKind)kind;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 新增操作
|
||||
|
||||
/// <summary>
|
||||
/// 创建注册表项
|
||||
/// </summary>
|
||||
/// <param name="fullPath">完整注册表路径</param>
|
||||
/// <returns>是否创建成功</returns>
|
||||
public static bool CreateKey(string fullPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
var (rootKey, relativePath) = ParseFullPath(fullPath);
|
||||
using RegistryKey root = GetRootRegistryKey(rootKey);
|
||||
using RegistryKey key = root.CreateSubKey(relativePath);
|
||||
return key != null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException($"创建注册表项失败: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入注册表值
|
||||
/// </summary>
|
||||
/// <param name="fullPath">完整注册表路径</param>
|
||||
/// <param name="valueName">值名称</param>
|
||||
/// <param name="value">值数据</param>
|
||||
/// <param name="valueKind">值类型</param>
|
||||
public static void WriteValue(string fullPath, string valueName, object value, RegValueKind valueKind = RegValueKind.String)
|
||||
{
|
||||
try
|
||||
{
|
||||
var (rootKey, relativePath) = ParseFullPath(fullPath);
|
||||
using RegistryKey root = GetRootRegistryKey(rootKey);
|
||||
using RegistryKey key = root.CreateSubKey(relativePath);
|
||||
|
||||
if (key == null)
|
||||
throw new InvalidOperationException($"无法创建或打开注册表项: {fullPath}");
|
||||
|
||||
RegistryValueKind registryValueKind = ToRegistryValueKind(valueKind);
|
||||
key.SetValue(valueName, value, registryValueKind);
|
||||
}
|
||||
catch (SecurityException ex)
|
||||
{
|
||||
throw new UnauthorizedAccessException($"没有权限写入注册表路径: {fullPath}", ex);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException($"写入注册表值时发生错误: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入字符串值
|
||||
/// </summary>
|
||||
public static void WriteString(string fullPath, string valueName, string value)
|
||||
{
|
||||
WriteValue(fullPath, valueName, value, RegValueKind.String);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入扩展字符串值
|
||||
/// </summary>
|
||||
public static void WriteExpandString(string fullPath, string valueName, string value)
|
||||
{
|
||||
WriteValue(fullPath, valueName, value, RegValueKind.ExpandString);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入DWORD值
|
||||
/// </summary>
|
||||
public static void WriteDWord(string fullPath, string valueName, int value)
|
||||
{
|
||||
WriteValue(fullPath, valueName, value, RegValueKind.DWord);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入QWORD值
|
||||
/// </summary>
|
||||
public static void WriteQWord(string fullPath, string valueName, long value)
|
||||
{
|
||||
WriteValue(fullPath, valueName, value, RegValueKind.QWord);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入二进制值
|
||||
/// </summary>
|
||||
public static void WriteBinary(string fullPath, string valueName, byte[] value)
|
||||
{
|
||||
WriteValue(fullPath, valueName, value, RegValueKind.Binary);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 写入多字符串值
|
||||
/// </summary>
|
||||
public static void WriteMultiString(string fullPath, string valueName, string[] value)
|
||||
{
|
||||
WriteValue(fullPath, valueName, value, RegValueKind.MultiString);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 修改操作
|
||||
|
||||
/// <summary>
|
||||
/// 重命名注册表值
|
||||
/// </summary>
|
||||
/// <param name="fullPath">完整注册表路径</param>
|
||||
/// <param name="oldValueName">原值名称</param>
|
||||
/// <param name="newValueName">新值名称</param>
|
||||
public static void RenameValue(string fullPath, string oldValueName, string newValueName)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 读取原值
|
||||
object value = ReadValue(fullPath, oldValueName);
|
||||
RegValueKind? kind = GetValueKind(fullPath, oldValueName);
|
||||
|
||||
if (value == null || kind == null)
|
||||
throw new InvalidOperationException($"原值不存在或无法读取: {oldValueName}");
|
||||
|
||||
// 写入新值
|
||||
WriteValue(fullPath, newValueName, value, kind.Value);
|
||||
|
||||
// 删除原值
|
||||
DeleteValue(fullPath, oldValueName);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException($"重命名注册表值失败: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 删除操作
|
||||
|
||||
/// <summary>
|
||||
/// 删除注册表值
|
||||
/// </summary>
|
||||
/// <param name="fullPath">完整注册表路径</param>
|
||||
/// <param name="valueName">值名称</param>
|
||||
/// <returns>是否删除成功</returns>
|
||||
public static bool DeleteValue(string fullPath, string valueName)
|
||||
{
|
||||
try
|
||||
{
|
||||
var (rootKey, relativePath) = ParseFullPath(fullPath);
|
||||
using RegistryKey root = GetRootRegistryKey(rootKey);
|
||||
using RegistryKey key = root.OpenSubKey(relativePath, true);
|
||||
|
||||
if (key == null) return false;
|
||||
|
||||
key.DeleteValue(valueName, false);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException($"删除注册表值失败: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除注册表项
|
||||
/// </summary>
|
||||
/// <param name="fullPath">完整注册表路径</param>
|
||||
/// <param name="recursive">是否递归删除所有子项</param>
|
||||
/// <returns>是否删除成功</returns>
|
||||
public static bool DeleteKey(string fullPath, bool recursive = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
var (rootKey, relativePath) = ParseFullPath(fullPath);
|
||||
using RegistryKey root = GetRootRegistryKey(rootKey);
|
||||
|
||||
if (recursive)
|
||||
{
|
||||
root.DeleteSubKeyTree(relativePath, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
root.DeleteSubKey(relativePath, false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException($"删除注册表项失败: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 高级功能
|
||||
|
||||
/// <summary>
|
||||
/// 递归获取所有子键
|
||||
/// </summary>
|
||||
public static List<string> GetAllSubKeys(string fullPath, int maxDepth = 10)
|
||||
{
|
||||
List<string> results = new List<string>();
|
||||
GetAllSubKeysRecursive(fullPath, results, 0, maxDepth);
|
||||
return results;
|
||||
}
|
||||
|
||||
private static void GetAllSubKeysRecursive(string currentPath, List<string> results, int currentDepth, int maxDepth)
|
||||
{
|
||||
if (currentDepth >= maxDepth) return;
|
||||
|
||||
try
|
||||
{
|
||||
string[] subKeys = GetSubKeyNames(currentPath);
|
||||
foreach (string subKey in subKeys)
|
||||
{
|
||||
string subKeyPath = $"{currentPath}\\{subKey}";
|
||||
results.Add(subKeyPath);
|
||||
GetAllSubKeysRecursive(subKeyPath, results, currentDepth + 1, maxDepth);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 忽略无权限访问的键
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 备份注册表项到文件
|
||||
/// </summary>
|
||||
public static async Task BackupToFile(string fullPath, string outputFilePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
var (rootKey, relativePath) = ParseFullPath(fullPath);
|
||||
using RegistryKey root = GetRootRegistryKey(rootKey);
|
||||
using RegistryKey key = root.OpenSubKey(relativePath);
|
||||
|
||||
if (key == null)
|
||||
throw new InvalidOperationException($"注册表项不存在: {fullPath}");
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.AppendLine($"注册表备份: {fullPath}");
|
||||
sb.AppendLine($"备份时间: {DateTime.Now}");
|
||||
sb.AppendLine("=" + new string('=', 50));
|
||||
|
||||
// 备份值
|
||||
string[] valueNames = key.GetValueNames();
|
||||
foreach (string valueName in valueNames)
|
||||
{
|
||||
object value = key.GetValue(valueName);
|
||||
RegistryValueKind kind = key.GetValueKind(valueName);
|
||||
sb.AppendLine($"值: {valueName ?? "(默认)"}");
|
||||
sb.AppendLine($"类型: {kind}");
|
||||
sb.AppendLine($"数据: {ConvertValueToString(value, kind)}");
|
||||
sb.AppendLine();
|
||||
}
|
||||
|
||||
// 备份子键结构
|
||||
sb.AppendLine("子键结构:");
|
||||
BackupSubKeysRecursive(key, sb, 1);
|
||||
|
||||
await File.WriteAllTextAsync(outputFilePath, sb.ToString(), Encoding.UTF8);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException($"备份注册表失败: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static void BackupSubKeysRecursive(RegistryKey parentKey, StringBuilder sb, int depth)
|
||||
{
|
||||
string[] subKeyNames = parentKey.GetSubKeyNames();
|
||||
foreach (string subKeyName in subKeyNames)
|
||||
{
|
||||
sb.AppendLine($"{new string(' ', depth * 2)}[{subKeyName}]");
|
||||
using RegistryKey subKey = parentKey.OpenSubKey(subKeyName);
|
||||
if (subKey != null)
|
||||
{
|
||||
BackupSubKeysRecursive(subKey, sb, depth + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string ConvertValueToString(object value, RegistryValueKind kind)
|
||||
{
|
||||
return kind switch
|
||||
{
|
||||
RegistryValueKind.String or RegistryValueKind.ExpandString => value as string ?? string.Empty,
|
||||
RegistryValueKind.DWord => ((int)value).ToString(),
|
||||
RegistryValueKind.QWord => ((long)value).ToString(),
|
||||
RegistryValueKind.Binary => BitConverter.ToString((byte[])value),
|
||||
RegistryValueKind.MultiString => string.Join("; ", (string[])value),
|
||||
_ => value?.ToString() ?? string.Empty
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
65
Ramitta/SolidWorks.cs
Normal file
65
Ramitta/SolidWorks.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ramitta.lib
|
||||
{
|
||||
public static class ComInterop
|
||||
{
|
||||
internal const String OLEAUT32 = "oleaut32.dll";
|
||||
internal const String OLE32 = "ole32.dll";
|
||||
|
||||
[System.Security.SecurityCritical] // auto-generated_required
|
||||
public static Object GetActiveObject(String progID)
|
||||
{
|
||||
Object? obj = null;
|
||||
Guid clsid;
|
||||
|
||||
// Call CLSIDFromProgIDEx first then fall back on CLSIDFromProgID if
|
||||
// CLSIDFromProgIDEx doesn't exist.
|
||||
try
|
||||
{
|
||||
CLSIDFromProgIDEx(progID, out clsid);
|
||||
}
|
||||
// catch
|
||||
catch (Exception)
|
||||
{
|
||||
CLSIDFromProgID(progID, out clsid);
|
||||
}
|
||||
|
||||
GetActiveObject(ref clsid, IntPtr.Zero, out obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
//[DllImport(Microsoft.Win32.Win32Native.OLE32, PreserveSig = false)]
|
||||
[DllImport(OLE32, PreserveSig = false)]
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
[System.Security.SecurityCritical] // auto-generated
|
||||
private static extern void CLSIDFromProgIDEx([MarshalAs(UnmanagedType.LPWStr)] String progId, out Guid clsid);
|
||||
|
||||
//[DllImport(Microsoft.Win32.Win32Native.OLE32, PreserveSig = false)]
|
||||
[DllImport(OLE32, PreserveSig = false)]
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
[System.Security.SecurityCritical] // auto-generated
|
||||
private static extern void CLSIDFromProgID([MarshalAs(UnmanagedType.LPWStr)] String progId, out Guid clsid);
|
||||
|
||||
//[DllImport(Microsoft.Win32.Win32Native.OLEAUT32, PreserveSig = false)]
|
||||
[DllImport(OLEAUT32, PreserveSig = false)]
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
[System.Security.SecurityCritical] // auto-generated
|
||||
private static extern void GetActiveObject(ref Guid rclsid, IntPtr reserved, [MarshalAs(UnmanagedType.Interface)] out Object ppunk);
|
||||
|
||||
}
|
||||
public static class SolidWorks
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -75,6 +75,7 @@ namespace Ramitta
|
||||
elementFactory.SetValue(ComboBox.SelectedIndexProperty, 0);
|
||||
SetBindingToProperty(elementFactory, ComboBox.ItemsSourceProperty, $"[{columnName}].ItemsSource");
|
||||
SetBindingToProperty(elementFactory, ComboBox.SelectedValueProperty, $"[{columnName}].SelectedValue");
|
||||
SetBindingToProperty(elementFactory, ComboBox.MaxWidthProperty, $"[{columnName}].MaxWidth");
|
||||
break;
|
||||
case ColumnType.Label:
|
||||
elementFactory = new FrameworkElementFactory(typeof(Label));
|
||||
@@ -94,9 +95,6 @@ namespace Ramitta
|
||||
column.CellEditingTemplate = dataTemplate;
|
||||
xDataGrid.Columns.Add(column);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Dictionary<string, object> AddRow()
|
||||
{
|
||||
var keys = ColumnsName.Keys.ToList();
|
||||
|
||||
10
Ramitta/winView3D.xaml
Normal file
10
Ramitta/winView3D.xaml
Normal file
@@ -0,0 +1,10 @@
|
||||
<UserControl x:Class="Ramitta.winView3D"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Ramitta" xmlns:h="http://helix-toolkit.org/wpf"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid x:Name="MainGrid"/>
|
||||
</UserControl>
|
||||
164
Ramitta/winView3D.xaml.cs
Normal file
164
Ramitta/winView3D.xaml.cs
Normal file
@@ -0,0 +1,164 @@
|
||||
using HelixToolkit.Geometry;
|
||||
using HelixToolkit.Wpf;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Media3D;
|
||||
|
||||
namespace Ramitta
|
||||
{
|
||||
public partial class winView3D : UserControl
|
||||
{
|
||||
public HelixViewport3D _viewport3D;
|
||||
|
||||
public winView3D()
|
||||
{
|
||||
InitializeComponent();
|
||||
// 默认初始化
|
||||
Init("Viewport3D");
|
||||
}
|
||||
|
||||
public void Init(string name = "Viewport3D")
|
||||
{
|
||||
// 检查是否已有Viewport3D
|
||||
var existingViewport = FindName(name) as HelixViewport3D;
|
||||
if (existingViewport != null)
|
||||
{
|
||||
_viewport3D = existingViewport;
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 创建新的Viewport3D
|
||||
_viewport3D = new HelixViewport3D
|
||||
{
|
||||
Name = name,
|
||||
//Background = Brushes.White,
|
||||
IsPanEnabled = true,
|
||||
IsRotationEnabled = true,
|
||||
IsZoomEnabled = true,
|
||||
ShowCoordinateSystem = true,
|
||||
ShowViewCube = true,
|
||||
ZoomExtentsWhenLoaded = true
|
||||
};
|
||||
|
||||
// 添加到MainGrid(XAML中定义的Grid)
|
||||
MainGrid.Children.Add(_viewport3D);
|
||||
// 注册名称
|
||||
RegisterName(name, _viewport3D);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new InvalidOperationException($"Failed to initialize 3D view: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 在两点之间绘制一条3D直线
|
||||
/// </summary>
|
||||
/// <param name="point1">起点</param>
|
||||
/// <param name="point2">终点</param>
|
||||
/// <param name="color">线条颜色(默认红色)</param>
|
||||
/// <param name="thickness">线条粗细(默认2.0)</param>
|
||||
/// <returns>创建的线条可视化对象</returns>
|
||||
public LinesVisual3D DrawLineBetweenPoints( Point3D point1,
|
||||
Point3D point2,
|
||||
Color color = default,
|
||||
double thickness = 2.0,
|
||||
bool point1head=false,
|
||||
Color point1color=default,
|
||||
double point1radius = 0.5,
|
||||
bool point2head = false,
|
||||
Color point2color = default,
|
||||
double point2radius = 0.5)
|
||||
{
|
||||
// 如果没有指定颜色,使用红色
|
||||
if (color == default) color = Colors.Red;
|
||||
|
||||
var line = new LinesVisual3D
|
||||
{
|
||||
Points = new Point3DCollection { point1, point2 },
|
||||
Color = color,
|
||||
Thickness = thickness
|
||||
};
|
||||
|
||||
_viewport3D.Children.Add(line);
|
||||
|
||||
if (point1head)
|
||||
{
|
||||
DrawPointAsSphere(point1, color: point1color, radius: point1radius);
|
||||
}
|
||||
if (point2head)
|
||||
{
|
||||
DrawPointAsSphere(point2, color: point2color, radius: point2radius);
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
public SphereVisual3D DrawPointAsSphere(Point3D point,
|
||||
Color color = default,
|
||||
double radius = 0.5,
|
||||
int resolution = 10)
|
||||
{
|
||||
if (color == default) color = Colors.Green;
|
||||
|
||||
var sphere = new SphereVisual3D
|
||||
{
|
||||
Center = point,
|
||||
Radius = radius,
|
||||
ThetaDiv = resolution,
|
||||
PhiDiv = resolution,
|
||||
Material = new DiffuseMaterial(new SolidColorBrush(color))
|
||||
};
|
||||
|
||||
_viewport3D.Children.Add(sphere);
|
||||
return sphere;
|
||||
}
|
||||
|
||||
|
||||
// 其他辅助方法
|
||||
public void ClearAllModels()
|
||||
{
|
||||
if (_viewport3D == null) return;
|
||||
|
||||
// 保留光源和坐标轴网格,移除其他
|
||||
for (int i = _viewport3D.Children.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var child = _viewport3D.Children[i];
|
||||
if (!(child is SunLight || child is GridLinesVisual3D))
|
||||
{
|
||||
_viewport3D.Children.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
public void SetCamera(Point3D Position, Vector3D LookDirection) {
|
||||
// 设置相机 - 斜向下视角
|
||||
var camera = new PerspectiveCamera
|
||||
{
|
||||
// 从右上后方位看向结构中心,并稍微向下倾斜
|
||||
// 相机位置在结构的右、上、后方,距离根据结构尺寸动态调整
|
||||
Position = Position,
|
||||
|
||||
// 看向结构的中心点
|
||||
LookDirection = LookDirection,
|
||||
|
||||
UpDirection = new Vector3D(0, 1, 0), // Y轴为上方向
|
||||
FieldOfView = 45 // 视野角度
|
||||
};
|
||||
|
||||
_viewport3D.Camera = camera;
|
||||
_viewport3D.ZoomExtents();
|
||||
}
|
||||
|
||||
public void ZoomToExtents()
|
||||
{
|
||||
_viewport3D?.ZoomExtents();
|
||||
}
|
||||
|
||||
public void ResetView()
|
||||
{
|
||||
_viewport3D?.ResetCamera();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user