Showing posts with label Tricks. Show all posts
Showing posts with label Tricks. Show all posts

Tuesday, October 2, 2012

Prevent Double Click Opening of Central Files

It happens all too often that a rookie user or non Revit savvy person double clicks on an RVT file to open it. If this RVT is a work shared central model then it is a real cluster F%#&. This can be disastrous to anyone working in the model as well as the model's health in general if not correctly saved back as a central model with all elements properly relinquished.


This post will show a way to keep RVT files from being able to be opened by double clicking them (do this on the client machines where you think run a high risk of causing an issue with this). This still will not prevent a "smart" user from dragging an RVT file onto their Revit shortcut on their desktop though, so be aware of that.

This can easily be setup in your IT Manager's Group Policy for all current users of a domain if you really want to enforce this for everyone... or maybe just to users within a certain group?... you get the idea.

You do NOT need admin privileges to make this adjustment because it will change the setting for the current user only.

Create a new txt file (or download mine) and place the following lines in it
(save it as "RevitFileOpenTroll.reg"):


Windows Registry Editor Version 5.00
 
[HKEY_CURRENT_USER\Software\Classes\rvt_auto_file]
@="BIM Model :P"
 
[HKEY_CURRENT_USER\Software\Classes\rvt_auto_file\shell]
 
[HKEY_CURRENT_USER\Software\Classes\rvt_auto_file\shell\open]
 
[HKEY_CURRENT_USER\Software\Classes\rvt_auto_file\shell\open\command]
@="explorer http://wikihelp.autodesk.com/Revit/enu/2013/Help/00001-Revit_He0/2278-Collabor2278/2333-Working_2333/2354-Working_2354/2363-Opening_2363"

Double click this file on any machine that you want to make this change for. After running this registry updater, double clicking an RVT file will open the Autodesk Wiki page showing the proper method for opening a workshared model.

You can change the web site to one of your own if you like that tells the proper method for opening an RVT in your organization.

Friday, April 6, 2012

Revit 2013 Visual Studio 2010 Template

For those of you that also write Add-Ins for Revit, I went ahead and posted an updated template for Autodesk Revit Architecture 2013. I've included links to a VB.NET and C# template below.
Installing VB.NET
Copy this zip file as-is (do not unzip it) into a directory beneath
"%USERPROFILE%\Documents\Visual Studio 2010\Templates\ProjectTemplates\Visual Basic" 

Installing C#
Copy this zip file as-is (do not unzip it) into a directory beneath
"%USERPROFILE%\Documents\Visual Studio 2010\Templates\ProjectTemplates\Visual C#" 

The next time you launch Visual Studio 2010, you will notice a new project template named "Revit Architecture 2013 Template" in the directory's name you placed it under kinda like what you see below.


Wednesday, December 28, 2011

Strange To Room and From Room Data on Elements

If you have relied on the "To Room" or "From Room" data on an element and didn't always get what you were expecting, I'd be willing to bet that it is due to one of two things. No room elements in the newest phase of your model or refer* to the first reason.

* recursion humor

Room data for the "To Room" and "From Room" parameters on FamilyInstance elements can only read from rooms in the youngest phase in time. This means that any room you place in a previous phase in your model will be ignored in terms of "To Room" and "From Room" no matter what. Confused yet?

Let's say that your model has three phases:

  • Existing
  • Main Construction
  • Future
If you perform most of your modeling and place your rooms in the "Main Construction" phase none of your elements will return a "To Room" or "From Room" element at all unless these rooms are placed in the "Future" phase. Something even a bit more confusing is that your existing doors will report the "To Room" and "From Room" data for the room that exists in the same location in the newest phase.

The image below shows the room data that results from a door selected in a view that is set to the existing phase. There are rooms on either side both places in the existing phase yet the data reported by the door is showing from the future. If the rooms placed in the future phase were deleted, this door would not display any room data even though there are clearly two existing rooms on either side of the door.



The two phases are shown below to help you understand how this door data is coming through the element.



The "To Room" and "From Room" data comes from the rooms placed in the newest phase of your model only so be careful when developing tools that rely on these room settings. You can see below what happens when an element is not adjacent to any rooms in the last phase of your model... you get nothing:


Thursday, December 15, 2011

How To Uninstall or Remove a Revit Add-In

I've been getting this question quite a bit recently:
"How do I remove an Add-In from Revit?"



This post will not focus on what an Add-In is nor what an Add-In manifest is... hopefully you already have an idea or can find out about those things here.

The uninstall solution depends on the version of Revit that you are running. The method that I will discuss in this post is suitable for Revit 2011 and newer. If you are using Revit 2010 then you just need to go ahead and upgrade your shiz.

There are two locations that Add-In manifests can be placed to load into Revit. The paths shown below are for Windows7. If you are still running Windows XP than it may be time to update your other shiz.

Machine Wide Location
The first is available to all users that log into the machine and requires administrative privileges to add files to.

  • C:\ProgramData\Autodesk\Revit\Addins\
User Profile Location
The user profile location will only load for the current user. This location does not require administrative privileges and therefor anyone can install Revit Add-Ins into their environment if they use this location.
  • %USERPROFILE%\AppData\Roaming\Autodesk\Revit\Addins\

Preventing the Add-In from Loading
There's a bunch of ways to prevent an Add-In from loading into Revit.

  • Removing the associated .addin file from either of the locations mentioned above will prevent the Add-In from loading into Revit. You can leave the .dll and all other files there if you want and they will not load without the associated .addin file instructing Revit to do so.
  • Another trick is to simply rename the extension of the .addin file to something like .addin.notloaded or something to keep it from loading.
  • Revit 2011 and 2012 do not load .addin files that are placed in sub-directories of these Add-In manifest directories either, so you could just simply create a sub-directory for the Add-Ins that you don't want to be loaded and place them in that sub directory.

Saturday, October 1, 2011

How to Build a ClickOnce Installer for Revit Add-Ins

Have you ever wanted to deploy an installation package that did not required Admin privileges for the distribution of your Revit Add-ins? Do you also need a simple means to deploy frequent updates? ClickOnce installers can do just that for you.


Microsoft unveiled the ClickOnce technology way back in 2003 and is great so long as your application is simple and does not require any modifications during install that may require administrative access. ClickOnce works by copying an entire isolated application to the user's profile on install. There is a small issue in that ClickOnce is not available for class library projects (Revit Add-Ins are class library projects).

Here is a workaround that you can use to deploy a ClickOnce application to install your Revit Add-Ins.

From inside your current Revit Add-In Visual Studio solution, add a new Windows Console project named the same as your target project but with a ".Updater" suffix added to the end. Save this new project alongside your current project. This new console project will only be used to copy the Revit Add-In program files into the user's Revit Add-Ins directory under their Windows user profile.



This new project will allow you to generate the published installer that a standard class will not. Open the project settings and click on the "Publish" tab along the left (VB.NET, C# will be different). You can enter a version setting as well as an installation URL where youy will post your updates.


Notice the highlighted path above in the URL section? You need to also enter this in the "Updates" section. Click on the "Updates" button to access the optional updates settings.


You can set the project and publisher settings from the "Options" button shown here.


The next thing that you need to do is add a reference to your main project so that the resulting dll files can be included as part of the installation of this console project. Add a reference to your console project and choose your project from the Projects tab.


Now that you have a reference to this project, you can add the output dll to your ClickOnce installation process. From the Publish tab, click the "Application Files" button and make sure that everything required by your Revit-Add-In is also available within this dialog. Set each file to "Include" that you will require in your main installation.


You may have noticed that the ".addin" file is included in the above list. Be sure to add your addin file to the console project so that it can be included in this list as it is required in order for the Revit Add-In to launch in a Revit session.

You can also add an icon to be used by your installer if you like by setting an icon in the "Application" tab of the console project.

Now that you've got the basic format of the publish project configured, you'll need some code to copy the files into the user's Revit Add-Ins directory. Enter the following code in the default "Module1" that was created automatically in your new console project to do just that:


Imports System.IO
Imports System.Reflection

Module mod1

    Private m_sourcePath As String = Path.GetDirectoryName(Assembly.GetExecutingAssembly.Location)
    Private m_w7 As String = Environment.GetEnvironmentVariable("UserProfile") & "\AppData\Roaming\"
    Private m_xp As String = Environment.GetEnvironmentVariable("UserProfile") & "\Application Data\"

    ''' <summary>
    ''' The Main Function
    ''' </summary>
    ''' <remarks></remarks>
    Sub Main()
        ' Test for Win7
        If Directory.Exists(m_w7) Then
            DoCopy(m_w7)
            Exit Sub
        End If
        ' Test for XP
        If Directory.Exists(m_xp) Then
            DoCopy(m_xp)
            Exit Sub
        End If
        ' Warn on Failure
        MsgBox("Your Operating System was not Properly Detected", MsgBoxStyle.Exclamation, "Installation Failed")
    End Sub

    ''' <summary>
    ''' Copy the Files
    ''' </summary>
    ''' <param name="p_destination"></param>
    ''' <remarks></remarks>
    Private Sub DoCopy(p_destination As String)
        ' Addin path
        Dim m_PathAddin As String = p_destination & "Autodesk\Revit\Addins\2012"
        ' Get Files
        Dim m_di As New DirectoryInfo(m_sourcePath)
        Dim m_FilesAddin As FileInfo() = m_di.GetFiles("*.addin")
        Dim m_FilesDll As FileInfo() = m_di.GetFiles("*.dll")
        For Each x In m_FilesAddin
            Try
                x.CopyTo(m_PathAddin & "\" & x.Name, True)
            Catch ex As Exception
                ' Quiet Fail
            End Try
        Next
        For Each x In m_FilesDll
            Try
                x.CopyTo(m_PathAddin & "\" & x.Name, True)
            Catch ex As Exception
                ' Quiet Fail
            End Try
        Next
    End Sub

End Module

After you've made all the necessary adjustments, you can click the "Publish Now" button in the Publish tab to publish the project. A new Publish directory will be created beneath the directory where your new console project was saved. This is your ClickOnce installer? Copy the entire set of files to either a location on your network or to an FTP on the web where you will host the installations. The ".application" file is the installer. Setup.exe can be used for browsers other than IE.


Each subsequent time that you update your code, click the "Publish Now" button to create a new publish installer. Each sequence will be saved in the same location. Copy the updated files to the location where you are hosting your updates and will become available to your users by executing the "updater" program that was originally installed on your client's machines (Executing the tool from inside Revit will NOT automatically update the tools in this configuration).

Be sure and use Internet Explorer to run the "*.application" ClickOnce installer as this is the only browser that will support this technology so far.

Tuesday, August 30, 2011

Relax Dataset Constraints for TableAdapters in .NET

This is a very common issue that people run into as they begin to use complex dataset objects in their .NET development work. This applies to ASP.NET as well as Winforms development work... even WPF.

If you've ever put together a complex join query in one of your TableAdapter objects and then in your code attempted to apply it to a DataTable object, you may have seen this warning and had no idea what to do about it:

The solution is simple. Open your XSD in design view and select on the background area (do not select a query or a TableAdapter).

Then in the properties pallet you will see a property named "EnforceConstraints". Set this property to False.


This option gives you the ability to provide dataset level constraints which are usually not necessary if your database backend has its own constraints.

Wednesday, August 24, 2011

Using the Find Items Feature in Navisworks 2012 for Revit Rooms

I've heard some frustrations from people on how to use the Find Items feature in Navisworks 2012 to find Revit rooms within the model.

The first thing that you need to make sure is that the "Export room geometry" option is checked prior to exporting the Revit model to Navisworks 2012.


Then in the "Find Items" dialog accessible from the View tab of the ribbon under the Windows drop-down set the following line in your search:

  • Category = Category
  • Property = Name
  • Condition = =
  • Value = Rooms
This will find all Revit rooms in your Navisworks model where you can then save this as a search set for future use without ever having to update your selections.


Monday, August 15, 2011

Check a String for Valid File Naming Characters

Here's a super simple solution to a surprisingly common problem for validating file naming strings using .NET.

If you have ever required a user to enter a file name and had to validate the characters they entered, I'm sure you have some sort of function that can do this. Surprisingly though, I see a bunch of code where people build their own file name character validation functions.

There is a built-in .NET function for validating file naming characters available from the System.IO namespace. The snippet below shows a very basic use of this command accepting an input of a string to validate and returns the same string back out if valid and an empty string if invalid file naming characters are detected.

    ''' <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
You can call this function like:

If CheckValidFileName(m_string) = "" Then Throw New Exception
If an empty string is returned, you've got invalid characters in the file name...

Tuesday, August 2, 2011

Revit 2011 Categories that Do NOT Have Types

I've taken the liberty of listing each Revit 2011 category that does not contain types for anyone looking to impress their spouse with some pointless trivia (more for my own future reference than anything else).

Can anyone name the one category that only has types and no instances??....


AREAS
AREA LOADS
DUCT SYSTEMS
ELECTRICAL CIRCUITS
EXTERIOR
GBXML SURFACE
LEVELS
HVAC ZONES
INTERIOR
INTERNAL AREA LOADS
INTERNAL LINE LOADS
INTERNAL POINT LOADS
LINE LOADS
MASS EXTERIOR WALL
MASS FLOOR
MASS GLAZING
MASS INTERIOR WALL
MASS OPENING
MASS ROOF
MASS SKYLIGHT
MASS ZONE
MATERIALS
OPENING
PADS
PIPING SYSTEMS
POINT LOADS
PROJECT INFORMATION
ROADS
ROOMS
SHADE
SHAFT OPENINGS
SHEETS
SPACES
SWITCH SYSTEM
UNDERGROUND
VIEWS

FACIAS is the category that only contains types and no instances...

Monday, May 2, 2011

Revit Tip, Ceiling Displays Messed up by Tall Furniture

Have you ever had an issue where your ceilings do not display correctly when you have elements that you need to show in your ceiling plans that are taller than your cut-plane? This is a common issue worth discussing, so here's one of many ways to get your displays fixed...

Issue: Tall cabinets that will obstruct lighting design cause unwanted breaks in the ceiling patterns. You do not want to raise the cut plane because it makes your door openings display incorrectly.

In this case, the ceiling is placed at 9'-6", the furniture causing the display issue is 8'-0" tall and the RCP view cut plane needs to be set at 7'-6". The image below shows how the grid pattern is broken incorrectly by the tall furniture element:


Solution: Use a series of "Plan Regions" and set their View Range to the necessary height so that the ceiling above these items displays correctly. The image below shows the correct plan display for the ceiling pattern:


This issue was resolved by placing a Plan Region over the tall furniture item and setting the cut plane to 8'-0"


Draw the region around the necessary area and set the cut plane's height to the height that you require.

Wednesday, April 27, 2011

Revit 2011 Worksharing User Name

Do you have a bunch of public workstations that your users use to access workshared Revit 2011 models? Have you ever noticed that the name that displays in the worksharing monitor does not match the actual user's name?... Well this is an issue that has been resolved in Revit 2012 but is till annoying in Revit 2011.


So if you're still wondering how to change this name (sigh), you can adjust it to read anything you like... just be careful that you do not have two names in any two machines that are the same and have the same model loaded at the same time (this really jacks up how Revit 2011 worksharing works and will cause some dumb stuff...)



So if you have a bunch (or just one) public walk-up or training machines that people use to access workshared Revit 2011 models, enter a name in the user name field that is descriptive as to the machine's use or location:

  • San Francisco Giants 2010 World Series Champion Test Machine #1
  • Training #1
  • 197th Floor Spaceship Walk-up
  • Etc.

Wednesday, March 9, 2011

Winning Visual Studio Stretchy Form Design 101

I get this question a bunch: "How Don, how do you build those awesome winning forms all the time that stretch all sweet like?"... The answer is simple and I'll share how it's done right here in this very post!

First off, if you're using the form resize events to calculate the widths and heights of your controls based on the size of the form, you're on the wrong path... there's a far easier way to do it.

If you want to follow along, create a new form and layout some controls like the one shown here in this tricky example (datagrid on the left, grouped listbox in upper right, two buttons on the lower right):




Here is how it looks as it stretches (in design view too!!!).... notice how the controls morph in a logical way? It's magic... and logic (I know, I get the two confused sometimes too...)



Here's how I got it to do this... the trick is in each control's anchor settings!... Select a control and click on the Anchor properties. You can set any combination of four directions for anchoring for a single control.



Setting the anchoring of opposite directions will result in the control stretching as the form is stretched in that same direction. Setting all four directions will result in the control stretching in all directions as the form is stretched in both directions from the corner.

Setting the anchor to upper and right will simply justify the control in the form in that direction as the form is stretched in any direction...

When working with groups, the controls inside the groups are anchored within the group boundary only. So if you want a group to stretch, you must set the anchor settings for the group... you should then set the anchoring for the control within the group boundary separately.

See you guys at RTC 2011!!

Wednesday, March 2, 2011

Thou Shall Read Thy Dialog Box!!

This may appear to be a ridiculous post to most... but you would be amazed as to how many people call me to fix something with their model when they get a popup dialog that they have not seen before. They could solve their own problems 99% of the time if they would just simply READ the dialog box.

It really gets me though when people never read any warnings or dialogs at all and just close them no matter what. These are the people that tend to destroy stuff and don't even know it!

So please... if you're new to Revit or have been doing this stuff for 20 years... please... PLEASE read the dialogs and warning popups all the time!


...or the code ninjas will get you!!! I'm planning to start placing random jokes in my dialogs to urge people to want to start reading dialog boxes... I wish Autodesk could do the same

Tuesday, December 7, 2010

Human Readable Double Values for Parameters in the Revit API

This is a follow up or addition if you like to a previous post entitled A Classy Way to Handle Revit Parameters where I demonstrate a simple class for working with parameter objects in the Revit API.

This particular example is interesting in that we actually have a carnivorous way to get and set double formatted data by decimal as well as a more generic and simple way as string. It is obviously more difficult to calculate or aggregate values from a string representation value such as 6'-4" compared to 76.00 but sometimes the string representation is exactly what you need.

The sample code below demonstrates ho a variable initiated as a DB.Parameter is used to get and set the value from or to a string. The get will retrieve a value of 7'-0" or similarly you can set a value by entering 7'-0"...

Add the following snippet to the clsPara class to access the string values of a double formatted parameter:


''' <summary>
    ''' This property will return the string structured value for a double rather than a decimal
    ''' </summary>
    ''' <value></value>
    ''' <returns>A String</returns>
    ''' <remarks></remarks>
    Public Property DoubleValueAsString As String
        Get
            If m_parameter.StorageType = DB.StorageType.Double Then
                Try
                    ' Returns the human readable string representation of a double
                    Return m_parameter.AsValueString
                Catch ex As Exception
                    Return ""
                End Try
            Else
                Return ""
            End If
        End Get
        Set(ByVal value As String)
            If m_parameter.StorageType = DB.StorageType.Double Then
                Try
                    ' Sets the human readable string representation of a double (7'-0" or 150mm)
                    m_parameter.SetValueString(value)
                Catch
                End Try
            End If
        End Set
    End Property

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.


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.


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

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.


' 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.

Saturday, November 6, 2010

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.


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