Sunday, March 28, 2010

Revit API 2011: The New Way to Find Elements

(Part of our Revit API 2011 Series)
[Editor’s Note: Updated with some late-breaking additions that will only be documented in the released documentation]

For the uninitiated, much of the core work in a Revit application involves finding elements within the Revit database. Whether it’s finding exterior walls, 3D Views, or wall types – it’s always the same concept… Doing a lookup from the Revit to get a list of elements.

This is an area that “the factory” has improved upon release-after-release… From the early days, where you always had to cycle through everything – through the newest incarnation, today. I think I’m counting right that this is the 4th generation of the element iteration API. And no more ignoring what’s new – because you’re required to use the new method in 2011!

The 2011 Approach

The factory has really created something great here – something that is mature and answers almost anything you could want in an element iteration API. And they’ve really tried to do it in a way that matched the best and most modern approaches in .NET – such as LINQ.

The fundamental concept for iteration is the FilteredElementCollector class.

Getting Started

You construct the class in one of three ways:

// get ready to filter across an entire document
FilteredElementCollector coll =
     new FilteredElementCollector( myDoc );

or

// get ready to filter across just my pre-selected set of
// elements!
FilteredElementCollector coll =
     new FilteredElementCollector( myDoc, myElementCollection );

This is great when you’d rather not search your entire model when you’ve already got the subset you want…

or

// get ready to filter across just the elements visible in a view
FilteredElementCollector coll =
    new FilteredElementCollector( myDoc, viewId );

This is equivalent to the old mechanism of the View.Elements collection – which is now gone.

These constructors just get you started… Then it’s time to move on to the filtering.

Filtering Mechanisms with FilteredElementCollection

The factory has introduced three different categories of filtering in 2011:

  • Logical (operations like AND/OR)
  • Quick (operations that are FAST)
  • Slow (operations that take a bit longer)

While these kinds of things have probably conceptually always existed, but they were found out by experimentation rather than Autodesk documenting and sharing them up front…

  • Quick
    • ElementCategoryFilter / OfCategoryId()
    • ElementTypeFilter / OfType()
    • ElementIsElementTypeFilter /
          WhereElementIsElementType()
          WhereElementIsNotElementType()
    • ElementOwnerViewFilter / OwnedByView(), WhereElementIsViewIndependent()
    • ElementDesignOptionFilter / ContainedInDesignOption()
    • ElementIsCurveDriven / WhereElementIsCurveDriven()
    • ElementStructuralTypeFilter
    • BoundingBoxContainsPointFilter
    • BoundingBoxIntersectsFilter
    • BoundingBoxIsInsideFilter
    • ExclusionFilter
    • FamilySymbolFilter
  • Slow
    • ElementParameterFilter
    • ElementLevelFilter
    • FamilyInstanceFilter
    • FamilyStructuralMaterialTypeFilter
    • PrimaryDesignOptionMemberFilter
    • StructuralInstanceUsageFilter
    • StructuralMaterialTypeFilter
    • StructuralWallUsageFilter
    • CurveElementFilter
    • RoomFilter
    • SpaceFilter
    • AreaFilter
    • RoomTagFilter
    • SpaceTagFilter
    • AreaTagFilter

These are documented further in the API help file in its own introductory section called “Element Iteration API”.

I’ll give some of the typical situations here:

If you know the type:

// we want walls
coll.OfClass( typeof(Wall) );

or if you know the category:

// we want Curtain Wall Panels:
coll.OfCategoryId( BuiltInCategory.OST_CurtainWallPanels );

Now here’s where it starts to get interesting… If you want to put different filters together, it can look something like this:

// We want door instances
coll.OfCategoryId( BuiltInCategory.OST_Doors ).OfClass( typeof(FamilyInstance));

What’s going on here? each filter ADDs requirements to the collector. And to make the whole thing more friendly towards combining, the methods return a pointer to their object, so that you can “chain” them together. For example, the code above would be equivalent to:

// we want door instances
coll.OfCategoryId( BuiltInCategory.OST_Doors);
coll.OfClass( typeof(FamilyInstance) );

We are updating our collector two times with the filter requirements.

The ElementType Topic

The ElementType / NotElementType can be a little confusing at first… There are two filters, the short-hand versions are:

  • WhereElementIsElementType()
  • WhereElementIsNotElementType()

What is ElementType? This is the renamed Symbol class in the API (re-named to match better what interactive users call things). So an “ElementType” refers to a symbol/type/definition kind of thing (a “block definition” for you AutoCAD-types). Something which is “Not an ElementType”, on the other hand – is typically something which is physically IN the model – like a specific door, line, or wall. Technically it’s a bit more broad – because it also includes items like views, etc.

That said – these two can be key filters to use to distinguish between whether you want Doors vs. Door Types, for example.

What’s the Deal with Rooms/Areas/Spaces/Tags?

Here’s a place where Autodesk’s new strategy of matching up more closely with the internal API will cause you a little bit of hassle. With Rooms/Areas/Spaces and their tags (as well as about 9 other types – see the API Introduction for the list) – there is no internal Revit type which matches them.

For example, if you look at the Room class in the 2011 API, you’ll see that it is actually a descendant of the Enclosure Class. Enclosure covers Rooms, Spaces, and Areas… Here’s the trick – Revit’s internals are obviously modeled on the “Enclosure” class – so if you’re querying by type – you can’t query on
typeof( Room ), for example.

There are some specially designed filters to compensate for this – like RoomFilter, AreaFilter, SpaceFilter, etc… These would be called as follows:

coll.WherePasses( new RoomFilter() );

The WherePasses method is another mechanism for specifying filters – you can use any filter with it.

Final Requirements of the Filter

Ok, ok – we’re almost to the payoff… But one thing I should note before we go on… If you’re used to being able to just query the whole model (for whatever reason) – you’ll find that a little bit tricky with this mechanism… Why? Because the rule is that after you construct the collector – you MUST apply at least one filter before you attempt to retrieve from it. You can’t (easily) just retrieve everything.

The closest I’ve come to it is:

// get EVERYTHING – like in the bad-old-days…
// get all the ElementTypes + all the non-ElementTypes
coll.WhereElementIsElementType().UnionWith( new
         ElementIsElementTypeFilter( false ) );


Finally – Retrieving from the Filter

Sorry to make you go through all this to get to the good part! Once you have constructed your collector and applied filter(s), then it’s time to request the contents of the collector and see what you get. Autodesk has really done a nice job of implementing some .NET 3.5 goodies here, so there are a variety of options.

coll.ToElements(); Return an IList<Element> of the contents.
coll.ToElementIds(); Return an ICollection<ElementId> of the contents.
coll.FirstElement() Return the first Element found that matches.

But that’s only the first part – the other thing I love is that the .NET 3.5 tricks that get around another annoyance – that these query routines return pointers to “Element” – which you immediately have to convert/cast down into, say “Room” to be able to easily access the properties and methods of that class.

// get all the wall types as wall type objects:
coll.OfClass (typeof(WallType));
IEnumerable<WallType> types = coll.Cast<WallType>();

foreach (WallType wt in types )
{
    // do something with the wall type
}

 

Using with LINQ

Because the FilteredElementCollector supports the IEnumerable interface – it easily  can make the jump to LINQ – being able to write full-fledged queries directly in code.

This looks something like:

FilteredElementCollector coll = new FilteredElementCollector(doc);
coll.OfClass(typeof(WallType));

var bigEnoughWallTypes =
from element in coll
where element.get_Parameter(BuiltInParameter.WALL_ATTR_WIDTH_PARAM).AsDouble() > 0.5 &&
   element.get_Parameter(BuiltInParameter.FUNCTION_PARAM).AsInteger() == 1
                         select element;

IEnumerable<WallType> types = bigEnoughWallTypes.Cast<WallType>();

ok, so the thin screen doesn’t lend itself to this… In any case – it’s not magic, it’s nothing you couldn’t have done before – but it DOES make your code a bit tighter and arguably easier to maintain because it’s clear what you’re doing (as opposed to doing the same thing in a query then loops with if statements).

The Final Analysis

In the final analysis – the new FilteredElementCollector is a fantastic new way of accessing data within Revit. It does take a little bit of adjustment, but once you’re there, I’d say it’s nicer than what existed before – and it has nice room to grow.

I still need to run the new things through a performance test (my impression is that they run faster than their 2010 equivalents – but I haven’t put a stopwatch to it yet). This post is already too long – so I’ll save that for another post…

Friday, March 26, 2010

Revit API 2011: Upgrading Existing Add-Ins

(Part of our Revit API 2011 Series)
If there is a dark side to all of the positive changes in the 2011 API – it is that the amount of re-work required for existing add-ins is FAR more than previous upgrades. I’m tired just writing this post…

While previous upgrades have been fairly painless, in 2011 you’re up against:

  • Massive namespace renaming/restructuring.
  • Deprecation and replacement of many of the fundamental element search and iteration APIs.
  • Fundamentally new transaction and regeneration mechanisms
  • Non-trivial changes to the fundamental XYZ, UV and ElementId class
  • Changes to the Element.ObjectType structure.
  • Replacement of the Analytical Model classes
  • New Event Model
  • New Selection Mechanisms
  • Ribbon API changes
  • Print API changes
  • Re-work of the gbXML class
  • Installer changes (if you want to take advantage of new capabilities)

Massive Namespace Restructuring

The factory has taken this opportunity to completely re-work the namespace hierarchy into something which more closely matches Revit’s internals – as well as to clean house, straighten up, and simplify some things.

While I would argues that this is probably a good thing in the long term, it will require a bit of work to recompile your code.

While I won’t cover the namespaces in detail here, to give you an idea of what you’re looking at:

  • Autodesk
    • Autodesk.Revit
          • Autodesk.Revit.UI (where all the User Interface and command/application integration classes landed)
          • Autodesk.Revit.DB   (this is the container for most core elements, geometry, parameters, and other concepts)
              • Autodesk.Revit.DB.Architecture ( contains architecture-specific elements like Rooms, RoomTags, Gutter, Fascia, etc)
              • Autodesk.Revit.DB.Electrical (contains electrical-related elements and concepts, from CableTray to DemandFactor)
              • Autodesk.Revit.DB.Events (contains the event arguments for all the different kinds of events)
              • Autodesk.Revit.DB.Mechanical (Spaces, Zones, SpaceTags, Ductwork, etc)
              • Autodesk.Revit.DB.Plumbing ( Piping, PipingSystems, etc)
              • Autodesk.Revit.DB.Structure ( Analytical Model, Loads, Rebar, Trusses, etc)

Other key re-naming issues:

  • the Symbol class has been re-named to “ElementType”
  • the old Geometry.Element class has been renamed to GeometryElement
  • the old Geometry.Instance class has been renamed to GeometryInstance
  • These are further described in the “What’s New” section of the API Help File

Autodesk is also providing in the SDK a spreadsheet of all of the class renames, and their corresponding new names. It is a long list :).

Where Did My ElementIterator Go?

Autodesk has taken somewhat of an unusual step in 2011 – that of ripping and replacing all of the three different element search and iteration schemes from before 2011 and replacing them with the new FilteredElementCollector. The Document.Elements collection, the Document.get_Elements( type ) and the filter mechanism have all been removed.

See our separate post on the new mechanism (which is quite superior) – but it may take a minute or two to re-work any of your code which iterates through elements in the document (which almost every command does at least once).

Also note – the View.Elements collection has also been re-worked to the new scheme.

The New Transaction Mechanisms

There are fundamentally new transaction mechanisms that you will likely need to deal with (unless your application was very straightforward). Commands are now attributed with one of two Transaction modes:

  • Automatic – like what has existed historically.
  • Manual – the developer must control their own transactions explicitly.

For upgrading an existing application, you’ll probably want to stay with Automatic because it most closely matches the prior release behavior. However, if you had been using transactions within your code in the past (i.e. Document.BeginTransaction) you must replace these with the new “SubTransaction” classes.

//New SubTransaction approach

SubTransaction subTr = new SubTransaction( myDoc );
try
{
    subTr.Start();
   // do something
    subTr.Commit()
}
catch (Exception ex)
{
    TaskDialog.Show(“Error”, “An unexpected error was encountered: “ + ex.GetType().Name + “: “ + ex.Message);
    if (subTr.HasStarted()) subTr.Rollback();
}

Developer TechTip:
If you go the manual transaction approach, don’t forget to name your transaction. This name shows up in the “Undo” box, but because there is a constructor which does not require a name, it’s easy to forget. And Revit throws a nasty exception at you if you forget to name it.

The New Regeneration Mechanism

All commands in Revit are now attributed with another attribute: RegenerationMode:

  • Automatic – same way Revit has worked traditionally – after every action in Revit, the model is regenerated (unless you’re using SuspendUpdate). Solid, but slow on occasion. Also – Autodesk has indicated that this mode is going away in the future.
  • Manual – you are in complete control of your own regeneration (powerful and fast but occasionally painful).

With manual regeneration, you issue a Document.Regenerate any time that you want the project to regenerate. Seems easy enough, right? Well… First you have to understand when you NEED to regenerate. There are a variety of cases, particularly when you are creating or modifying geometry, that the changes will not be propagated until you do the regenerate. For example, if you create a line, you are unable to query for the reference to that line until the document has been regenerated.

Why it can be challenging: If you’ve got library code that you re-use in multiple commands. Are you currently in Manual Regeneration mode or not? it depends on how you entered the current command. If you call Document.Regenerate and you’re already in Automatic mode, Revit will throw an exception (seems like a harmless problem – factory guys, chill out!). To further complicate things, if your code is being called as part of an event callback, I believe that it is ALWAYS going to be in Automatic Transaction mode (even if the whole thing is in the context of a manual transaction command). So there’s some potential trickiness to deal with.

XYZ, UV and ElementId - All Change to be Unchangeable!

OK – this is just cruel… I’d swear that this is the third change to the XYZ class in three releases! And it’s worse than previous issues. In 2011, you can no longer do the following code:

myPoint.X = 10;

What?? why not? Well, Autodesk has made the XYZ, UV, and ElementId classes immutable – they cannot be changed once they are created. There’s a reasonable reason behind this from a framework design perspective – because it implies that you could do something that you really couldn’t. For example, if you did:

myWall.Location.Point.X = myWall.Location.Point.X + 1;

What would this do? You would think that it might move the wall 1 foot in the X direction. In fact, it does not. The Point here was a COPY of the actual data – so changing the X value did nothing.

To do what you wanted to do above, you had to:

XYZ newPt = new XYZ( myWall.Location.Point.X + 1,
                               myWall.Location.Point.Y, 
                               myWall.Location.Point.Z);
myWall.Location.Point = newPt;

In the case of the new immutable XYZ class, the only way to modify an XYZ, or UV, or ElementId is to construct a new version. So to modify an XYZ point, you must:

myPoint = new XYZ( myPoint.X +1, myPoint.Y, myPoint.Z);

If you did much with XYZ coordinates in the past, this likely means a bunch of grumbling, painful code re-writing and re-testing.

Oh – and ElementId? they changed the name of the actual Id property to “IntegerValue”. They’re not as bad as the Autodesk Vault team with the seemingly meaningless renames, but I definitely have had cause to grumble here.

Changes to the Element.ObjectType mechanism

Prior to 2011, if you wanted to interrogate the type of a given element, you navigated via the Element.ObjectType mechanism and voila, you were at the type element.

In 2011, this mechanism has been deprecated. In its place, you actually have to call a couple of methods to do the same thing:

Element.GetTypeId()   - which returns an ElementId, not an element. You’ll still have to call Document.get_Element() to get the element object.

Correspondingly – whereas you could previously just modify the element type through the property, you now much do Element.ChangeTypeId().

Further, if you used to use “Element.SimilarObjectTypes” to browse the corresponding other types that could be swapped to – you’ll now have to call Element.GetValidTypes().

Replacement of the Analytical Model classes

I have to say I’m relatively unfamiliar with AnalyticalModels – but suffice it to say it’s all been ripped out and replaced with something better! Unfortunately, you’ll have to re-work any existing usages.

Deprecated Events

If you were lazy last time – and didn’t remove your 2009-era events like Application.OnDocumentSaved, OnDocumentSavedAs, OnDocumentOpened, OnDocumentClosed, OnDocumentNewed, OnDialogBox, Document.OnSaveAs, OnSave, OnClose…

Then you’ve got some work to do – because they’ve all been removed now. They’ve all been replaced with newer and better events, though.

New Selection Mechanisms

The existing selection mechanisms (PickOne/Window Select). Find out all about the new mechanisms here.

Ribbon API changes

The ribbon API has had some non-trivial changes… if you’ve done a ribbon panel, it will require updates. See more here.

Print API changes

The PrintSetup.CurrentPrintSetting has been changed to a new interface: IPrintSetting. This should make things better going forward, but again – it will make for a little bit of cleanup time.

Re-work of the gbXML class

If you were previously getting at the gbXMLelement class, there’s some work required to get at its replacement – the EnergyDataSettings class. While it does inherit from Element, it’s been my experience so far that it is not retrievable in the same ways as in the past – it is not a parameter within the ProjectInformation class. Also, it is not queryable in the same ways as before.

To retrieve it in 2011, you need to actually call a static methods:

EnergyDataSettings.GetFromDocument(myDoc)

Also note the other static method: EnergyDataSettings.IsDocumentUsingEnergyDataAnalyticalModel(myDoc) – which tells you if there is an analytical model as well.

 

Installer Changes

While only a minimal installer change is necessary for 2011 (if you still like the bad-old-way of looking through registry uninstall keys to find which versions of Revit are installed and where) – you should probably think about going further.

While the Revit.INI file approach still works – the AddIn file mechanism is better, and the redistributable AddInUtility.dll can really help make this an easier process.

Whew!

While there’s a lot in this document, don’t despair… Chances are your application doesn’t use ALL of these features – does it? There are a variety of common, painful ones – but it’s mostly just mindless grinding through errors.

Just go into it with the right expectations – it will take you at least 3-5x as long as it used to take you with previous upgrade projects! It will be worth it to get to Revit 2011!

Thursday, March 25, 2010

Revit 2011 API: Exceptional Stuff…

(Part of our Revit API 2011 Series)
Forgive the bad pun of a title…

One of the new capabilities in the Revit 2011 API that I haven’t covered yet is some re-working of the way that Revit throws exceptions when you do something it doesn’t like… Whereas in the past, you would have gotten something pretty generic (in terms of the type of exception thrown), in 2011 Autodesk has introduced a variety of very specific Revit exceptions which are thrown. All of these inherit from Autodesk.Revit.Exceptions.ApplicationException:

  • ApplicationException
    • ArgumentException
        • ArgumentNullException
        • ArgumentOutOfRangeException
        • ArgumentsInconsistentException
        • FileArgumentNotFoundException
        • InvalidPathArgumentException
    • InternalException
    • InvalidOperationException
        • AutoJoinFailedException
        • FamilyContextException
        • ForbiddenForDynamicUpdateException
        • InapplicableDataException
        • IncorrectProductException
        • InvalidLicenseException
        • InvalidObjectException
        • ModificationForbiddenException
        • ModificationOutsideTransactionException
        • ObjectAccessException
        • RegenerationFailedException
    • IOException
        • DirectoryNotFoundException
        • FileAccessException
        • FileNotFoundException
        • InvalidDataStreamException

So what, you say? An exception is an exception, you say? I disagree – historically it has been painful to try to figure out why something didn’t work in Revit – the exceptions and error messages were not always helpful. And if you wanted to trap specific exceptions, it was pretty weak.

I see this as a great investment on Autodesk’s part in making the Revit API “grow up” to a level of maturity that you can develop strong applications with it. Applications that are easier to control and to diagnose when something goes wrong.

And speaking of diagnosis, there’s one other hidden gem in all these exceptions: the FunctionId. A property on these exceptions which gives you:

  • The Revit source code file
  • The Revit source code function
  • The Revit source code line number

where this particular exception occurred. This strikes me as a great help when I’m sending something in to Autodesk Developer Network… Telling them EXACTLY where in their code something is going bad (and to help me figure out why).

All in all, I appreciate that they took some time to implement this in 2011.

Obscure Developer TechNote:

One thing that I had not been expecting… If you use the “Debug + Exceptions + Thrown Exceptions” in Visual Studio… When a Revit Exception is first thrown, it shows up as an “SEHException” which I believe means an unmanaged C++ exception that is bubbling up. That said, when it actually arrives – it is one of the new types shown above. So you actually have to let it bubble all the way up before you get the benefit of the knowledge of what it is.

Revit API 2011: Ooh Ooh! Pick Me!

(Part of our Revit API 2011 Series)
The Revit 2011 API adds some new ways to interact with elements in the project – through picking. These are all available through the UIDocument.Selection class:

  • PickObject (replaces PickOne – pick something in the active view – get back a reference)
  • PickObjects – pick multiple objects, click “Finish” when done.
  • PickElementsByRectangle – a replacement for “WindowSelect”
  • PickPoint – return an XYZ coordinate based on picking on the active workplane

What’s Even Better?

All of the above except for PickPoint support a number of options that go deeper than what we had in Revit 2010 and prior (where you could only support picking full elements):

  • Element (as before a whole element)
  • Face (a specific face of an element)
  • Edge (any model edge)
  • PointOnElement (any point on any face or curve)

Further, the methods mentioned above also support a new concept as well – a Selection Filter interface: ISelectionFilter. You can implement ISelectionFilter on any class – it will get callbacks from the pick method to help you control what is allowed to be selected or not:

  • a Pre-filter method at the element-level
  • a Post-filter method at the reference-level

This lets you easily limit your selections to, for example, “walls” or “exterior walls” or “an inside horizontal top edge of an exterior wall” – the mind boggles.

But Wait, There’s More!

While PickPoint() does not support the options described above – it DOES support a different set of options – Object Snaps!

  • Points - Snaps to site points.
  • Quadrants - Snaps to quadrant points. For arcs, jump snaps are enabled.
  • Tangents - Snaps tangent to an arc.
  • Perpendicular - Snaps to perpendicular elements or components.
  • Centers - Snaps to the center of an arc.
  • Intersections - Snaps to intersections.
  • WorkPlaneGrid - Snaps to a work plane grid.
  • Nearest - Snaps to the nearest element or component.
  • Midpoints - Snaps to the midpoint of an element or component.
  • Endpoints - Snaps to the endpoint of an element or component.

Conclusion

The Pick mechanism in Revit has gone from paltry to an embarrassment of riches… I’m not aware of a better Pick API in any CAD system. While there are still a few usability oddities, it’s a vast improvement over 2010.

Revit API 2011: User Interface Changes/Improvements

(Part of our Revit API 2011 Series)
The 2011 API has a variety of interesting enhancements in the ribbon user interface – making it possible to build applications which more closely match the look, feel and capability of native Revit commands (aside from being relegated to the Add-Ins tab).

In 2010, the first Ribbon release, the API already had access to controls such as:

  • RibbonPanel
  • Pushbutton
  • Stacked Pushbutton
  • Pulldown Button

What is new in 2011 are a wide variety of new controls and constructs in the ribbon:

  • Combo Box
  • SplitButton (like a Pulldown button, but it has a default action)
  • TextBox
  • SlideOut

I created the following sample ExternalApplication which illustrates the different controls now possible:

Figure 1
Figure 1

If the user has added a SlideOut to the RibbonPanel, any additional controls will be only available on the SlideOut panel – available when you click the down-arrow to the right of the Ribbon Panel name.

image
Figure 2

Note that the slide out is “pinnable” to keep it open. That, combined with the ability to “tear off” the panel (also available in 2010) – makes for some interesting capabilities.

Going Deeper

Beyond the new controls, there are some new capabilities a level deeper:

  • Images on Pulldown buttons
  • Tooltips and Long Descriptions – to provide more detail on how to run your command.
  • Tooltip Images – to provide a graphic for your command – a picture is worth a thousand words

image

General Availability

Another new feature in 2011 is the ability to have an interface (IExternalCommandAvailability) which implements a check for whether your command should be enabled or disabled.

This is useful if your command should only be available in a 3D View, or only if the user has filled out the setup/preferences dialog, or only if they user has pre-selected a certain category of elements. The command will be automatically enabled/disabled as appropriate.

The TaskDialog

One of the new core capabilities of Windows (starting in Vista) is an upgrade for the venerable MessageBox – called the TaskDialog. Revit now provides the TaskDialog on a platform-independent basis. The TaskDialog has all of the capabilities of the old MessageBox, but also has new and interesting capabilities like:

  • Expanded Content (visible when the user expands it)
  • As many or few buttons as you’d like (Yes/No/Close/Retry/About/etc).
  • Up to 4 Command Link buttons with supporting text.
  • Checkbox with verification text
  • Footer text

Here’s an example showing a bit of everything:

image

The code required to do a TaskDialog is pretty straightforward:

TaskDialog td = new TaskDialog("Hello World");
td.MainContent = "This is main content";
td.ExtendedContent = “This is shown on demand”;
td.Show();

// or, alternatively – you can use a static method, if you only need the basics:
TaskDialog.Show("The Title", "The Main Instruction");

Conclusion

Revit 2011 provides a good number of new controls and capabilities – it’s nice to be able to make applications that have the feel of native Revit commands.

Revit API 2011: The New UI vs. Database Split

(Part of our Revit API 2011 Series)
One interesting development in the Revit 2011 API is the splitting of the single Revit API into two – a Revit User-Interface DLL and a core Revit database DLL.

The “RevitAPI.dll” continues to cover the core database, while the new “RevitAPIUI.dll” covers the user-interface integration. This split extends to the core of the object model as well – while in the past the two primary classes in the API were Application and Document. Now, these classes have been split into:

  • UIApplication and Application
  • UIDocument and Document

UIApplication has picked up the classes and methods defining the RibbonPanels, the loaded applications, and some UI-oriented events like view changes and dialog boxes. The Application class retains the rest of the core application capability.

UIDocument picks up some of the UI-oriented aspects of the document, like selection, showing elements, and refreshing the active view.

The IExternalCommand and IExternalApplication interfaces live in the RevitAPIUI.dll, so all Add-In DLLs will have to reference the new DLL.

What does it all mean?

I don’t know this for certain, but I’m hopeful that this signals a shift towards an ability to access the Revit model outside of the user interface (similar to ObjectDBX/RealDWG on the AutoCAD side). I’m sure this is a hard feature for the factory to pursue – but here’s hoping that we might see it in a release or two.

What’s New in the Revit 2011 API: New Deployment Methods

(Part of our Revit API 2011 Series)
Deploying commands and applications in Revit up until now has required a mental visit back to the 90’s… You had to create or edit sections within the Revit.INI file – keywords and values (and ugly ones at that). And developing installers which would programmatically add and remove things? Ugh!

Autodesk has heard and finally answered the call on this issue – new in 2011 are XML-based “add-in” files. These new files (typically one for each program) also address some of the issues with permissions – particularly in Vista and Windows 7:

The locations are:

  • For “All Users”:
    • Windows XP: C:\Documents and Settings\All Users\Application Data\Autodesk\Revit\Addins\2011\
    • Windows Vista/Windows 7: C:\ProgramData\Autodesk\Revit\Addins\2011\
  • For “User-Specific”:
    • Windows XP: C:\Documents and Settings\<user>\Application Data\Autodesk\Revit\Addins\2011\
    • Windows Vista/Windows 7: C:\Users\<user>\AppData\Roaming\Autodesk\Revit\Addins\2011\

For .NET programmers, I would recommend using the Environment.GetFolder() method, where you can specify:

  • All Users: Environment.SpecialFolder.CommonApplicationData
  • Current User: Environment.SpecialFolder.ApplicationData

A basic Command sample might look like:

<?xml version="1.0" encoding="utf-16" standalone="no"?>
<RevitAddIn>
<AddIn Type="Command">
<Assembly>C:\MyDirectory\MyCommand.DLL</Assembly>
<ClientId>64end01a-5d66-4243-b4544-31429ecae9ed</ClientId>
<FullClassName>Avatech.RoomRenumber</FullClassName>
<Text>Room Renumber</Text>
<VisibilityMode>NotVisibleInFamily</VisibilityMode>
<VisibilityMode>NotVisibleInMEP</VisibilityMode>
<AccessibilityClassName></AccessibilityClassName>
</AddIn>
</RevitAddIn>

I’ll write more about some of the capabilities implied here – but as you can see it represents a big step forward versus the REVIT.INI file (which still works).

More Deployment Help Still… For Installers.

As mentioned above – writing installers for Revit in the olden-days was no picnic. While it’s no picnic in 2011, beyond the new file format, Autodesk has also provided an all-new redistributable DLL – specifically to help developers do installations in .NET.

The “RevitAddInUtility.DLL” can:

  1. Provide you information about which versions of Revit 2011 are installed (no much reverse engineering 6+ uninstall registry keys!).
  2. Get all existing addins, and manifest.

All in all, there are a variety of new features, capabilities and tools which bring more power and professionalism to Revit AddIn deployment in 2011.

The Revit API – 2011 Edition – What’s New?

For the past few years, I’ve done a series of posts describing what’s new and possible in the latest version of Revit and it’s Application Programming Interface (API). For the uninitiated, the API is the series of mechanisms that Autodesk provides to be able to drive or analyze Revit through programming.

2011 represents a watershed year in the ongoing development of the Revit API. Autodesk has taken the opportunity to re-work the API to better match how Revit works internally – and at the same time to do some amazing new things.

Over the following series of posts, I hope to cover topics such as:

  1. Upgrading Existing Revit API commands/applications
  2. New Deployment Methods
  3. The New UI vs. Database split.
  4. New Ribbon Capabilities
  5. Element Iteration Changes
  6. Ooh-ooh Pick Me! New Selection Methods
  7. Dynamic Model Update
  8. Event Model Changes
  9. RevitLookup: The New RevitMgdDbg
  10. Revit AddIn Manager: Almost Edit & Continue
  11. What’s New in Element Creation?
  12. Exceptional Stuff
  13. What Kinds of Applications are Possible Now?
  14. And More…