List wall and floor types and change the type of system instances
next previous home

In this section, we list system types and change the type of a system family instance element. All the previous labs in this section dealt with the standard families and instances. In this lab, we show more or less the same issues for system families, which are often host objects, such as walls and floors. Wall is the most comprehensively exposed host object so far in the Revit API. Specific and dedicated classes, methods and properties are available which makes them somewhat simpler to use than standard family instances.

Add a new command class to the Lab3 module, e.g. Lab3_5_WallAndFloorTypes. First we will enumerate all available wall types. This is simple thanks to the dedicated property on the document object. We will also store the last one in order to change the selected wall's type later without any complex user interface:

  //
  // Find all wall types and their system families (or kinds)
  //
  WallType newWallType = null;
  string sMsg = "ALL Wall Types/Families in the model:";
  foreach( WallType wt in doc.WallTypes )
  {
    sMsg += "\r\n  Type=" + wt.Name + " Family(or Kind)=" + wt.Kind.ToString();
    newWallType = wt;
  }
  LabUtils.InfoMsg( sMsg );
  LabUtils.InfoMsg( "Stored WallType " + newWallType.Name + " (Id=" + newWallType.Id.Value.ToString() + ") for later use" );
  ' Find ALL Wall Types and their System Families (or Kinds)
  '--------------------
  Dim newWallType As WallType = Nothing 'at the same time store the last one to use to change the wall type later
  Dim sMsg As String = "ALL Wall Types/Families in the model:"

  ' We could again iterete all elements and check for WallType class, but it's simpler directly from the doc:
  Dim doc As Revit.Document = commandData.Application.ActiveDocument
  For Each wt As WallType In doc.WallTypes
  	sMsg += vbCrLf & "  Type=" & wt.Name & " Family(or Kind)=" & wt.Kind.ToString
      newWallType = wt
  Next
  MsgBox(sMsg)
  MsgBox("Stored WallType " & newWallType.Name & " (Id=" & newWallType.Id.Value.ToString & ") for later use")

Implement the same functionality for floor types. Since Revit 2008, the document class has a FloorTypes property and we can use this to retrieve the collection of all the floor types. However from 9.0 version, the "Foundation Slab" system family from the "Structural Foundations" category also contain FloorType class instances.

In the C# sample, we loop through all the FloorTypes listed in the document and then check if the category of the floor type is same as built-in category of Floor. This is done by comparing the category id of the floor type element with that of the built-in Floors category. Please note that from Revit 2009 onwards, category ids need to be used to compare categories, instead of comparing categories with each other directly.

In the VB.Net sample, the approach is more performance centric, where we use a compound filter called NewLogicAndFilter and use that to filter elements of FloorType AND built-in category Floors to avoid structural foundation floor slabs.

  //
  // Find all floor types:
  //
  FloorType newFloorType = null;
  Category floorCat = doc.Settings.Categories.get_Item( BuiltInCategory.OST_Floors );
  sMsg = "All floor types in the model:";
  foreach( FloorType ft in doc.FloorTypes )
  {
    sMsg += "\r\n  Type=" + ft.Name + ", Id=" + ft.Id.Value.ToString();
    // In 9.0, the "Foundation Slab" system family from "Structural
    // Foundations" category ALSO contains FloorType class instances.
    // Be careful to exclude those as choices for standard floor types.
    Parameter p = ft.get_Parameter( BuiltInParameter.SYMBOL_FAMILY_NAME_PARAM );
    string famName = null == p ? "?" : p.AsString();
    Category cat = ft.Category;
    sMsg += ", Family=" + famName + ", Category=" + cat.Name;
    if( floorCat.Id.Equals( cat.Id ) ) // store only if proper Floors category
    {
      newFloorType = ft;
    }
  }
  LabUtils.InfoMsg( sMsg );
  LabUtils.InfoMsg( "Stored FloorType " + newFloorType.Name + " (Id=" + newFloorType.Id.Value.ToString() + ") for later use" );
  Dim newFloorType As FloorType = Nothing ' store the last one to use to change the floor type later
  sMsg = "ALL FLOOR Types in the model:"

  ' define a filter to get the family
  Dim filterFloorType As Filter = app.Create.Filter.NewTypeFilter(GetType(FloorType))
  Dim filterFloorCategory As Filter = app.Create.Filter.NewCategoryFilter(BuiltInCategory.OST_Floors)

  ' make a compund filter using logical or/and
  Dim filterFloorTypeFloorCategory As Filter = app.Create.Filter.NewLogicAndFilter(filterFloorType, filterFloorCategory)

  ' get a list using the filter
  Dim elementList As New List(Of Revit.Element)
  Dim num As Integer = doc.Elements(filterFloorTypeFloorCategory, elementList)

  ' go over the list
  Dim elem As Revit.Element
  For Each elem In elementList

      Dim ft As Symbols.FloorType = elem
      sMsg += vbCrLf & "  Type=" & ft.Name & ", Id=" & ft.Id.Value.ToString
      Dim p As Parameter = ft.Parameter(Parameters.BuiltInParameter.SYMBOL_FAMILY_NAME_PARAM)
      Dim famName As String = "?"
      If Not p Is Nothing Then
          famName = p.AsString
      End If
      Dim cat As Category = ft.Category
      sMsg += ", Family=" & famName & ", Category=" & cat.Name
      ' all elements have proper Floors category
      newFloorType = ft

  Next

  MsgBox(sMsg)
  MsgBox("Stored FloorType " & newFloorType.Name & " (Id=" & newFloorType.Id.Value.ToString & ") for later use")

Build the application, add the command to the Revit.ini file and check the result in the debugger and in Revit.

Modifying the wall and floor type of an instance are both simple operations in Revit 2009, since they each expose a WallType and FloorType property, respectively:

  //
  // Change the type for selected walls and floors
  //
  ElementSet sel = doc.Selection.Elements;
  int iWall = 0;
  int iFloor = 0;
  // Loop all selection elements
  foreach( Element el in sel )
  {
    if( el is Wall ) // Check for walls
    {
      ++iWall;
      Wall wall = el as Wall;
      WallType oldWallType = wall.WallType;
      // change wall type and report the old/new values
      wall.WallType = newWallType;
      LabUtils.InfoMsg( "Wall " + iWall.ToString() + ": Id=" + wall.Id.Value.ToString()
        + "\r\n  changed from OldType=" + oldWallType.Name + "; Id=" + oldWallType.Id.Value.ToString()
        + "  to NewType=" + wall.WallType.Name + "; Id=" + wall.WallType.Id.Value.ToString() );
    }
    else if( el is Floor )
    {
      ++iFloor;
      Floor f = el as Floor;
      FloorType oldFloorType = f.FloorType;
      f.FloorType = newFloorType;
      LabUtils.InfoMsg( "Floor " + iFloor.ToString() + ": Id=" + f.Id.Value.ToString()
        + "\r\n  changed from OldType=" + oldFloorType.Name + "; Id=" + oldFloorType.Id.Value.ToString()
        + "  to NewType=" + f.FloorType.Name + "; Id=" + f.FloorType.Id.Value.ToString() );
    }
  }
  ' Change the Type for selected Walls and Floors
  Dim sel As ElementSet = doc.Selection.Elements
  Dim iWall As Integer
  Dim iFloor As Integer
  Dim el As Revit.Element

  'Loop through all selection elements
  If sel.Size > 0 Then
      For Each el In sel
          If TypeOf el Is Wall Then 'Check for walls
              Dim wall As Wall = el
              iWall += 1
              Dim oldWallType As WallType = wall.WallType
              'change wall type and report the old/new values
              wall.WallType = newWallType
              MsgBox("Wall " & iWall.ToString & ": Id=" & wall.Id.Value.ToString & vbCrLf & _
               "  changed from OldType=" & oldWallType.Name & "; Id=" & oldWallType.Id.Value.ToString & _
               "  to NewType=" & wall.WallType.Name & "; Id=" & wall.WallType.Id.Value.ToString)

          ElseIf TypeOf el Is Floor Then
              iFloor += 1
              Dim f As Floor = el

              ' simple code for 2008 onwards:
              Dim oldFloorType As FloorType = f.FloorType
              f.FloorType = newFloorType
              MsgBox("Floor " & iFloor.ToString & ": Id=" & f.Id.Value.ToString & vbCrLf & _
               "  changed from OldType=" & oldFloorType.Name & "; Id=" & oldFloorType.Id.Value.ToString & _
               "  to NewType=" & f.FloorType.Name & "; Id=" & f.FloorType.Id.Value.ToString)
          End If
      Next
  Else
      MsgBox("There are no elements in selection set!")
  End If

Run, analyse and discuss the code with the course instructor and your peers.

next previous home copyright © 2007-2009 jeremy tammik, autodesk inc. all rights reserved.