That's right... HOK San Francisco's own Travis Schmiesing won the 2010 HOK BIMie award for Best Visualization by a LANDSLIDE! Not only did he and Brian Campbell do all the work themselves, Travis presented their work and left the room in awe! The Animation presented was AMAZING. Truly professional!!
The project titles of which were presented have to be left anonymous for the time being, but each left us all speechless!! These projects will hopefully be given clearance to be mentioned in a later post on hokbimsolutions.blogspot.com !!
Four awards were handed out in four distinct categories(winners from from left to right!!!):
Category C - Best Collaboration
Irena Zamozniak from the HOK Toronto Office (a real example of raising the bar)!!!
Category A - Best Concept Design:
Kevin Shumbera from the HOK Houston Office (he got lucky)!!!
Category B - Best Design Delivery
Travon Price out of the Washington D.C. Office (really cool presentation)!!!!!!
Category D - Best Visualization
Travis Schmiesing from my home San Francisco team office (... it was... "ok" :) )!!!
Many thanks to the buildingSMART and ATG team as well as all of the sponsors and associated partners that helped kick the event over to the next level!!!
A truly successful event!!
Tuesday, November 30, 2010
Monday, November 29, 2010
By the Book Part 2 - Harvesting Families from a Project Model
This post is part 2 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."
Well, I promised I would show you the updated family export code in my previous post "By the Book Part 1 - Harvesting Families from a Project Model."... so without further procrastination...
We'll get started off by setting the code to our export button illustrated below. All this does is hide the lower buttons to make room for the progress bar and then runs the export routine. When we're all done, we'll call the close function for the form and exit out.
I guess we should get the last remaining function out of the way as well before we dive into the export function. The function below is used to verify that all characters used to create a file name are valid for the Windows OS.
The export function starts out by first verifying that at least one category has been checked for export. Then a hashtable is used as a means to reference each selection (hashtables are FAST).
The next thing to do is make sure the target directory exists for the export.
With the main directory created, we can continue with the element collection and progress bar setup. The filter below grabs all "Type" elements from the model and turns the result into an easy to use list of DB.Element.
Now we can iterate the element list and perform the necessary exports as external RFA files.
That's it! Now you have the means to quickly harvest families from a Revit 2011 model.
If you have any questions or suggestions for other Revit 2011 code solutions, don't hesitate to leave a comment or ask a question.
Well, I promised I would show you the updated family export code in my previous post "By the Book Part 1 - Harvesting Families from a Project Model."... so without further procrastination...
We'll get started off by setting the code to our export button illustrated below. All this does is hide the lower buttons to make room for the progress bar and then runs the export routine. When we're all done, we'll call the close function for the form and exit out.
''' <summary> ''' Export the families and then quietly close ''' </summary> ''' <param name="sender"></param> ''' <param name="e"></param> ''' <remarks></remarks> Private Sub ButtonExport_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonExport.Click Me.ButtonCancel.Visible = False Me.ButtonExport.Visible = False Me.ButtonSelectAll.Visible = False Me.ButtonSelectNone.Visible = False doExport() ' We're all done Me.Close() End Sub
I guess we should get the last remaining function out of the way as well before we dive into the export function. The function below is used to verify that all characters used to create a file name are valid for the Windows OS.
''' <summary> ''' Make sure the path does not contain any invalid file naming characters ''' </summary> ''' <param name="fileName">The Filename to check</param> ''' <returns>A string</returns> ''' <remarks></remarks> Private Function CheckValidFileName(ByVal fileName As String) As String For Each c In Path.GetInvalidFileNameChars() If fileName.Contains(c) Then ' Invalid filename characters detected... ' Could either replace characters or return empty Return "" End If Next Return fileName End Function
The export function starts out by first verifying that at least one category has been checked for export. Then a hashtable is used as a means to reference each selection (hashtables are FAST).
''' <summary> ''' This routine performs the exports ''' </summary> ''' <remarks></remarks> Private Sub doExport() ' Ony export families that belong to our selected categories! Dim m_SelectedCategories = Me.CheckedListBoxCategories.CheckedItems ' Do nothing if nothing selected If m_SelectedCategories.Count = 0 Then MsgBox("You did not select any categories..." & vbCr & "Nothing to do...", _ MsgBoxStyle.Information, "No Categories Selected! Exiting...") Exit Sub End If ' A hashtable comes in handy when verifying multiple situations... or 1 Dim m_CatHash As New Hashtable For Each xItemC In m_SelectedCategories m_CatHash.Add(xItemC.ToString, "Category") Next
The next thing to do is make sure the target directory exists for the export.
Try ' If the parent export directory is missing, create it Directory.CreateDirectory(Replace(Me.LabelExportPath.Text, "/", "\", , , CompareMethod.Text)) Catch ex As Exception ' Message to show any errors MsgBox(Err.Description, MsgBoxStyle.Information, Err.Source) End Try
With the main directory created, we can continue with the element collection and progress bar setup. The filter below grabs all "Type" elements from the model and turns the result into an easy to use list of DB.Element.
' Filter to get a set of elements that are elementType Dim m_SymbFilter As New DB.ElementIsElementTypeFilter Dim collector As New DB.FilteredElementCollector(m_Doc) collector.WherePasses(m_SymbFilter) ' Create a list from the collector Dim FamilySymbols As New List(Of DB.Element) FamilySymbols = collector.ToElements ' Start the progressbar Dim iCnt As Integer = 0 Dim iCntFam As Integer = FamilySymbols.Count Me.ProgressBar1.Visible = True Me.ProgressBar1.Minimum = 0 Me.ProgressBar1.Maximum = iCntFam Me.ProgressBar1.Value = iCnt
Now we can iterate the element list and perform the necessary exports as external RFA files.
' The export process For Each x As DB.Element In FamilySymbols If (TypeOf x Is DB.FamilySymbol) Then Dim m_category As DB.Category = x.Category If Not (m_category Is Nothing) Then ' Is it a selected category? If m_CatHash.Contains(m_category.Name) Then Dim m_ExportPath As String = "" Try ' Create the subdirectory m_ExportPath = Me.LabelExportPath.Text & "\" & m_category.Name & "\" Directory.CreateDirectory(Replace(m_ExportPath, "/", "\", , , CompareMethod.Text)) Catch ex As Exception ' Category subdirectory exists End Try Try ' The family element Dim m_FamSymb As DB.FamilySymbol = x Dim m_FamInst As DB.Family = m_FamSymb.Family Dim m_FamName As String = m_FamInst.Name ' Verify famname is valid filename and exists If Dir$(m_ExportPath + m_FamName & ".rfa") = "" And CheckValidFileName(m_FamName) <> "" Then Me.LabelFileName.Text = "...\" & m_category.Name & "\" & m_FamInst.Name Dim famDoc As DB.Document = m_Doc.EditFamily(m_FamInst) famDoc.SaveAs(m_ExportPath + m_FamName & ".rfa") famDoc.Close(False) End If Catch ex As Exception ' Prevent hault on system families End Try End If End If End If ' Step the progress bar Me.ProgressBar1.Increment(1) Next
That's it! Now you have the means to quickly harvest families from a Revit 2011 model.
If you have any questions or suggestions for other Revit 2011 code solutions, don't hesitate to leave a comment or ask a question.
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.
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.
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.
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!...
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!...
Thursday, November 25, 2010
A Classy Way to Handle Revit Parameters
You may have noticed some of my previous posts referencing a clsPara object. I've been getting lots of interesting questions regarding this object and how it's built and just what the heck it does. Well... I guess I'll share.
My clsPara class is entirely reusable and very handy for handling data transactions in and out of parameters. Not only does this object connect with built-in parameters, it also connects with element properties! I know, its SO super exciting (breathe).
Let's start from the beginning... create a new class named clsPara and add the basic Autodesk.Revit reference as illustrated below.
The next thing we need to do is provide a constructor that we can use to build this class into a meaningful object. All we need to accept as an argument is a Revit parameter. We'll handle all the rest internally within the class in a very simple yet highly efficient manner.
Our new clsPara object can now be called from anywhere in the project with the following code and argument (where myParam is a valid Revit Parameter reference):
The next step is to provide all the basic data interaction routines and properties. We'll start with the data interactions for retrieving data from a Revit Parameter within the class.
Now another function to SET a value to a parameter:
Now that we can set and get a value for a Revit Parameter... let's add some functionality to react within the class using some handy properties!!! Exciting, I know....
... I know!!! Don't forget to breathe!!
My clsPara class is entirely reusable and very handy for handling data transactions in and out of parameters. Not only does this object connect with built-in parameters, it also connects with element properties! I know, its SO super exciting (breathe).
Let's start from the beginning... create a new class named clsPara and add the basic Autodesk.Revit reference as illustrated below.
Imports Autodesk.Revit ''' <summary> ''' An awesome class used to define a parameter ''' </summary> ''' <remarks></remarks> Public Class clsPara End Class
The next thing we need to do is provide a constructor that we can use to build this class into a meaningful object. All we need to accept as an argument is a Revit parameter. We'll handle all the rest internally within the class in a very simple yet highly efficient manner.
Private m_parameter As DB.Parameter ''' <summary> ''' Constructor ''' </summary> ''' <param name="parameter">Revit Parameter Object</param> ''' <remarks></remarks> Public Sub New(ByVal parameter As DB.Parameter) m_parameter = parameter End Sub
Our new clsPara object can now be called from anywhere in the project with the following code and argument (where myParam is a valid Revit Parameter reference):
Dim myLittleParam As New clsPara(myParam)
The next step is to provide all the basic data interaction routines and properties. We'll start with the data interactions for retrieving data from a Revit Parameter within the class.
''' <summary> ''' Get a parameter's value ''' </summary> ''' <param name="parameter"></param> ''' <returns></returns> ''' <remarks></remarks> Public Shared Function GetParameterValue(ByVal parameter As DB.Parameter) As String 'public static Object GetParameterValue(Parameter parameter) Select Case parameter.StorageType Case DB.StorageType.[Double] 'get value with unit, AsDouble() can get value without unit Return parameter.AsDouble Case DB.StorageType.ElementId ' Returns Only the ElementID Return parameter.AsElementId.IntegerValue Case DB.StorageType.[Integer] 'get value with unit, AsInteger() can get value without unit Return parameter.AsInteger Case DB.StorageType.None Return parameter.AsValueString() Case DB.StorageType.[String] Return parameter.AsString() Case Else Return "" End Select End Function
Now another function to SET a value to a parameter:
''' <summary> ''' Set a Parameter's value ''' </summary> ''' <param name="parameter"></param> ''' <param name="value"></param> ''' <remarks></remarks> Public Shared Sub SetParameterValue(ByVal parameter As DB.Parameter, ByVal value As Object) 'first,check whether this parameter is read only If parameter.IsReadOnly Then Exit Sub End If Select Case parameter.StorageType Case DB.StorageType.[Double] 'set value with unit, Set() can set value without unit parameter.SetValueString(TryCast(value, String)) Exit Select Case DB.StorageType.ElementId Dim myElementId As DB.ElementId = DirectCast((value), DB.ElementId) parameter.[Set](myElementId) 'MsgBox("Reminder to finish elementid write routine...") Exit Select Case DB.StorageType.[Integer] 'set value with unit, Set() can set value without unit parameter.SetValueString(TryCast(value, String)) Exit Select Case DB.StorageType.None parameter.SetValueString(TryCast(value, String)) Exit Select Case DB.StorageType.[String] parameter.[Set](TryCast(value, String)) Exit Select Case Else Exit Select End Select End Sub
Now that we can set and get a value for a Revit Parameter... let's add some functionality to react within the class using some handy properties!!! Exciting, I know....
''' <summary> ''' This property will return the value!! ''' </summary> ''' <value></value> ''' <returns></returns> ''' <remarks></remarks> Public Property Value() As String Get Try Return GetParameterValue(m_parameter) Catch Return Nothing End Try End Get Set(ByVal value As String) Try SetParameterValue(m_parameter, value) Catch End Try End Set End Property ''' <summary> ''' What's the unit type, anyway? ''' </summary> ''' <value></value> ''' <returns></returns> ''' <remarks></remarks> Public ReadOnly Property DisplayUnitType() As String Get Try Return m_parameter.DisplayUnitType.ToString Catch Return Nothing End Try End Get End Property ''' <summary> ''' True if this is a Read Only parameter such as Area!! ''' Will not fail when trying to write to a read-only parameter!! ''' </summary> ''' <value></value> ''' <returns></returns> ''' <remarks></remarks> Public ReadOnly Property ParameterIsReadOnly() As Boolean Get Try Return m_parameter.IsReadOnly Catch Return Nothing End Try End Get End Property ''' <summary> ''' Returns true or false if this is a Shared Parameter! ''' </summary> ''' <value></value> ''' <returns></returns> ''' <remarks></remarks> Public ReadOnly Property ParameterIsShared() As Boolean Get Try Return m_parameter.IsShared Catch Return Nothing End Try End Get End Property ''' <summary> ''' Returns the type of parameter, sometimes useful ''' </summary> ''' <value></value> ''' <returns></returns> ''' <remarks></remarks> Public ReadOnly Property ParaType() As String Get Try Return m_parameter.GetType.Name Catch Return Nothing End Try End Get End Property ''' <summary> ''' Returns the parameter name ''' </summary> ''' <value></value> ''' <returns></returns> ''' <remarks></remarks> Public ReadOnly Property ParaName() As String Get Try Return m_parameter.Definition.Name Catch Return Nothing End Try End Get End Property ''' <summary> ''' This property will return the data format! ''' </summary> ''' <value></value> ''' <returns></returns> ''' <remarks></remarks> Public ReadOnly Property Format() As String Get Try Return m_parameter.StorageType.ToString Catch Return Nothing End Try End Get End Property
... I know!!! Don't forget to breathe!!
Saturday, November 20, 2010
Tracking Revision Clouds in Revit 2011 can be a bit... Cloudy
Have you ever tried to schedule Revision Clouds in Revit 2011?... not so fun when you find that it is impossible... not to mention that if you select a revision cloud in a sheet and try the ol "Select All Instances" that the option is NOT supported for Revision Clouds... WTF....
Imagine if you had a means to export all revision clouds in your model to a neat and easy to view Excel document where you could see the sheet number of the sheet that the cloud displays on along with even the comments and revision date and sequence information... that would be pretty cool, huh?
I think this is a real short coming of Revit 2011, so here is a bit of code I used to solve the problem. I obviously cannot give you ALL of the code (what fun would that be?)... but I will share with you how I got ahold of the elements and then queried their view names and target sheet numbers and names.
First create a form and drop a filesave dialog from the tools menu and name it "SaveFileDialogCSV"... set the filetype filter to CSV... bla bla bla... The code below demonstrates the verification on the resulting file saved by the dialog. Eventually when satisfied there is a little function called "doScan" that actually scans the model for the Revision Cloud elements.
The next section of code generates a couple lists. One list for the Revision Cloud elements in the project selected by category and one for the sheets that exist in the model. This sample will ignore revision cloud elements that are on views that are not placed on sheets since if they aren't on a sheet, they are not part of the documentation (sounded logical at the time). At the end, we make sure the model has at least one sheet before we continue.
Now the next section saves the data it finds for each ViewSheet into a class named clsSheetMapper (not shown) so I can maintain an easy reference to the data between the clouds found on sheets and their host sheets.
The next bit of code finishes it up by scanning the revision cloud elements into a class named clsRevCloud I use to collect all of the view naming, sheet data and Revision Cloud parameter data into a single class and saving their parameter data to yet another secret class not shown named clsPara.
Now that we've got this handy list of classes with all of the sheet, view, and parameter data we can iterate them all and write the results to an external file... in this case it is a CSV file.
That's it... now if you ever have a HUGE project and a needy client that wants this data each time to issue a revision set, you can export a handy report for their use as well as for you to help keep track of your changes in your models.
Imagine if you had a means to export all revision clouds in your model to a neat and easy to view Excel document where you could see the sheet number of the sheet that the cloud displays on along with even the comments and revision date and sequence information... that would be pretty cool, huh?
I think this is a real short coming of Revit 2011, so here is a bit of code I used to solve the problem. I obviously cannot give you ALL of the code (what fun would that be?)... but I will share with you how I got ahold of the elements and then queried their view names and target sheet numbers and names.
First create a form and drop a filesave dialog from the tools menu and name it "SaveFileDialogCSV"... set the filetype filter to CSV... bla bla bla... The code below demonstrates the verification on the resulting file saved by the dialog. Eventually when satisfied there is a little function called "doScan" that actually scans the model for the Revision Cloud elements.
Me.SaveFileDialogCSV.ShowDialog() If SaveFileDialogCSV.FileName <> "" Then If File.Exists(SaveFileDialogCSV.FileName) = True Then Try ' Start with a clean file File.Delete(SaveFileDialogCSV.FileName) Catch ex As Exception End Try End If ' Scan for Revision Cloud Elements doScan() Else MsgBox("Please select a valid file name and location", MsgBoxStyle.Exclamation, "Error") Me.Close() End If
' Collect Sheets m_Sheets = New List(Of DB.Element) Dim m_SheetCollector As New DB.FilteredElementCollector(m_Doc) m_SheetCollector.OfCategory(DB.BuiltInCategory.OST_Sheets) m_Sheets = m_SheetCollector.ToElements ' Collect Revision Clouds m_RevClouds = New List(Of DB.Element) Dim m_RevCloudCollector As New DB.FilteredElementCollector(m_Doc) m_RevCloudCollector.OfCategory(DB.BuiltInCategory.OST_RevisionClouds) m_RevClouds = m_RevCloudCollector.ToElements ' No sheets... no revisions! If m_Sheets.Count < 1 Then Me.Close()
Now the next section saves the data it finds for each ViewSheet into a class named clsSheetMapper (not shown) so I can maintain an easy reference to the data between the clouds found on sheets and their host sheets.
' List all sheets and views for easy reference For Each x As DB.ViewSheet In m_Sheets ' Sheet element Dim m_Sht As New clsSheetMapper(x.Id.ToString, True) ' Sheet Number Dim m_ShtNumber As String = x.SheetNumber m_Sht.SheetNumber = m_ShtNumber ' Sheet Name Dim m_ShtName As String = x.Name m_Sht.SheetName = x.Name ' Add the view to the master list m_ViewsList.Add(m_Sht) ' Add the Views For Each y As DB.Element In x.Views ' View element Dim m_View As New clsSheetMapper(y.Id.ToString, False) ' Sheet Number m_View.SheetNumber = m_ShtNumber ' Sheet Name m_View.SheetName = m_ShtName ' View Name m_View.ViewName = y.Name ' Add the view to the master list m_ViewsList.Add(m_View) Next Next
The next bit of code finishes it up by scanning the revision cloud elements into a class named clsRevCloud I use to collect all of the view naming, sheet data and Revision Cloud parameter data into a single class and saving their parameter data to yet another secret class not shown named clsPara.
' Write the title line in our CSV file writeCSVline("Sheet Number, Sheet Name, View Name, ElementID, Revision Number, Revision Date, Comments, Mark, Issued To, Issued By") m_Revs.Clear() ' Process Revision Cloud Elements For Each m_RevCloud As DB.Element In m_RevClouds ' Create a matching Rev Item Dim m_RevItem As New clsRevcloud(m_RevCloud.Id.ToString) ' Test for viewID For Each x As clsSheetMapper In m_ViewsList Try If x.ViewID = m_Doc.Element(m_RevCloud.OwnerViewId).Id.ToString Then ' This is the view item If x.SheetNumber IsNot Nothing Then m_RevItem.SheetNumber = x.SheetNumber End If If x.SheetName IsNot Nothing Then m_RevItem.SheetName = x.SheetName End If If x.ViewName IsNot Nothing Then m_RevItem.ViewName = x.ViewName End If For Each y As DB.Parameter In m_RevCloud.Parameters Dim myPara As New clsPara(y) If myPara.Value IsNot Nothing Then Select Case y.Definition.Name.ToUpper Case "REVISION NUMBER" m_RevItem.RevisionNumber = myPara.Value Case "REVISION DATE" m_RevItem.RevisionDate = myPara.Value Case "COMMENTS" m_RevItem.Comments = myPara.Value Case "MARK" m_RevItem.Mark = myPara.Value Case "ISSUED TO" m_RevItem.IssuedTo = myPara.Value Case "ISSUED BY" m_RevItem.IssuedBy = myPara.Value End Select End If Next Exit For End If Catch ex As Exception ' Some may not have an ownerID End Try Next m_Revs.Add(m_RevItem) Next
Now that we've got this handy list of classes with all of the sheet, view, and parameter data we can iterate them all and write the results to an external file... in this case it is a CSV file.
' Write all of the records For Each x As clsRevcloud In m_Revs ' Skip items without a sheet number If x.SheetNumber IsNot Nothing And x.SheetNumber <> "" Then Dim LineItem As String = "" LineItem = x.SheetNumber & "," LineItem = LineItem & x.SheetName & "," LineItem = LineItem & x.ViewName & "," LineItem = LineItem & x.ElementID & "," LineItem = LineItem & x.RevisionNumber & "," LineItem = LineItem & x.RevisionDate & "," LineItem = LineItem & x.Comments & "," LineItem = LineItem & x.Mark & "," LineItem = LineItem & x.IssuedTo & "," LineItem = LineItem & x.IssuedBy ' Write the Line writeCSVline(LineItem) End If Next
That's it... now if you ever have a HUGE project and a needy client that wants this data each time to issue a revision set, you can export a handy report for their use as well as for you to help keep track of your changes in your models.
Tuesday, November 16, 2010
Where the Heck are all the AU2010 Handouts?... Lost?
I've been getting messages about where people can download the handout that I uploaded for my CP333-1 class. I logged into AU's website and looked around to see if I could find where/how to download the handouts and I'll have to say, I had NO LUCK.
Where are the handouts? I looked everywhere I could think of searching high and low with no luck.
So to get around this I'll post a link to where you can download the handout on my own personal data store (NOT AN AU SITE). You can download the CP333-1 Handout here.
I'm wondering if AU is delaying the actual post of the handouts pending their own edits?... not sure what is really going on.
Where are the handouts? I looked everywhere I could think of searching high and low with no luck.
So to get around this I'll post a link to where you can download the handout on my own personal data store (NOT AN AU SITE). You can download the CP333-1 Handout here.
I'm wondering if AU is delaying the actual post of the handouts pending their own edits?... not sure what is really going on.
Saturday, November 6, 2010
Closing a Microsoft Access 2007 Session with Yet Even More Brute Force! (part 2)
My post back in October regarding how to close MsAccess with Brute Force (Part 1) left out a few other tricks... I'll admit this is a freaky thing to deal with to say the least so here are a few BONUS functions that can help you deal with shutting down a Microsoft Access 2007 Interop session programmatically:..
The KillMsAccessApps is a function that iterates through all open processes running on your machine and kills the ones that are named MSACCESS... quite effective indeed.
You may also need to minimize a session of Microsoft Access 2007 from time to time. Since I'm in such a good mood today, I'll throw in these three BONUS snips for minimizing an MSACCE.
The KillMsAccessApps is a function that iterates through all open processes running on your machine and kills the ones that are named MSACCESS... quite effective indeed.
''' <summary> ''' Close and destroy all MSACCESS Applications ''' </summary> ''' <remarks></remarks> Sub KillMsAccessApps() For Each p As Process In Process.GetProcessesByName("MSACCESS") p.Kill() Next p End Sub
You may also need to minimize a session of Microsoft Access 2007 from time to time. Since I'm in such a good mood today, I'll throw in these three BONUS snips for minimizing an MSACCE.
''' <summary> ''' Minimize all MSACCESS Applications ''' </summary> ''' <remarks></remarks> Sub MinimizeMsAccessApps() For Each p As Process In Process.GetProcessesByName("MSACCESS") ShowWindow(p.MainWindowHandle, SHOW_WINDOW.SW_SHOWMINIMIZED) Next p End Sub ''' <summary> ''' For minimizing applications ''' </summary> ''' <param name="hWnd"></param> ''' <param name="nCmdShow"></param> ''' <returns></returns> ''' <remarks></remarks> Private Declare Function ShowWindow Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal nCmdShow As SHOW_WINDOW) As Boolean ''' <summary> ''' Human readable flag enums for minimizing applications ''' </summary> ''' <remarks></remarks> <Flags()> _ Private Enum SHOW_WINDOW As Integer SW_HIDE = 0 SW_SHOWNORMAL = 1 SW_NORMAL = 1 SW_SHOWMINIMIZED = 2 SW_SHOWMAXIMIZED = 3 SW_MAXIMIZE = 3 SW_SHOWNOACTIVATE = 4 SW_SHOW = 5 SW_MINIMIZE = 6 SW_SHOWMINNOACTIVE = 7 SW_SHOWNA = 8 SW_RESTORE = 9 SW_SHOWDEFAULT = 10 SW_FORCEMINIMIZE = 11 SW_MAX = 11 End Enum
Debugging a .NET 3.5 Class with Revit 2011 from Visual Studio 2010
Have you ever tried to build a Revit 2011 addin in Visual Studio 2010 only to discover that your debug will not work!!!??? This can be very frustrating but easily fixed if you follow the quick configuration steps illustrated in this post!!
You will need to make a couple minor configurations to both the Autodesk Revit 2011 configuration file and the Visual Studio 2010 development environment in order to successfully debug a Visual Studio 2010 application.
Since all projects built for Autodesk Revit 2011 must be compiled targeting the Microsoft .NET 3.5 Framework, you will first need to set your Visual Studio project to target the .NET Framework 3.5:
The Visual Studio 2010 default .NET Framework is 4.0 while the required .NET Framework for Autodesk Revit 2011 is 3.5. You will need to specify a target framework environment in the Revit 2011 executable configuration file so Visual Studio doesn’t try to debug in its default .NET Framework 4 mode.
Modify the Revit.exe.config file to support debug with Visual Studio 2010 by navigating to the Program directory beneath your Revit product's installation directory and open the XML formatted file named “Revit.exe.config” in an ASCII text editor such as Notepad.exe.
That's it!... You can now debug a Revit 2011 addin from Visual Studio 2010
You will need to make a couple minor configurations to both the Autodesk Revit 2011 configuration file and the Visual Studio 2010 development environment in order to successfully debug a Visual Studio 2010 application.
Since all projects built for Autodesk Revit 2011 must be compiled targeting the Microsoft .NET 3.5 Framework, you will first need to set your Visual Studio project to target the .NET Framework 3.5:
The Visual Studio 2010 default .NET Framework is 4.0 while the required .NET Framework for Autodesk Revit 2011 is 3.5. You will need to specify a target framework environment in the Revit 2011 executable configuration file so Visual Studio doesn’t try to debug in its default .NET Framework 4 mode.
Modify the Revit.exe.config file to support debug with Visual Studio 2010 by navigating to the Program directory beneath your Revit product's installation directory and open the XML formatted file named “Revit.exe.config” in an ASCII text editor such as Notepad.exe.
Add the following three lines highlighted in yellow just inside the closing tag of “configuration” to allow debug control with Visual Studio 2010:
That's it!... You can now debug a Revit 2011 addin from Visual Studio 2010
Subscribe to:
Posts (Atom)