Building Coder(Revit 二次开发) - 可扩展存储处理字典

原文链接: Extensible Storage of a Map

我在前面的博文里已经介绍过 Revit 2012 API 中新引入的可扩展存储功能 extensible storage。你还可以在 DevHelp Online Revit 2012 API webcast 找到更多的细节。

最近我更新了网络广播上的例程,下面是最新的主函数代码:
public Result Execute(
  ExternalCommandData commandData,
  ref string message,
  ElementSet elements )
{
  UIApplication uiapp = commandData.Application;
  UIDocument uidoc = uiapp.ActiveUIDocument;
  Document doc = uidoc.Document;
 
  try
  {
    // pick an element and define the XYZ 
    // data to store at the same time
 
    Reference r = uidoc.Selection.PickObject( 
      ObjectType.Face, 
      new WallFilter(), 
      "Please pick a wall at a point on one of its faces" );
 
    Wall wall = doc.get_Element( r.ElementId ) as Wall;
    XYZ dataToStore = r.GlobalPoint;
 
    Transaction t = new Transaction( doc,
      "Create Extensible Storage Schemata and Store Data" ); 
 
    t.Start();
 
    // store the data, and also 
    // demonstrate reading it back
 
    StoreDataInWall( wall, dataToStore );
 
    t.Commit();
 
    // list all schemas in memory across all documents
 
    ListSchemas();
 
    return Result.Succeeded;
  }
  catch( Exception ex )
  {
    message = ex.Message;
    return Result.Failed;
  }
}
这个外部命令首先要求用户通过指定点来选择一面墙体。PickObject 方法可以同时返回选中的墙体和选中的点。它使用一个实现了 ISelectionFilter 接口的 WallFilter 对象作为参数,来限制用户只能选择墙体。
class WallFilter : ISelectionFilter
{
  public bool AllowElement( Element e )
  {
    return e is Wall;
  }
 
  public bool AllowReference( Reference r, XYZ p )
  {
    return true;
  }
}
选中的点被封装为一个可扩展存储样式,然后保存到墙体模型中。下面是实现封装的辅助函数:
/// <summary>
/// Create an extensible storage schema, 
/// attach it to a wall, populate it with data, 
/// and retrieve the data back from the wall.
/// </summary>
void StoreDataInWall(
  Wall wall,
  XYZ dataToStore )
{
  SchemaBuilder schemaBuilder = new SchemaBuilder(
    new Guid( "720080CB-DA99-40DC-9415-E53F280AA1F0" ) );
 
  // allow anyone to read the object
 
  schemaBuilder.SetReadAccessLevel(
    AccessLevel.Public );
 
  // restrict writing to this vendor only
 
  schemaBuilder.SetWriteAccessLevel(
    AccessLevel.Vendor );
 
  // required because of restricted write-access
 
  schemaBuilder.SetVendorId( "ADNP" );
 
  // create a field to store an XYZ
 
  FieldBuilder fieldBuilder = schemaBuilder
    .AddSimpleField( "WireSpliceLocation",
    typeof( XYZ ) );
 
  fieldBuilder.SetUnitType( UnitType.UT_Length );
 
  fieldBuilder.SetDocumentation( "A stored "
    + "location value representing a wiring "
    + "splice in a wall." );
 
  schemaBuilder.SetSchemaName( "WireSpliceLocation" );
 
  // register the schema
 
  Schema schema = schemaBuilder.Finish(); 
 
  // create an entity (object) for this schema (class)
 
  Entity entity = new Entity( schema );
 
  // get the field from the schema
 
  Field fieldSpliceLocation = schema.GetField(
    "WireSpliceLocation" );
 
  // set the value for this entity
 
  entity.Set<XYZ>( fieldSpliceLocation, dataToStore,
    DisplayUnitType.DUT_METERS );
 
  // store the entity on the element
 
  wall.SetEntity( entity );
 
  // read back the data from the wall
 
  Entity retrievedEntity = wall.GetEntity( schema );
 
  XYZ retrievedData = retrievedEntity.Get<XYZ>(
    schema.GetField( "WireSpliceLocation" ),
    DisplayUnitType.DUT_METERS );
}
上面的主函数还调用了另外一个辅助函数 ListSchemas 来显示所有被加载到当前文档中的样式。
/// <summary>
/// List all schemas in Revit memory across all documents.
/// </summary>
void ListSchemas()
{
  IList<Schema> schemas = Schema.ListSchemas();
 
  int n = schemas.Count;
 
  Debug.Print( 
    string.Format( "{0} schema{1} defined:", 
      n, PluralSuffix( n ) ) );
 
  foreach( Schema s in schemas )
  {
    IList<Field> fields = s.ListFields();
 
    n = fields.Count;
 
    Debug.Print( 
      string.Format( "Schema '{0}' has {1} field{2}:", 
        s.SchemaName, n, PluralSuffix( n ) ) );
 
    foreach( Field f in fields )
    {
      Debug.Print(
        string.Format( 
          "Field '{0}' has value type {1}"
          + " and unit type {2}", f.FieldName, 
          f.ValueType, f.UnitType ) );
    }
  }
}

利用可扩展存储保存一个字典

在上面的例子里,我们只保存了一个简单的 XYZ 数据。最近我被问及如何保存一个更加复杂的数据,比方说字典。

提问

我想使用以下代码将一个字符串字典保存到文档中:

FieldBuilder.AddMapField( MyMappedField, typeof( string ), typeof( string ) );


但问题是我应该如何调用 Entity.Set<???>(???) 方法呢?类似地问题还有,如何读取和删除字典类型的数据呢?

回答

简单地说,应该使用 IDictionary<> 作为类型参数调用 Entity.Set<>() 方法,即使实际的数据类型是 Dictionary<>。实际上 Revit API 的帮助文档提到了这一点,不过叙述得不太清楚。顺便说一句,SDK 例程 ExtensibleStorageManager 里也有实际的代码。
  // Note that we use IDictionary<> for 
  // map types and IList<> for array types
 
  mySchemaWrapper
    .AddField<IDictionary<string, string>>(
      map0Name, UnitType.UT_Undefined, null );
 
  mySchemaWrapper
    .AddField<IList<bool>>(
      array0Name, UnitType.UT_Undefined, null );
我更新了之前提到的网络广播的例程,最新的主函数如下:
/// <summary>
/// Create an extensible storage schema specifying 
/// a dictionary mapping keys to values, both using 
/// strings,  populate it with data, attach it to the 
/// given element, and retrieve the data back again.
/// </summary>
void StoreStringMapInElement( Element e )
{
  SchemaBuilder schemaBuilder = new SchemaBuilder(
    new Guid( "F1697E22-9338-4A5C-8317-5B6EE088ECB4" ) );
 
  // allow anyone to read or write the object
 
  schemaBuilder.SetReadAccessLevel(
    AccessLevel.Public );
 
  schemaBuilder.SetWriteAccessLevel(
    AccessLevel.Public );
 
  // create a field to store a string map
 
  FieldBuilder fieldBuilder
    = schemaBuilder.AddMapField( "StringMap",
      typeof( string ), typeof( string ) );
 
  fieldBuilder.SetDocumentation(
    "A string map for Tobias." );
 
  schemaBuilder.SetSchemaName(
    "TobiasStringMap" );
 
  // register the schema
 
  Schema schema = schemaBuilder.Finish();
 
  // create an entity (object) for this schema (class)
 
  Entity entity = new Entity( schema );
 
  // get the field from the schema
 
  Field field = schema.GetField(
    "StringMap" );
 
  // set the value for this entity
 
  IDictionary<string, string> stringMap
    = new Dictionary<string, string>();
 
  stringMap.Add( "key1", "value1" );
  stringMap.Add( "key2", "value2" );
 
  entity.Set<IDictionary<string, string>>(
    field, stringMap );
 
  // store the entity on the element
 
  e.SetEntity( entity );
 
  // read back the data from the wall
 
  Entity retrievedEntity = e.GetEntity( schema );
 
  IDictionary<string, string> stringMap2
    = retrievedEntity
    .Get<IDictionary<string, string>>(
      schema.GetField( "StringMap" ) );
}
你也可以从这里下载完整的代码 ExtensibleStorage.zip

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值