Saturday, November 27, 2010

By the Book Part 1 - Harvesting Families from a Project Model

This post is part 1 in response to the sample Revit API application I wrote for the book entitled "Mastering Revit Architecture 2011"... in Chapter 24 "Under the Hood of Revit." The book has a five star amazon rating (I'm sure most of it is due to the insane quality of Chapter 24). It's also available on Kindle!!!


I'm sure you'll also be excited to know that ALL of the authors for the above mentioned book will be at Autodesk University 2010 this week in Las Vegas!... So if you like autographs, bring your book and start yourself a man hunt to find these guys!... weeeee

I'll have to admit, I wrote the original sample very quickly and could have done a better job in terms of its feature availability. For instance, I left out the ability to select categories to export! That's right, this post will add functionality for category selection!

First create a form named "form_Main" and add a checked listbox named "CheckedListBoxCategories" along with five buttons named "ButtonSelectAll", "ButtonSelectNone", "ButtonExport", "ButtonCancel", and "ButtonBrowse." Add a progress bar named "ProgressBar1" and a few labels named "LabelExportPath", "LabelFileName", and "LabelExport." When you're done, your form should resemble something close to the image below.


Now that we've got the interface all worked out, let's get the form class constructor put together. The code below shows the required imports along with the basic class constructor that will be called to eventually display the form.


Imports Autodesk.Revit
Imports System.Windows.Forms
Imports System.IO

Public Class form_FamilyExport

    Private m_App As UI.UIApplication = Nothing
    Private m_Doc As DB.Document

    ''' <summary>
    ''' Form class constructor, don't forget InitializeComponent()
    ''' </summary>
    ''' <param name="cmdData">The UI.ExternalCommandData object</param>
    ''' <param name="strAppVer">Application Version</param>
    ''' <remarks></remarks>
    Public Sub New(ByVal cmdData As UI.ExternalCommandData, ByVal strAppVer As String)
        InitializeComponent()
        ' Private variables
        m_App = cmdData.Application
        m_Doc = m_App.ActiveUIDocument.Document
        ' Form configurations
        Me.Text = "Batch Export Families - " & strAppVer
        Me.ProgressBar1.Visible = False
        Me.ButtonExport.Enabled = False
        ' Set default export path adjacent to model location
        ' If workshared, use the central model path
        If m_Doc.IsWorkshared = True Then
            Try
                Me.LabelExportPath.Text = Path.GetDirectoryName(m_Doc.WorksharingCentralFilename) & "\Exported Families\"
            Catch ex As Exception
                ' Detached model will not have a file path
            End Try
        Else
            Me.LabelExportPath.Text = Path.GetDirectoryName(m_Doc.PathName) & "\Exported Families\"
        End If
        ' Clear the list
        Me.CheckedListBoxCategories.CheckOnClick = True
        Me.CheckedListBoxCategories.Items.Clear()
        Me.LabelFileName.Text = ""
        Me.LabelExportPath.Text = ""
        ' Get all categories
        GetCategories()
    End Sub

End Class

Everything so far is the same as what we talk about in the book except for the call to a function named GetCategories(). This new category function is very basic and only collects the names of all categories available in your Revit environment. The results are then recorded into the checkedlistbox on our form. The function below collects the strings into a list first so we can sort them and then from the list to the listbox.


''' <summary>
    ''' Get a list of all 'non tag' categories
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub GetCategories()
        ' Full list of Categories
        Dim categoryList As New List(Of String)
        For Each category As DB.Category In m_Doc.Settings.Categories
            categoryList.Add(category.Name)
        Next
        ' Alpha sort the list
        categoryList.Sort()
        ' Add categories to the listbox
        For Each x As String In categoryList
            If InStr(UCase(x), "TAGS", CompareMethod.Text) = 0 Then
                ' Add the category
                Me.CheckedListBoxCategories.Items.Add(x)
            End If
        Next
    End Sub

Now that we have a massive list of categories we should probably provide a quick means for selecting all or none of the items in the list. The code illustrates how the ButtonSelectNone and ButtonSelectAll buttons to their thing.


''' <summary>
    ''' Uncheck all items in the listbox
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub ButtonSelectNone_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonSelectNone.Click
        For i As Integer = 0 To CheckedListBoxCategories.Items.Count - 1
            CheckedListBoxCategories.SetItemChecked(i, False)
        Next
    End Sub

    ''' <summary>
    ''' Check all items in listbox
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub ButtonSelectAll_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonSelectAll.Click
        For i As Integer = 0 To CheckedListBoxCategories.Items.Count - 1
            CheckedListBoxCategories.SetItemChecked(i, True)
        Next
    End Sub

The updated export code will be demonstrated in "By the Book Part 2 - Harvesting Families from a Project Model", so stay tuned to see all that excitement!...