Dynamic Model Update to warn or log after a user operation

Maybe the approach in the previous post, of completely shutting down the Import command, is too harsh. This example shows how a Dynamic Model Update macro can give a warning after the user imports a CAD file. For some introductory comments on Dynamic Model Update, see https://boostyourbim.wordpress.com/2012/12/17/automatically-run-api-code-when-your-model-changes.

Instead of (or in addition to) the TaskDialog warning used in the code below, you could do other things like write information to a log file (to submit to Human Resources and include in the Revit user’s permanent record!) or require the user to enter a password to complete the operation – if the wrong password is entered then delete the element id returned by data.GetAddedElementIds().

private void Module_Startup(object sender, EventArgs e)
{
    ImportInstanceUpdater updater = new ImportInstanceUpdater(this.Application.ActiveAddInId);
    try
    {
    UpdaterRegistry.RegisterUpdater(updater);
    UpdaterRegistry.AddTrigger(updater.GetUpdaterId(),
                               new ElementClassFilter(typeof(ImportInstance)),
                               Element.GetChangeTypeElementAddition());
    }
    catch {}
}

public class ImportInstanceUpdater : IUpdater
{
    static AddInId m_appId;
    static UpdaterId m_updaterId;
    // constructor takes the AddInId for the add-in associated with this updater
    public ImportInstanceUpdater(AddInId id)
    {
        m_appId = id;
        m_updaterId = new UpdaterId(m_appId, new Guid("FBFBF6A2-4C06-42d4-97C1-D1B4EB593EFF"));
    }
    public void Execute(UpdaterData data)
    {
        Document doc = data.GetDocument();
        Autodesk.Revit.ApplicationServices.Application app = doc.Application;
        foreach (ElementId addedElemId in data.GetAddedElementIds())
        {
            ImportInstance ii = doc.GetElement(addedElemId) as ImportInstance;
            if (ii.IsLinked == false)
                TaskDialog.Show("Hey!", app.Username + " - Maybe should should have linked that CAD instead of importing it.");
        }
    }
    public string GetAdditionalInformation(){return "Check to see if CAD file was imported";}
    public ChangePriority GetChangePriority(){return ChangePriority.FloorsRoofsStructuralWalls;}
     public UpdaterId GetUpdaterId(){return m_updaterId;}
    public string GetUpdaterName(){return "Import Check";}
}

How to override commands in the Revit UI (when you REALLY don’t want people to import CAD files)

The previous post showed how to delete CAD imports that are already in your Revit model. What if you want to prevent those CAD imports from being added in the first place?

The 2013 API introduced functionality that allows commands in the Revit UI to be replaced with your API code. In this simple case, the Import command will be replaced with an error dialog.

You will need to find the ID for the command that you want to replace. The easiest way to do that is to execute the command through the Revit UI and then open the Revit journal file (in C:\Users\HP002\AppData\Local\Autodesk\Revit\Autodesk Revit Architecture 2013\Journals or something like that). For import, the entry will be

 Jrn.Command "Internal" , "Import vector data from other programs , ID_FILE_IMPORT"

The string in capital letters near the end of the line is the command id. Here’s the code showing how to replace the Import command, and in the video you see that while Link still works as usual, Import does not.

private void Module_Startup(object sender, EventArgs e)
{
    UIApplication uiapp = new UIApplication(this.Application);

    // Get the command id for the import command
    RevitCommandId commandId = RevitCommandId.LookupCommandId("ID_FILE_IMPORT");

    // use try/catch because CreateAddInCommandBinding will throw if there is already a binding for this id
    // for more info see https://boostyourbim.wordpress.com/2013/01/06/using-module_startup-to-run-macro-code-when-revit-starts/
    try
    {
        AddInCommandBinding importBinding = uiapp.CreateAddInCommandBinding(commandId);
        importBinding.Executed += new EventHandler<Autodesk.Revit.UI.Events.ExecutedEventArgs>(importReplacement);
    }
    catch
    {}
}

private void importReplacement(object sender, Autodesk.Revit.UI.Events.ExecutedEventArgs arg)
{
    TaskDialog.Show("Stop!","Do not import!");
}

Delete Imported DWGs and Other CAD files

In yesterday’s post we learned that imports belong to the ImportInstance Class and that the ImportInstance.IsLinked property is true if the element is linked and false if it is imported.

With this knowledge, we just need a FilteredElementCollector, a bit of LINQ, a transaction, and Document.Delete to get the imports (but not the links) out of the model.

public void deleteImportsNotLinks()
{
    Document doc = this.ActiveUIDocument.Document;
    using (Transaction t = new Transaction(doc,"Delete Imports"))
       {
        t.Start();
        foreach (ImportInstance ii in new FilteredElementCollector(doc).OfClass(typeof(ImportInstance)).Cast<ImportInstance>().Where(i => i.IsLinked == false))
        {
            doc.Delete(ii);
        }      
        t.Commit();
   }
}

Stepping Into your macros and “Is this an import or a link?”

link

At Do U Revit, there is a post about finding and eliminating CAD imports from your Revit project. This is easy to do with a little bit of macro writing, and it also offers an opportunity for me to write about the “Step Into” macro command, which is a great way to explore the API and figure out how you might solve a specific problem.

In this case, I write a macro that prompts the user to select an element. If I select a DWG import and a DWG link, is there any way inside the API that I will be able to tell one from the other? If I want to write a filter to get all imports or all links, what data can I use to get them?

The answer is that imports and links both belong to the API’s ImportInstance class and this class has a property IsLinked (as shown in this screenshot from the API help file).

To learn how to find the answer, watch this video.