Files
ShrlAlgoToolkit/Sai.Toolkit.Revit/Assist/ExtensibleStorageAssist.cs
2024-10-08 16:21:39 +08:00

522 lines
15 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.IO;
using System.Windows;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.ExtensibleStorage;
namespace Sai.Toolkit.Revit.Assist;
/// <summary>
/// 可扩展存储工具Schema框架->由字段Field组成,由Schema可以生成、构建Entity实体
/// 层级关系:Entity->Schema/Field定义/Field属性-值
/// 元素阵列不会复制扩展数据
/// </summary>
/// <example>
/// <c>
/// IList<string> list = new List<string> { "我的v1", "我的v2", "我的v3", "我的v4" };
/// IDictionary<string, string> dict = new Dictionary<string, string>
/// {
/// { "p1", "v1" },
/// { "p2", "v2" },
/// { "p3", "v3" },
/// { "p4", "v4" }
/// };
/// var builder = CreateSchemaBuilder(schemaName);
/// //添加字段定义
/// builder.AddSimpleField("simple", typeof(string));
/// builder.AddArrayField("errorModels", typeof(string));
/// builder.AddMapField("dict", typeof(string), typeof(string));
/// builder.AddSingleField<string>("simple");
/// builder.AddListField<string>("errorModels");
/// builder.AddDictField<string, string>("dict");
/// //创建Schema
/// var schema = builder.CreateSchema();
/// var entity = e.CreateEntity(schema);
/// e.SetFieldValue("simple", "简单");
/// e.SetFieldValue("errorModels", list);
/// e.SetFieldValue("dict", dict);</c>
/// </example>
public static class ExtensibleStorageAssist
{
private static Entity GetEntity(this Schema schema, Element element)
{
if (element is null)
{
return null;
}
var entity = element.GetEntity(schema);
if (entity.Schema is not null)
{
return entity;
}
entity = new Entity(schema);
return entity;
}
/// <summary>
/// 创建字典类型的字段
/// </summary>
/// <typeparam name="TK">keyBoolean, Byte, Int16, Int32, Float, Double, ElementId,GUID, String, XYZ, UV and Entity</typeparam>
/// <typeparam name="TV">valueBoolean, Byte, Int16, Int32, Float, Double, ElementId,GUID, String, XYZ, UV and Entity</typeparam>
/// <param name="schemaBuilder"></param>
/// <param name="fieldName"></param>
/// <param name="description">描述</param>
/// <returns></returns>
public static FieldBuilder AddDictField<TK, TV>(this SchemaBuilder schemaBuilder, string fieldName, string description = "")
{
if (schemaBuilder is null)
{
throw new ArgumentNullException(nameof(schemaBuilder));
}
if (fieldName is null)
{
throw new ArgumentNullException(nameof(fieldName));
}
//if (!typeof(TK).IsPrimitive)
// throw new NotSupportedException(nameof(TK));
//if (!typeof(TV).IsPrimitive)
// throw new NotSupportedException(nameof(TV));
if (description == string.Empty)
{
description = fieldName;
}
var result = schemaBuilder.AddMapField(fieldName, typeof(TK), typeof(TV));
result.SetDocumentation(description);
return result;
}
/// <summary>
/// 创建集合类型的字段
/// </summary>
/// <typeparam name="T">Boolean, Byte, Int16, Int32, Float, Double, ElementId,GUID, String, XYZ, UV and Entity</typeparam>
/// <param name="schemaBuilder"></param>
/// <param name="fieldName"></param>
/// <param name="description">描述</param>
public static FieldBuilder AddListField<T>(this SchemaBuilder schemaBuilder, string fieldName, string description = "")
{
if (schemaBuilder is null)
{
throw new ArgumentNullException(nameof(schemaBuilder));
}
if (fieldName is null)
{
throw new ArgumentNullException(nameof(fieldName));
}
//if (!typeof(Command).IsPrimitive)
// throw new NotSupportedException(nameof(Command));
var result = schemaBuilder.AddArrayField(fieldName, typeof(T));
if (description == string.Empty)
{
description = fieldName;
}
result.SetDocumentation(description);
return result;
}
/// <summary>
/// 创建简单类型的字段
/// </summary>
/// <typeparam name="T">Boolean, Byte, Int16, Int32, Float, Double, ElementId,GUID, String, XYZ, UV and Entity</typeparam>
/// <param name="schemaBuilder"></param>
/// <param name="fieldName"></param>
/// <param name="description">描述</param>
/// <returns></returns>
public static FieldBuilder AddSingleField<T>(this SchemaBuilder schemaBuilder, string fieldName, string description = "")
{
if (schemaBuilder is null)
{
throw new ArgumentNullException(nameof(schemaBuilder));
}
if (fieldName is null)
{
throw new ArgumentNullException(nameof(fieldName));
}
//if (!typeof(Command).IsPrimitive)
// throw new NotSupportedException(nameof(Command));
var result = schemaBuilder.AddSimpleField(fieldName, typeof(T));
//result.SetUnitType(unitType);
if (description == string.Empty)
{
description = fieldName;
}
result.SetDocumentation(description);
return result;
}
/// <summary>
/// 创建元素扩展数据实体
/// </summary>
/// <param name="element"></param>
/// <param name="schema"></param>
/// <returns></returns>
public static Entity CreateEntity(this Element element, Schema schema)
{
Entity entity = new(schema);
element.SetEntity(entity);
return entity;
}
/// <summary>
/// 创建Schema
/// </summary>
/// <param name="builder"></param>
/// <returns></returns>
public static Schema CreateSchema(this SchemaBuilder builder)
{
return builder?.Finish();
}
/// <summary>
/// 创建参数的表
/// </summary>
/// <param name="schemaName"></param>
/// <param name="accessLevel"></param>
/// <param name="description"></param>
/// <returns></returns>
public static SchemaBuilder CreateSchemaBuilder(string schemaName, AccessLevel accessLevel = AccessLevel.Public, string description = null)
{
if (schemaName is null)
{
throw new ArgumentNullException(nameof(schemaName));
}
SchemaBuilder builder = new(Guid.NewGuid());
builder.SetReadAccessLevel(accessLevel);
builder.SetWriteAccessLevel(accessLevel);
builder.SetSchemaName(schemaName);
description ??= schemaName;
builder.SetDocumentation(description);
#if USE_FORGETYPEID
//roleFieldBuilder.SetSpec(SpecTypeId.Custom);//设置字段值的单位,并不是所有类型都需要单位
#else
//roleFieldBuilder.SetUnitType(UnitType.UT_Undefined);//设置字段值的单位,并不是所有类型都需要单位
//roleFieldBuilder1.SetUnitType(UnitType.UT_Undefined);//设置字段值的单位,并不是所有类型都需要单位
//roleFieldBuilder2.SetUnitType(UnitType.UT_Undefined);//设置字段值的单位,并不是所有类型都需要单位
#endif
return builder;
}
/// <summary>
/// 删除实体
/// </summary>
/// <param name="element">元素</param>
/// <param name="fieldName">字段名</param>
public static void DeleteEntityByFieldName(this Element element, string fieldName)
{
var schema = element.GetSchemaByFieldName(fieldName);
if (schema != null)
{
element.DeleteEntity(schema);
}
}
/// <summary>
/// 删除实体
/// </summary>
/// <param name="element">元素</param>
/// <param name="schemaName">表名</param>
public static void DeleteEntityBySchemaName(this Element element, string schemaName)
{
var schema = element.GetSchemaBySchemaName(schemaName);
if (schema != null)
{
element.DeleteEntity(schema);
}
}
/// <summary>
/// 获取文件级数据存储
/// </summary>
/// <param name="doc"></param>
/// <param name="schemaName"></param>
/// <param name="fieldName"></param>
/// <param name="fileName"></param>
public static void GetDateStorage(Document doc, string schemaName, string fieldName, string fileName)
{
DataStorage storage = new FilteredElementCollector(doc).OfClass(typeof(DataStorage)).Cast<DataStorage>().First();
Schema sch = Schema.ListSchemas().First(o => o.SchemaName == schemaName);
Entity ent = storage.GetEntity(sch);
byte[] bytes = ent.Get<byte[]>(sch.GetField(fieldName)).ToArray();
using (FileStream fs = new(fileName, FileMode.Create, FileAccess.Write))
{
fs.Write(bytes, 0, bytes.Length);
}
MessageBox.Show("文件提取完毕!", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
}
/// <summary>
/// 获取字段参数值
/// </summary>
/// <param name="element">元素</param>
/// <param name="fieldName">字段名</param>
public static T GetFieldValue<T>(this Element element, string fieldName)
where T : new()
{
if (!typeof(T).IsPrimitive)
{
throw new NotSupportedException(nameof(T));
}
T t = new();
try
{
Schema schema = element.GetSchemaByFieldName(fieldName);
Entity entity = element.GetEntity(schema);
if (!entity.IsValid())
{
return t;
}
Field f = schema.GetField(fieldName);
return entity.Get<T>(f);
}
catch
{
return t;
}
}
/// <summary>
/// 获取元素的所有字段值
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="e"></param>
/// <returns></returns>
public static List<T> GetFiledValues<T>(this Element e)
{
if (!typeof(T).IsPrimitive)
{
throw new NotSupportedException(nameof(T));
}
List<T> storages = new();
//方法一
var schemaGuids = e.GetEntitySchemaGuids();
foreach (var schemaGuid in schemaGuids)
{
Schema schema = Schema.Lookup(schemaGuid);
Entity ent = e.GetEntity(schema);
if (!ent.IsValid())
{
return storages;
}
IList<Field> fields = schema.ListFields();
foreach (var field in fields)
{
var f = ent.Get<T>(field);
storages.Add(f);
}
}
//if (storages.Count == 0)
//{
// //方法二
// //从内存中获取 Schema 列表
// IList<Schema> schemas = Schema.ListSchemas();
// //从 Schema 中获取 Field 列表
// foreach (var schema in schemas)
// {
// IList<Field> fields = schema.ListFields();
// Entity ent = e.GetEntity(schema);
// foreach (var field in fields)
// {
// var f = ent.Get<Command>(field);
// storages.Add(f);
// }
// }
//}
return storages;
}
/// <summary>
/// 通过字段名称获取Schema
/// </summary>
/// <param name="elm"></param>
/// <param name="fieldName"></param>
/// <returns></returns>
public static Schema GetSchemaByFieldName(this Element elm, string fieldName)
{
if (elm is null)
{
throw new ArgumentNullException(nameof(elm));
}
if (fieldName is null)
{
throw new ArgumentNullException(nameof(fieldName));
}
var schemaGuids = elm.GetEntitySchemaGuids();
return schemaGuids.Select(Schema.Lookup).FirstOrDefault(f => f.GetField(fieldName) != null);
}
/// <summary>
/// 通过Schema名称获取Schema
/// </summary>
/// <param name="elm"></param>
/// <param name="schemaName"></param>
/// <returns></returns>
public static Schema GetSchemaBySchemaName(this Element elm, string schemaName)
{
if (elm is null)
{
throw new ArgumentNullException(nameof(elm));
}
if (schemaName is null)
{
throw new ArgumentNullException(nameof(schemaName));
}
var schemaGuids = elm.GetEntitySchemaGuids();
return schemaGuids.Select(Schema.Lookup).FirstOrDefault(f => f.SchemaName == schemaName);
}
/// <summary>
/// 从元素中读取schema中存储的值
/// </summary>
/// <param name="element">存储数据的元素</param>
/// <param name="schema">Existing schema</param>
/// <param name="fieldName">The Field name</param>
/// <typeparam name="T">schema中要存储的数据类型。该类型必须与schemabuilder中指定的数据类型相匹配。</typeparam>
/// <returns>存储在元素中的数据。如果字段不存在或数据尚未保存,则返回空值</returns>
/// <example>
/// <code>
/// document.ProjectInformation.LoadEntity&lt;string&lt;(schema, "schemaField")
/// </code>
/// </example>
public static T LoadEntity<T>(this Element element, Schema schema, string fieldName)
{
var field = schema.GetField(fieldName);
var entity = schema.GetEntity(element);
return entity is null || field is null ? default : entity.Get<T>(field);
}
/// <summary>
/// 在元素中存储数据。现有数据将被覆盖
/// </summary>
/// <param name="element">存储数据的元素</param>
/// <param name="schema">Existing schema</param>
/// <param name="data">Type of data</param>
/// <param name="fieldName">The Field name</param>
/// <typeparam name="T">The type of data to be stored in the schema. The type must match the type of data specified in the SchemaBuilder</typeparam>
/// <returns>True if entity save succeeded</returns>
/// <example>
/// <code>
/// document.ProjectInformation.SaveEntity(schema, "data", "schemaField")
/// </code>
/// </example>
/// <summary>
public static bool SaveEntity<T>(this Element element, Schema schema, T data, string fieldName)
{
var field = schema.GetField(fieldName);
if (field is null)
{
return false;
}
var entity = schema.GetEntity(element);
if (entity is null)
{
return false;
}
entity.Set(field, data);
element.SetEntity(entity);
return true;
}
/// <summary>
/// 设置文件级别数据存储
/// </summary>
/// <param name="doc"></param>
/// <param name="fileName"></param>
public static void SetDateStorage(Document doc, string fileName)
{
Transaction tran = new(doc, "BIM");
tran.Start();
//项目文档中使用扩展数据,可以使用静态方法创建
DataStorage store = DataStorage.Create(doc);
Schema schema;
using (SchemaBuilder schemaBuilder = new(new Guid(Guid.NewGuid().ToString("D"))))
{
schemaBuilder.SetReadAccessLevel(AccessLevel.Public);
schemaBuilder.SetWriteAccessLevel(AccessLevel.Public);
schemaBuilder.SetSchemaName("LeiFile");
schemaBuilder.SetDocumentation("DataStorageFile");
FieldBuilder arrayField = schemaBuilder.AddArrayField("data", typeof(byte));
arrayField.SetDocumentation("Store file data");
schema = schemaBuilder.Finish();
}
byte[] data;
using (FileStream stream = new(fileName, FileMode.Open, FileAccess.Read))
{
data = new byte[(int)stream.Length];
stream.Read(data, 0, data.Length);
stream.Close();
}
Entity entity = new(schema);
Field field = schema.GetField("data");
entity.Set(field, data);
store.SetEntity(entity);
MessageBox.Show("文件存储成功!", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
tran.Commit();
}
/// <summary>
/// 设置可扩展参数的值:简单类型、集合、字典(这一步骤涉及对文档的修改,需在事务中进行)
/// </summary>
/// <param name="element">元素</param>
/// <param name="fieldName">字段</param>
/// <param name="value">字段值</param>
public static void SetFieldValue<T>(this Element element, string fieldName, T value)
{
Schema schema = element.GetSchemaByFieldName(fieldName);
var entity = element.GetEntity(schema);
Field field = schema.GetField(fieldName);
entity.Set(field, value);
element.SetEntity(entity);
}
/// <summary>
/// 设置可扩展参数的值:简单类型、集合、字典(这一步骤涉及对文档的修改,需在事务中进行)
/// </summary>
/// <param name="element">元素</param>
/// <param name="schema"></param>
/// <param name="fieldName">字段</param>
/// <param name="value">字段值</param>
public static void SetFieldValue<T>(this Element element, Schema schema, string fieldName, T value)
{
var entity = element.GetEntity(schema);
Field field = schema.GetField(fieldName);
entity.Set(field, value);
element.SetEntity(entity);
}
}