Revit APP Blog

Information on Revit APP.

Browsing Posts published in June, 2010

Revit 2011 API provides user ways to create their own ribbon panel & buttons. Plus the shortcut capability, it makes addins similar as built-in functionalities. To add your own ribbon stuff, you only need to implement the IExternalApplication interface, and in the OnStartup function, write code like this:

public Result OnStartup(UIControlledApplication uiControlledApplication)
{
   // The location of this command assembly
   string assemblyPath = System.Reflection.Assembly.GetExecutingAssembly().Location;

   // begin to create custom Ribbon panel and command buttons.
   // create a Ribbon panel.
   RibbonPanel myPanel = uiControlledApplication.CreateRibbonPanel(“MyRibbonPanel”);

   // the button in the new panel
   PushButton pushButton = myPanel.AddItem(new PushButtonData(“MyPushButton”, “Command1″, assemblyPath, typeof(Command1).FullName)) as PushButton;
   pushButton.ToolTip = “Command1″;
   // the large image uses for tooltip
   Command1.LargeImage = new BitmapImage(new Uri(Path.Combine(buttonImageDir, “Command1_Large.bmp”)));
   // image uses for the button
   Command1.Image = new BitmapImage(new Uri(Path.Combine(buttonImageDir, “Command1_Small.bmp”)));

   RadioButtonGroupData radioButtonGroupData = new RadioButtonGroupData(“TypeSelector”);
   RadioButtonGroup radioButtonGroup = (RadioButtonGroup)(myPanel.AddItem(radioButtonGroupData));
   ToggleButton toggleButton = radioButtonGroup.AddItem(new ToggleButtonData(“Type1″, “Type1″, assemblyPath, “MyApp.Type1″));
   toggleButton.LargeImage = new BitmapImage(…large image uri);
   toggleButton.Image = new BitmapImage(…image uri);
   toggleButton = radioButtonGroup.AddItem(new ToggleButtonData(“Type2″, “Type2″, assemblyPath, “MyApp.Type1″));
   toggleButton.LargeImage = new BitmapImage(…large image uri);
   toggleButton.Image = new BitmapImage(…image uri);

   return Result.Succeeded;
}

Go to the SDK\Samples\Ribbon\CS folder to get more detail examples.

If you want to use images added in the solution (so you don’t need external image file when deployment), you can add all needed image files in projects and set their “Build Action” in property as “Embedded Resource”, and get the ImageSource using following code:

System.IO.Stream file = app.GetManifestResourceStream(namespace + “.” + imageName);
PngBitmapDecoder bd = new PngBitmapDecoder(file, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);

 Please replace the namespace with your own namespace name.

Revit 2011 supports user defined keyboard shortcut for both build-in commands and API addin commands. Here we show you the way to set your own keyboard shortcut for your addin commands. Before the setting, please make sure “Add-ins” tab shows up in your Revit ribbon and your addin commands shows up under the “Add-ins” tab.

Go to “View” tab, click the “User Interface” dropdown menu, and select the “Keyboard Shortcuts” item like following pic.

Then in the pop up dialog, select “Add-ins tab” in the Filter dropdown combobox, like following pic:

After the selection, you can see all your commands under Add-ins tab, choose the command item and input the keyboard shortcuts in the “Press new keys” area, then click “Assign” button:

Click “OK” to close the Keyboard Shortcuts dialog. Then you can use your new defined shortcuts for your own commands now.

New interfaces have been added to the API to permit iteration of elements and element ids. These new interfaces have been designed to provide a more flexible and usable interface for a variety of applications, while being completely implemented in native Revit code to provide the best possible performance.

Existing element iteration routines have been replaced, including:

  • Document.Elements (all versions of this property)
  • ElementIterator
  • Filter and all subclasses of it
  • Application.Create.Filter
  • Classes and properties related to the ParameterFilter:
  • CriteriaFilterType
  • Document.FilterTypeSupported
  • FilterCriterion
  • ParameterStorage

The new element iteration interfaces offer several enhanced capabilities from their predecessors:

  • The ability to iterate and filter elements from a document, or only elements from an arbitrary list of element ids, or elements visible in a view (replacing View.Elements)
  • The ability to clearly identify filters which are designed for best performance (“Quick Filters”), which do not expand the element in memory when evaluating whether the element passes the filter
  • The ability to use chained shortcuts which automatically apply commonly used filters, e.g.

FilteredElementCollector collector = new FilteredElementCollector(document);
// Finds all walls in a certain design option
ICollection<ElementId> walls = collector.OfClass(typeof(Wall))
                                        .ContainedInDesignOption(myDesignOptionId)
                                        .ToElementIds();
 

  • The ability to logically group more than two filters.
  • The ability to match derived types automatically when using the type filter and type filter shortcut.
  • The ability to iterate elements from all design options or from any specific design option.
  • The ability to use foreach on the collector element, and to use the class with LINQ queries. This is due to the connection between the collector class and System.Collections.Generic.IEnumerable<Element>. Note that because the ElementFilters and the shortcut methods offered by this class process elements in native code before their managed wrappers are generated, better performance will be obtained by using as many native filters as possible on the collector before attempting to process the results using LINQ queries.

FilteredElementCollector collector = new FilteredElementCollector(m_doc);
// First apply a built-in filter to minimize the number of elements processed by LINQ
collector.WherePasses(new ElementCategoryFilter(BuiltInCategory.OST_Levels));

var levelElements = from element in collector
                    where element.Name == “Level 1″
                    select element;  // LINQ query to find level with name == “Level 1″

Level level1 = levelElements.Cast<Level>().ElementAt<Level>(0);

Detailed information on the new element iteration interfaces can be found in the document “Element iteration APIs” in the SDK.

Note that there are a few behavioral changes in the new iteration mechanism when compared to the old:

  • View templates were previously returned as Element. They are now returned as the correct View subclass (ViewPlan, View3d, etc). You can identify these using the new View.IsTemplate property.
  • Previous element iteration methods only returned elements of the main model, the active design option, and primary design options of each option set. Elements of design options which were not active and not primary were excluded. In the new iteration API, by default, design option membership is no longer considered when iterating elements. In order to find the same elements which were iterated in the 2010 API, you should use the following filters combined using ‘OR’:
  • An ElementDesignOptionFilter with id = InvalidElementId, to match all elements not associated to a design option.
  • An ElementDesignOptionFilter with id = DesignOption.GetActiveDesignOptionId(), to match elements in the active design option.
  • A PrimaryDesignOptionMemberFilter, to match all elements in primary design options.

The custom attribute Autodesk.Revit.Attributes.RegenerationAttribute should be applied to your implementation class of the IExternalCommand interface and IExternalApplication interface to control the regeneration behavior for the external command and external application. There is no default for this option. You must apply it to legacy application classes to allow your application to function in Revit 2011.

This mode controls whether or not the API framework automatically regenerates after every model modification. There are two supported values:

  1. RegenerationOption.Automatic – The API framework will regenerate after every model level change (equivalent behavior with Revit 2010 and earlier). Regeneration and update can be suspended using SuspendUpdating for some operations, but in general the performance of multiple modifications within the same file will be slower than RegenerationOption.Manual. This mode is provided for behavioral equivalence with Revit 2010 and earlier; it is obsolete and will be removed in a future release.
  2. RegenerationOption.Manual – The API framework will not regenerate after every model level change. Instead, you may use the regeneration APIs to force update of the document after a group of changes. SuspendUpdating blocks are unnecessary and should not be used. Performance of multiple modifications of the Revit document should be faster than RegenerationOption.Automatic. Because this mode suspends all updates to the document, your application should not read data from the document after it has been modified until the document has been regenerated, or it runs the risk of accessing stale data. This mode will be only option in a future release.

For example, to set an external command to use manual regeneration mode:

[Regeneration(RegenerationOption.Manual)]
[Transaction(TransactionMode.Automatic)]
public class Command : IExternalCommand
{
    public Autodesk.Revit.IExternalCommand.Result Execute(Autodesk.Revit.ExternalCommandData commandData,
                                                          ref string message,
                                                          Autodesk.Revit.ElementSet elements)
    {
        // Command implementation, which modifies the document and calls regeneration APIs when
        // needed.
    }
}

To set an external application to use automatic mode

[Regeneration(RegenerationOption.Automatic)]
public class Application : IExternalApplication
{
    public Autodesk.Revit.UI.Result OnStartup(ControlledApplication application)
    {
        // OnStartup implementation
    }
  
    public Autodesk.Revit.UI.Result OnShutdown(ControlledApplication  application)
    {
      // OnShutdown implementation
    }
}

 The regeneration mode used for code executed during events and updater callbacks will be the same mode applied to the ExternalApplication or ExternalCommand during which the event or updater was registered.

Revit 2011 API exposed many new application events that API developer can use. The whole list of events is:

Name Description
DocumentChanged Subscribe to the DocumentChanged event to be notified when Revit document has changed.
DocumentClosed Subscribe to the DocumentClosed event to be notified immediately after Revit has finished closing a document.
DocumentClosing Subscribe to the DocumentClosing event to be notified when Revit is just about to close a document.
DocumentCreated Subscribe to the DocumentCreated event to be notified immediately after Revit has finished creating a new document.
DocumentCreating Subscribe to the DocumentCreating event to be notified when Revit is just about to create a new document.
DocumentOpened Subscribe to the DocumentOpened event to be notified immediately after Revit has finished opening a document.
DocumentOpening Subscribe to the DocumentOpening event to be notified when Revit is just about to open a document.
DocumentPrinted Subscribe to the DocumentPrinted event to be notified immediately after Revit has finished printing a view or ViewSet of the document.
DocumentPrinting Subscribe to the DocumentPrinting event to be notified when Revit is just about to print a view or ViewSet of the document.
DocumentSaved Subscribe to the DocumentSaved event to be notified immediately after Revit has finished saving a document.
DocumentSavedAs Subscribe to the DocumentSavedAs event to be notified immediately after Revit has finished saving document with a new file name.
DocumentSaving Subscribe to the DocumentSaving event to be notified when Revit is just about to save a document.
DocumentSavingAs Subscribe to the DocumentSavingAs event to be notified when Revit is just about to save the document with a new file name.
DocumentSynchronizedWithCentral Subscribe to the DocumentSynchronizedWithCentral event to be notified immediately after Revit has finished synchronizing a document with central file.
DocumentSynchronizingWithCentral Subscribe to the DocumentSynchronizingWithCentral event to be notified when Revit is just about to synchronize a document with central file.
FailuresProcessing Subscribe to the FailuresProcessing event to be notified when failures are being processed at the end of transaction.
FileExported Subscribe to the FileExported event to be notified immediately after Revit has finished exporting files of formats supported by the API.
FileExporting Subscribe to the FileExporting event to be notified when Revit is just about to export files of formats supported by the API.
FileImported Subscribe to the FileImported event to be notified immediately after Revit has finished importing a file of format supported by the API.
FileImporting Subscribe to the FileImporting event to be notified when Revit is just about to import a file of format supported by the API.
ViewPrinted Subscribe to the ViewPrinted event to be notified immediately after Revit has finished printing a view of the document.
ViewPrinting Subscribe to the ViewPrinting event to be notified when Revit is just about to print a view of the document.

When the event will be post is decribed in the description part. Most cases, you could know what the event is through its name directly.

Use the event is very simple, let’s use the DocumentOpened event as example, the event handler should be added when revit startup, so we need an external application instead of external command to handle this. New a file and write code as:

using System;

using Autodesk.Revit;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Events;
using Autodesk.Revit.UI;

namespace myRevitApp
{
   [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Automatic)]
   [Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
   public class MyApp : IExternalApplication
   {
      public Result OnStartup(UIControlledApplication uiControlledApplication)
      {
         uiControlledApplication.ControlledApplication.DocumentOpened += new EventHandler<DocumentOpenedEventArgs>(docOpen);
         return Result.Succeeded;
      }

      private void docOpen(object sender, DocumentOpenedEventArgs e)
      {
         Autodesk.Revit.ApplicationServices.Application app = sender as Autodesk.Revit.ApplicationServices.Application;
         UIApplication uiApp = new UIApplication(app);
         Document doc = uiApp.ActiveUIDocument.Document;
         // show document name
         TaskDialog.Show(“Doc path name”, doc.PathName);
      }

      public Result OnShutdown(UIControlledApplication application)
      {
         return Result.Succeeded;
      }
   }
}

And the .addin file should be like:

<?xml version=”1.0″ encoding=”utf-16″ standalone=”no”?>
<RevitAddIns>
  <AddIn Type=”Application”>
    <Name>myRevitApp</Name>
    <Assembly>C:\Project\myRevitApp.dll</Assembly>
    <AddInId>7cbae747-78f9-4dd5-ac92-a94f6229f9b3</AddInId>
    <FullClassName>myRevitApp.MyApp</FullClassName>
  </AddIn>
</RevitAddIns>

 Then build the solution and run, a task dialog will show up when you open a document.

In previous blog, we said that user can retrieve one parameter from an element through Element.get_Parameter(…) function.

Revit API also provides properties for API developer to get all parameters of an element, the two properties are:
Element.Parameters
Element.ParametersMap

Both properties contain all public parameters the element has, however, they also differ a little and we should use them in different ways.

The first property Parameters returns a set of Parameter, we can use this if we want to iterate all public parameters. The code would like:
   ParameterSetIterator it = Element.Parameters.ForwardIterator();
   while (it.MoveNext())
   {
      Parameter param = it.Current as Parameter;
      // Maybe check some conditiones like param.Definition, StorageType etc.
      // do something for param…
   }
The second property ParametersMap returns a map of Parameters, whose key is the name of the parameter. So if we want to retrieve several parameters from element through their name, use this property would be better (get_Parameter can also achieve this, however, that function will iterate all parameters each time it calls). The code looks like:
   ParameterMap paramMap = eRef.Element.ParametersMap;
   if (paramMap.Contains(“ParamA”))
   {
      Parameter param = paramMap.get_Item(“ParamA”);
      // do something for param …
   }
   if (paramMap.Contains(“ParamB”))
   {
      Parameter param = paramMap.get_Item(“ParamB”);
      // do something for param …
   }
   if (paramMap.Contains(“ParamC”))
   {
      Parameter param = paramMap.get_Item(“ParamC”);
      // do something for param …
   }
Attention: Check whether the map contains the parameter before get it, otherwise, it will throw an exception if the name is not found.

The custom attribute Autodesk.Revit.Attributes.TransactionMode should be applied to your implementation class of the IExternalCommand interface to control transaction behavior for external command. There is no default for this option. You must apply it to legacy application classes to allow your application to function in Revit 2011.

This mode controls how the API framework expects transactions to be used when the command is invoked. There are three supported values:

  1. TransactionMode.Automatic – The API framework will create a transaction on the active document before the external command is executed and the transaction will be committed or rolled back after the command is completed (based upon the return value of the ExternalCommand callback). This means that command code cannot create and start its own Transactions, but it can create SubTransactions as required during the implementation of the command. The command must report its success or failure status via the Result return value.
  2. TransactionMode.Manual – The API framework will not create a transaction (but it will create an outer group to roll back all changes if the external command returns a failure status). Instead, you may use combinations of Transactions, SubTransactions, and TransactionGroups as you please. You will have to follow all rules regarding use of transactions and related classes. You will have to give your transaction(s) names, which will then appear in the Undo menu. Revit will check that all transactions (also groups and sub-transactions) are properly closed upon return from an external command. If not, it will discard all changes made to the model.
  3. TransactionMode.ReadOnly – No transaction (nor group) will be created, and no transaction may be created for the lifetime of the command. The External command may use methods that only read from the model, but not methods that write anything to it. Exceptions will be thrown if the command either tries to start a transaction (or group) or attempts to write to the model.

In all three modes, the TransactionMode applies only to the active document. You may open other documents during the course of the command, and you may have complete control over the creation and use of Transactions, SubTransactions, and TransactionGroups on those other documents (even in ReadOnly mode).

For example, to set an external command to use automatic transaction mode:

[Regeneration(RegenerationOption.Manual)]

[Transaction(TransactionMode.Automatic)]

public class Command : IExternalCommand

{

    public Autodesk.Revit.IExternalCommand.Result Execute(Autodesk.Revit.ExternalCommandData commandData,

                                                          ref string message,

                                                          Autodesk.Revit.ElementSet elements)

    {

        // Command implementation, which modifies the active document directly and no need to

        // start/commit any transactions.

    }

}

The Revit API now offers the ability to register API applications via a .addin manifest file.

Manifest files will be read automatically by Revit when they are places in one of two locations on a user’s system:

  • In a non-user specific location in “application data”
  • For Windows XP – C:\Documents and Settings\All Users\Application Data\Autodesk\Revit\Addins\2011\
  • For Vista/Windows 7 – C:\ProgramData\Autodesk\Revit\Addins\2011\
  • For Windows XP – C:\Documents and Settings\<user>\Application Data\Autodesk\Revit\Addins\2011\
  • For Vista/Windows 7 – C:\Users\<user>\AppData\Roaming\Autodesk\Revit\Addins\2011\
  • In a user specific location in “application data”

All files named .addin in these locations will be read and processed by Revit during startup.

A basic file adding one ExternalCommand looks like this:

<?xml version=”1.0″ encoding=”utf-8″ standalone=”no”?>

<RevitAddIns>

   <AddIn Type=”Command”>

      <Assembly>c:\MyProgram\MyProgram.dll</Assembly>

      <AddInId>76eb700a-2c85-4888-a78d-31429ecae9ed</AddInId>

      <FullClassName>Revit.Samples.SampleCommand</FullClassName>

      <Text>Sample command</Text>

      <VisibilityMode>NotVisibleInFamily</VisibilityMode>

      <VisibilityMode>NotVisibleInMEP</VisibilityMode>

      <AvailabilityClassName>Revit.Samples.SampleAccessibilityCheck</AvailabilityClassName>

      <LongDescription>

         <p>This is the long description for my command.</p>

         </p/>

         <p>This is another descriptive paragraph, with notes about how to use the command properly.</p>

      </LongDescription>

      <TooltipImage>c:\MyProgram\Autodesk.jpg</TooltipImage>

      <LargeImage>c:\MyProgram\MyProgramIcon.png</LargeImage>

   </AddIn>

</RevitAddIns>

A basic file adding one ExternalApplication looks like this:

<?xml version=”1.0″ encoding=”utf-8″ standalone=”no”?>

<RevitAddIns>

   <AddIn Type=”Application”>

      <Name>SampleApplication</Name>

      <Assembly>c:\MyProgram\MyProgram.dll</Assembly>

      <AddInId>604B1052-F742-4951-8576-C261D1993107</AddInId>

      <FullClassName>Revit.Samples.SampleApplication</FullClassName>

   </AddIn>

</RevitAddIns>

Multiple AddIn elements may be provided in a single manifest file.

The new mechanism currently offers the following XML tags:

 Tag  Description
 Assembly  The full path to the add-in assembly file. Required for all ExternalCommands and ExternalApplications.
 FullClassName  The full name of the class in the assembly file which implements IExternalCommand or IExternalApplication. Required for all ExternalCommands and ExternalApplications.
 ClientId  A GUID which represents the id of this particular application. ClientIds must be unique for a given session of Revit. Autodesk recommends you generate a unique GUID for each registered application or command. Required for all ExternalCommands and ExternalApplications.  The property UIApplication.ActiveAddInId provides programmatic access to this value, if required.
 Name  The name of application. Required; for ExternalApplications only.
 Text  The name of the button. Optional; use this tag for ExternalCommands only. The default is “External Tool”.
 Description  Short description of the command, will be used as the button tooltip. Optional; use this tag for ExternalCommands only. The default is a tooltip with just the command text.
 VisibilityMode  Provides the ability to specify if the command is visible in project documents, family documents, or no document at all. Also provides the ability to specify the discipline(s) where the command should be visible. Multiple values may be set for this option. Optional; use this tag for ExternalCommands only. The default is to display the command in all modes and disciplines, including when there is no active document. Previously written external commands which need to run against the active document should either be modified to ensure that the code deals with invocation of the command when there is no active document, or apply the NotVisibleWhenNoActiveDocument mode.
 AvailabilityClassName  The full name of the class in the assembly file which implemented IExternalCommandAvailability. This class allows the command button to be selectively grayed out depending on context. Optional; use this tag for ExternalCommands only. The default is a command that is available whenever it is visible.
 LargeImage  The path to the icon to use for the button in the External Tools pulldown menu. The icon should be 32 x 32 pixels for best results. Optional; use this tag for ExternalCommands only. The default is to show a button without an icon.
 LongDescription  Long description of the command, will be used as part of the button’s extended tooltip. This tooltip is shown when the mouse hovers over the command for a long amount of time. You can split the text of this option into multiple paragraphs by placing <p> tags around each paragraph. Optional; use this tag for ExternalCommands only. If neither of this property and TooltipImage are supplied, the button will not have an extended tooltip.
 TooltipImage  The path to an image file to show as a part of the button extended tooltip, shown when the mouse hovers over the command for a longer amount of time. Optional; use this tag for ExternalCommands only. If neither of this property and TooltipImage are supplied, the button will not have an extended tooltip.
 LanguageType  Localization setting for Text, Description, LargeImage, LongDescription, and TooltipImage of external tools buttons. Revit will load the resource values from the specified language resource dll. The value can be one of the eleven languages supported by Revit. If no LanguageType is specified, the language resource which the current session of Revit is using will be automatically loaded. For more details see the section on Localization.

The Revit.ini registration mechanism remains in place for the 2011 release but will be removed in the future. The Revit.ini mechanism does not offer any of the new capabilities listed above. In addition, because Dynamic Model Update registration requires a valid AddInId, updaters may not be registered from applications declared in Revit.ini.

Powered by WordPress Web Design by SRS Solutions © 2012 Revit APP Blog Design by SRS Solutions