Thursday, December 10, 2009

Revit API: More on the KeyboardShortcuts in Subscription pack

In the new Revit 2010 Subscription Advantage Pack, as previously mentioned, there is a new menu for setting up keyboard shortcuts.

Our office is rolling out this pack and have been fiddling with this menu to try and get our standard setup working on the new system. There are a number of things that have popped up that I thought were worth mentioning.

First is that you can now create a keyboard shortcut to a Custom Add-Ins Ribbon menu! Previously in the old text file you could not do this, so you had to have a keyboard shortcut to an external command in the External Tools menu.

However, on the flipside, now it seems that creating shortcuts to the commands in the External Tools menu is not going to work very well if you are sharing your configuration with others. By that I mean, if you setup a standard keyboard shortcuts file, and send it out across your office for others to import (see my previous post on this) then creating shortcuts to external tools will not work very well.

The reason being is I believe the new system records your shortcut as being “Press this key, to go to the 3rd menu item down in the External Tools drop down on the Add-Ins Tab” whereas previously the text file said “Press this key, to go to the menu item with the name COMMAND_NAME in the external tools drop down on the add-ins tab”

The difference to note is that it appears to rely on the ordering of items in the menu. This is fine for all other menus in Revit but not the external tools menu, as each user may have installed different tools at different times and thus have different listing of tools in that menu.

The workaround for this for developers, is that you have to create a ribbon menu for your tools and keyboard shortcut to that – as you are then in control of the ordering.

This is a pretty isolated situation, but if you are like me – creating API add-ins that all Revit users will install, and having a standard keyboard shortcut for these tools, it’s an important issue.

Thursday, December 3, 2009

Autodesk University 2009

I’m currently in Las Vegas, for the Autodesk University 2009 conference.

It’s a great event, I thoroughly recommend it to anyone interested in Autodesk products.

If you aren’t here – check out Autodesk University Virtual, which gives you access to certain online only classes (including a good one by Jeremy Tammik) and I believe recordings of classes here in Vegas.

Some good ones to check our include CP204-3 Deep Dive on the Autodesk® Revit API: Advanced Topics by Matt Mason and Expanding BIM With the Autodesk® Revit® API by Anthony Hauck

Still one day of classes to go, but my main focus for the day will be my presentation, which is the last of the conference, I’m presenting “How the Autodesk Revit API has saved our company time and money – and how it can do the same for yours” tomorrow at 5pm.

I’ll be joined by Andrew Bryant, the chief structural drafter at Bornhorst + Ward, where I work. We’ll be demonstrating a number of the API tools I’ve developed for Bornhorst + Ward. The second half of my presentation will be showing where YOU can go to find the best resources to learn the API and how you can use those resources to find the information you need.

If you are attending the class, come say hi after (or at the AU party)!

Wednesday, November 18, 2009

Revit Subscription Advantage Pack – Pushing the new keyboard shortcuts out to your office

The new Subscription Advantage Pack for Revit brings a new Keyboard Shortcuts dialog inside of Revit, for easier, on the fly editing of keyboard shortcuts.

The keyboardshortcuts.txt file is gone now from the Revit directory, the data is now stored in an XML format.

Our office has an installation tool for our API add ons, and part of this tool used to copy a keyboardshortcuts.txt file from a central location, onto the users Revit installation. This is obviously no longer useful, so how do we make sure our office are using standard keyboard shortcuts?

The answer is, there is now a KeyboardShortcuts.xml file stored in C:\Users\USERNAME\AppData\Local\Autodesk\Revit\Autodesk Revit Structure 2010\

of course this is different depending on the revit version you have, but our office uses revit structure exclusively so that wasn’t an issue for me. I believe this may point do the documents and settings folder for XP instead of C:\Users\ which is the Vista/Win7 replacement.

To get this location in C# I used:

   1:                  String currentKeyboard = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
   2:                  currentKeyboard += @"\Autodesk\Revit\Autodesk Revit Structure " + _revitYear + @"\KeyboardShortcuts.xml";

On line 1, I got the location to the C:\Users\USERNAME\AppData\Local\ folder

then on the second line I added the Revit specific path, _revitYear is a variable that I have populated from a config file to allow easy updating when our office upgrades each year.

You could improve on this code by checking for other Revit versions, or perhaps using the registry to gather which version was installed, but for our office this simple implementation worked fine – hopefully it gives you a base to start from!

Monday, October 12, 2009

New Visual Studio Theme

I use Visual Studio 2008 Professional in the office, and have recently discovered Scott Hanselman’s blog post on Visual Studio themes.

I’m finding Brad Wilsons Dark Visual Studio theme very easy on my eyes.

If you’re still using the default visual studio theme, check out Scott’s post for some other alternatives, I’m finding it a lot easier on my eyes staring at a black screen all day (and night…) instead of a white one.

Monday, September 28, 2009

Programming for beginners

I’ve seem quite a few instances now of people who are Revit Users that would like to be Revit Programmers as well. I came to Revit development from the other way – I have a background in I.T. and was taught Revit on a need to know basis (this is how you do it in Revit, now go code it, nerd boy!).

If you are someone daunted by programming in general, or perhaps you are someone who did a bit of Autocad customization and doesn’t know much about .NET, a good place to start might be at the MSDN Beginner Developer Learning Centre.

I always recommend that before you try to learn how to program in Revit, you try to understand C#/VB.Net, the .NET framework and software development in general. This site can help you do that, It has a few different tracks (Windows Track is probably best bet for Revit) that you can work through.

Let me know if it helped you out, or if you have any better resources!

Monday, September 7, 2009

Install Certificate button not visible on IE8

A non-programming related blog post for a change. A problem I ran into today in IE8 is that when you manually need to install a certificate (which we need to do for our remote login page) the normal install certificate button was not visible.

A Google brought up this bug report, which suggests you need to run the browser as an administrator for that button to be visible.

Once you right click on IE and run it as an administrator you are then able to install the certificate as per usual!

Thursday, July 23, 2009

Revit API Wish List Survey

Autodesk currently have a survey up that allows Revit API developers to give some feedback on what they would like to see in the API of future Revit releases.

It closes on the 31st of July and is available here: http://www.zoomerang.com/Survey/?p=WEB229BU6PH7J9 

Make sure you head over there and give your feedback. You have no excuse to complain about missing features if you don’t!

Some specific things that I’ve submitted to ADN as a wish list in the past have been:

  • Ability to work with filters (view filters, not the document element filters)
  • Ability to pick a point in the document
  • Ability to change the active view
  • More of the ‘override graphics in view’ menu actions exposed, ie setting elements to be transparent or half tone.
  • Ability to ‘duplicate as dependant’
  • Section mark creation

Now is your chance to tell yours to Autodesk, wether you are in ADN or not!

Wednesday, July 8, 2009

Revit API Search Engine

Hi all,
I had an idea today whilst doing some research for an API program I'm attempting to create.  My normal procedure for this after exhausting my usual resources (SDK, RvtMgdDbg etc), is to search a few of the Revit API blogs out there, then AUGI, Autodesk.com forums etc.

I've found this 'Google custom search' feature that Google has now - you can setup your own search engine to only search certain sites. So I decided to create own with Revit API resources.

http://www.google.com/coop/cse?cx=003379886482190238526:wi7yjrtrkd8 is the full link. I’ve created a slightly easier redirect page at http://RevitAPISearch.RodH.org/

The blogs I’ve got there at the moment are:
http://redbolts.com/blog/
http://revit-programmer.blogspot.com/
http://thebuildingcoder.typepad.com/blog/
http://cadappdev.blogspot.com/
http://roddotnet.blogspot.com

I've added AUGI and Autodesk.com forums in there now, but I'm having trouble restricting the results to just Revit API sections..

http://discussion.autodesk.com/forum...pa?forumID=160
http://forums.augi.com/forumdisplay.php?f=218 are the two links I’ve inserted, and I can choose one of these options:
Include all pages this page links to
Include all partial sites this page links to
Include all sites this page links to

I've experimented with the first 2, and found they still seem to show up results from other forum sections, so I'll have to keep working on that.
My goal here is to try and narrow the results down to the API as much as possible - ie not find info about what buttons to click to insert columns in Revit when you are trying to do it programmatically.

If anyone would like to suggest sites to index please let me know! I’ve started a discussion about AUGI HERE.

Tuesday, July 7, 2009

How to use an app.config file in a DLL plugin (External Command)

This post relates to wider .Net app.config files and linked DLL’s, but more specifically, my instance was relating to the Revit API.

For those that don’t know, an app.config file is a nice, easy way of doing configuration for your applications in .net. You can use the System.Configuration namespace to quickly access an XML config file without needing to do any manual XML reading. Unfortunately, you can only have one app.config file per executable, so if you have DLL’s linked into your application, they cannot have their own app.config files.

Seeing as the Revit API is done by external .Net DLL files which are opened within the Revit environment, this applies to them as well.

At Bornhorst + Ward, we have all of our external commands on a central network share, and each staff members ini is edited (using a tool I’ve written) to point to these external commands. I’d previously tried to use app.config files, and found they weren’t working, it seems they weren’t looking for the correct file in that network directory.

The way around it for me, was to manually locate the app.config file in my code.

   1: /// <summary>
   2: /// Get the configuration for the supplied type
   3: /// </summary>
   4: /// <param name="type">type of class</param>
   5: /// <returns>a configuration</returns>
   6: public static System.Configuration.Configuration GetConfig(Type type)
   7: {
   8:     //workout app.config lokcation
   9:     string dllLocation = type.Assembly.Location + ".config";
  10:  
  11:     if (dllLocation == null)
  12:         throw new Exception("Could not find config file, add .config in DLL location");
  13:  
  14:     //create config
  15:     ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
  16:     fileMap.ExeConfigFilename = dllLocation;
  17:     System.Configuration.Configuration config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
  18:  
  19:     return config;
  20: }

Seeing as app.config files on DLL’s are named dllName.dll.config this gave me an easy rule for finding the config file. I then used an ExeConfigurationFileMap pointed to that location to generate the Configuration. The ‘type’ parameter, is for me to supply a type (using typeof(ClassName)) to identify the correct dll – as this method for me was written in a separate helper dll which contains some commonly used functions for all of my tools.

Then, to access the properties in that file:

   1: /// <summary>
   2: /// Gets a specific config property
   3: /// </summary>
   4: /// <param name="key">the property to get</param>
   5: /// <param name="type">type of class asking - to get right assembly</param>
   6: /// <returns>value</returns>
   7: public static string GetConfigProperty(string key, Type type)
   8: {
   9:     System.Configuration.Configuration config = GetConfig(type);
  10:     return config.AppSettings.Settings[key].Value;
  11: }

I call that method, supply the typeof(ClassName) of the class calling it, and it gets the configuration from my previous method, and then uses an access method similar to the standard AppSettings class.

Now I can have .configs for all of my revit external commands and access them easily!

Monday, April 27, 2009

Revit: 2010 API Developer Guide

I stumbled across this document today whilst setting up my SDK Samples menus in Revit.

It’s located in the Revit 2010 SDK folder (there’s an extractable on the Revit disc to get this folder) and spotted the ‘Revit 2010 API Developer Guide’.

It’s a 315 page PDF with a whole heap of tutorials, code samples and tips for using the Revit API. It’s pretty much the user manual and seems to be exactly where a new Revit API user should start. This document is exactly what I dreamed of when I started developing with the Revit API a couple of years ago!

The section headings include:

  • Getting Started
  • Add-in Integration
  • Application and Document
  • Elements Essentials
  • Parameters
  • Collections
  • Editing Elements
  • Walls, Floors, Roofs and Openings
  • Family Instances
  • Family Creation
  • Datum and Information Elements
  • Annotation Elements
  • Sketching
  • Views
  • Material
  • Geometry
  • Place and Locations
  • Shared Parameters
  • Transactions
  • Events
  • Revit Architecture
  • Revit Structure
  • Revit MEP

If there isn’t anything there that interests you, you obviously aren’t interested in the Revit API. Props to Autodesk for putting this together!

Revit 2010: Parameter.Set – Unexpected Behaviour – Fixed in 2010

I previously wrote a blog post about unexpected behaviour from the Parameter.Set method in the Revit API.

What was happening was if you called Parameter.Set and set a value that was the same as the previous value (ie unchanged) it would return false. This caused problems with detecting when the operation failed (it didn’t fail, it did what we asked).

A note in the Revit Platform API Changes and Additions document confirms that this has been fixed in Revit 2010, and the more logical functionality has been introduced:

Parameter.Set return value when value is unchanged

Previously, Revit returned False if the input value for Parameter.Set was the same as the current value. Revit now returns True in this case.”

Wednesday, April 22, 2009

ASP.Net: Error executing child request for ChartImg.axd

Sorry to all Revit API readers, this one isn’t really relevant to you.

I’ve been working on an ASP.Net project, making use of the awesome free charting tools from Microsoft. I made a form that posts back and generates a column graph based on the inputs and some database calls. A problem I kept running into was an error message that says:
”Error executing child request for ChartImg.axd”

After looking around on the net and reading through some forum posts, I discovered to fix this you just need to make a small change to your web.config.

The problem arises as I was using postbacks to generate my chart, you must add support for this in your httpHandlers section of the web.config by changing:

   1: <add path="ChartImg.axd" verb="GET,HEAD" type="System.Web.UI.DataVisualization.Charting.ChartHttpHandler, System.Web.DataVisualization, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="false"/>

To:

   1: <add path="ChartImg.axd" verb="GET,HEAD,POST" type="System.Web.UI.DataVisualization.Charting.ChartHttpHandler, System.Web.DataVisualization, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="false"/>

The only change between the two is in the “verb=” property I added “,POST” to the end.

After this all should work fine.

Wednesday, April 8, 2009

How to create keyboard shortcuts to External Commands in Revit 2010

Seeing we now have the fancy ribbon interface in Revit 2010, the keyboard shortcuts files you have been using are obsolete. There is instructions in the file for how to setup normal shortcuts, however I ran into a problem when trying to point the shortcuts to my external commands.

An example of an line in the keyboard shortcut file is:

"VG"    ribbon:"View-Graphics-Visibility and Appearance"

As you can see, the ribbon item you want to shortcut to is pathed out using - as a separator. This works fine, but what happens when you want to use the “Add-Ins” tab?? (note the –)

The answer is, you use ‘Add_Ins’ instead. See an example here:

"HLWD"   ribbon:"Add_Ins-External Tools-External Tools-HelloWorld"

Also note the two external tools sections, these are because there is an external tools menu on the external tools panel.

Another thing to note is that unfortunately, the problem from Revit 2009 still remains, to create a keyboard shortcut to an API program, it must be an external command in the External Tools menu. You can’t create a keyboard shortcut to your own ribbon panels/menus/buttons. So even if you have created a nice looking ribbon panel for your program, you’re going to have to make an external command (and do the ini editing to register it). If anyone knows a workaround for this, please let me know, but I’d say it’s due to the order in which Revit loads things.

Problems activating Revit 2010 – Can’t find internet connection

Our office ran into this problem all through the beta, unfortunately looks like the issue is still there in the final release.

The issue is when you try to activate, a dialog tells you there is no internet connection available. I believe this is to do with firewall settings, port 443 and proxies. However after trying to get through our ISA firewall (which is set to allow 443) it doesn’t seem to work.

Seems a little strange given all other Autodesk products have activated perfectly for years, so I’m not too keen on opening ports to try and get it to work.

Not to worry though, there is a workaround. Firstly, get as far as you can go on the activation before it tells you it’s failed. Then go and get a coffee. Come back a couple of minutes later (should only take 20-30 seconds really) and your screen should now be telling you that it’s timed out, and will offer you a link to ‘retry’. For some reason, this link must point to a different method of activation, and works fine, just like Revit 2009 did.

Alternatively if you are a subscription customer, you could try getting the activation code yourself from the register.autodesk.com site.

Hope this helps someone who is pulling their hair out trying to activate Revit!

Tuesday, April 7, 2009

Monday, March 23, 2009

Revit: How to print sheets in order.

I’ve had a bit of fun lately working with the Revit 2009/2010 API for printing views. There is a useful SDK sample, ‘ViewPrinter’ which shows you how to replicate the print menu in revit, but using the API.

I’ve created a customized version of this that links in with our companies document management systems, and does things like prints, renames, and copies PDFs to the correct directory all with the press of a button.

This has been working well for our drafters, and has sped things up, however there have been a few issues that I’ve run into whilst following the methods set out in ViewPrinter and in the SDK documentation. Most of them relate to selecting certain views (in this case, sheets) and printing them in the correct order, and with the correct amount of copies.

The way the SDK sample does this, is it gathers a list of the sheet names the user selected, compares their names with those in the PrintMan.ViewSheetSetting.AvailableViews list and selects ones that match. It then adds these into a ViewSet, and supplies that to PrintMan and calls SubmitPrint().

   1: //create Viewset store those you need to print
   2: ViewSet viewsToPrint = new ViewSet();
   3:  
   4: //Compare your list of sheets, to those in AvailableViews
   5: foreach (string name in selectedSheetNames) 
   6: {
   7:     foreach (View view in _printMan.ViewSheetSetting.AvailableViews)
   8:      {
   9:         if (view.ViewType == ViewType.DrawingSheet)
  10:         {
  11:             //cast to viewsheet
  12:             ViewSheet vs = view as ViewSheet;
  13:  
  14:             if (vs != null && name.Contains(vs.SheetNumber + " - " + vs.Name))
  15:             {
  16:                 viewsToPrint.Insert(vs);
  17:             }
  18:         }
  19:      }
  20: }
  21:  
  22: ViewSheetSet viewSheetSet = m_viewSheetSetting.CurrentViewSheetSet;
  23: viewSheetSet.Views = selectedViews;
  24: m_viewSheetSetting.Save();
  25:  
  26: //set copies
  27: _printMan.CopyNumber = numCopies;
  28:  
  29: //submit print
  30: _printMan.SubmitPrint(v); 
  31:  
  32:  

This works great ok normally, however there is a significant problem. The problem lies in how the views are stored. The views are placed into a ViewSet, which is an implementation of the Set collection type, ie, an unordered set of items. Unfortunately, this means that us coders have no say in how the prints get ordered.

My experimentation shows that revit seems to order them by ElementID, or, in the order they were created. So lets say you create Sheet 1, Sheet 2, Sheet 4, Sheet 3, in that order. That is exactly how they will come out of the printer, even though the user would assume otherwise.

My workaround for this, after much trial and error, is this:

   1: //create a list of view tp store those you need to print
   2: List<View> viewsToPrint = new List<View>();
   3:  
   4: //Compare your list of sheets, to those in AvailableViews
   5: foreach (string name in selectedSheetNames) 
   6: {
   7:     foreach (View view in _printMan.ViewSheetSetting.AvailableViews)
   8:      {
   9:         if (view.ViewType == ViewType.DrawingSheet)
  10:         {
  11:             //cast to viewsheet
  12:             ViewSheet vs = view as ViewSheet;
  13:  
  14:             if (vs != null && name.Contains(vs.SheetNumber + " - " + vs.Name))
  15:             {
  16:                 viewsToPrint.Add(vs);
  17:             }
  18:         }
  19:      }
  20: }
  21: //loop through copies 
  22: for (int i = 1; i <= numCopies; i++) 
  23: { 
  24:  //loop through each view 
  25:  foreach (View v in viewsToPrint) 
  26:  { 
  27:   //submit print of just 1 view 
  28:    _printMan.SubmitPrint(v); 
  29:   } 
  30: }

There are a number of steps behind the scenes (such as setting up _printMan aka my PrintManager to have the correct settings) but instead of supplying PrintManager with a ViewSet of views I want to print, and changing the CopyNumber to how many times I wish to print them, I’m printing one view at a time using the overload for SubmitPrint. This allows me to order my list of selectedSheetNames in the way I wish it to come out, including sorting and reversing it. I’ve also done a for loop to replicate the CopyNumber property.

Now, at long last, my prints are coming out in the correct order!

Note: This code was created for Revit 2010, not fully tested in 2009, though most of it should work the same.

Revit 2010 Kinks – BuiltInCategory.OST_DrawingSheets

In going through and converting my external tools, I stumbled across this problem. A few of my tools used a CategoryFilter on the category ‘BuiltInCategory.OST_DrawingSheets’, this was so I could get all of the sheets in the revit model. It appears this is not a category anymore.

A scroll through the categories revealed another category ‘BuiltInCategory.OST_Sheets’, that appears to achieve the same results.

I plan to continue posting any little changes like this that I’ve noticed in my Revit 2010 conversions.

Wednesday, March 11, 2009

Revit 2010 - More feedback on external commands errors

While Matt Mason has been blogging away furiously at the Revit 2010 platform/API enhancements, I've got a smaller feature to talk about.
If you're anything like me, you would have run into the situation where you create an external command, link it up in the ini file, and go to run it.. and get nothing, no error, no warnings, just nothing. While the journal file can sometimes offer a little bit of assistance, you really have very little to go on.
This has changed in 2010, with increased reporting of errors in API commands. One I noticed today is that if you link to a DLL file in the revit.ini that doesn't exist, you will get a popup warning alerting you that your dll doesn't exist and thus the command has been disabled. This is great, as often typos are made in the revit.ini, and this points you straight to it.
Another one is that when an unhandled exception occurs, a friendlier dialog box is now shown, alerting the user to the error, and allows them to view technical detail if they wish. Previously it was a standard .net dialog box which didn't mean much to the end user.
It's the little things that count, and this little thing is a worthy inclusion in Revit 2010!

Monday, February 23, 2009

Parameter.Set - Unexpected Behaviour

This is something I ran into today working on a Revit API External Command. The program I was trying to make, involves changing the 'Mark' parameter on beams/columns. I was using the Parameter.Set(string) boolean, which returns true if the parameter was set successfully to the new value, otherwise false. I decided to use the T/F value to determine if it had been successful or not, before incrementing a certain value. It turns out however, that the Set method only returns True if it has been set to a new value. So if you assign the same value that was already in the mark, it returns false! So my program was thinking that the method had failed, when really, it just had set the same value as was already there. So keep in mind that if you are going to use the T/F value of this method, make sure you also compare the value which you are setting, with the current value of the parameter.

Friday, February 20, 2009

Revit 2010

It seems the NDA has lifted on Revit 2010, and the blogosphere is starting to populate with information. I plan on doing a couple of blog posts on the subject, as some of the new API enhancements are great (Families!), but just have to find the time to write the posts.
In the mean time, Matt Mason is doing an epic series on the topic at his blog:
CAD Application Development Be sure to check it out, so far it's been very informative and well done, and he's got a lot more lined up!

Thursday, January 15, 2009

Document.LoadFamilySymbol method in Revit API doesn't work for all symbols

I ran into this problem recently on an External Command I was working on. My command listed all of the available families in a directory, and allowed checkboxes to choose which one they would like to open. Further to this I listed the individual symbols from each family, so you could load just one of those instead of the whole family. My initial testing showed that this worked fine, however after getting some others to use it for a few weeks some errors cropped up on certain families. The error was that if you loaded an individual symbol, it wouldn't work, however loading the whole family did. The Revit API does not throw an exception if the loading of a family symbol was unsuccessful, so the way to check if the loading was successful is to use the 'out FamilySymbol' paramater of the LoadFamilySymbol method. Using that, and comparing working text files with not working text files showed that the ones that weren't working, had spaces after the symbol name, but before the comma, whereas the ones that were working didn't. When you use the inbuild Revit load family window, it must automatically check for this and trim all the white space, however the API call function doesn't - you must do that in your code. So when you use the LoadFamilySymbol method, make sure the string that represents your symbol has been .Trim()'ed first. Either that or make sure the person managing your families doesn't add extra spaces!