Adding Forms to Revit Macros

Adding Forms to Revit Macros

Recently, I attended RTCNA2014 and was lucky enough to participate in a fantastic class taught by Troy Gates. The class focused around the concept of creating Revit macros for BIM Management. I’ll admit that I dont always look to the API to make my life easier but Jason and I have defintely talked about it. As with most technology conferences, each class has a Q/A session at the end. One of the questions that came up asked if it was possible to add user forms in a revit macro. Troy gracefully answered the question but it I realized that its not really something that is documented for Revit specifically. Therefor, I am going to take a crack at it for the greater community. Please remember, I am not a professional coder so if this goes against the best known methods for expert coders, I am sorry and welcome “down-to-earth” suggestions.

Adding Forms to a Macro

Adding a form to a macro is not very difficult if you have built a form in Visual Studio or any other VSTA. However, Revit does not use a Visual Studio variant, the developers went with SharpDevelop which is an opensource IDE. If you have created a few macros in Revit, this is not news to you. With that said, there are a few posts out there to create forms in SharpDevelop but most require interpertation for usage with Revit. Example Let’s just get started shall we.

To create a form, first you need to have created a module within the Macro Manager. So if you have not started that process, I’ll wait for you. Great! With SharpDevelop open, find the project that you are currently editing. In the following example, My project will be called: MattBeNimble. Right Click on the Project > Add > New Item and create a New C# (VB) > Windows Applications > Form and name as desired.

Add Item Project > Add > New Item

New Form New C# (VB) > Windows Applications > Form

This will create a standard Windows Form and relevant form class and form designer. Just like in Visual Studio, you have the ability to visually design the form. At the bottom of the Form.cs you will have access to [2] tabs Source and Design where design will allow visual designing. You may need to turn on the View > Tools pallette to access the form tools.

At this time, you would build up a standard Windows form as you would in Visual Studio.

Sample Macro with a Form

I dont want to just leave it there, as I said earlier, I have not seen a post out there for a form based macro with a Revit focus. I have built up an extremly simple macro that create a drafting view with a text note based upon input from a form. Here is a video of its functionality.

As you can see there is a simple form: Add Item

that allows an input and when complete, creates the view, text note and then activates the view.

The Code

For the macro itself the code is pretty darn simple:

public void testForm()
  {
   //Active UIDocument
   UIDocument uidoc = this.ActiveUIDocument;
   
   //Active Document
   Document doc = uidoc.Document;

   //Access a new instance of the Form1 created earlier and call it 'form'
   using(var form = new Form1())
   {
    //use ShowDialog to show the form as a modal dialog box. 
    form.ShowDialog();
    
    //if the user hits cancel just drop out of macro
    if(form.DialogResult == forms.DialogResult.Cancel) return;
   
    //else do all this :)
    
    //create a transaction
    using(var t = new Transaction(doc,"FormSample"))
    {
     //stert 'er up
     t.Start();
     
     //create a simple drafting view
     View view = doc.Create.NewViewDrafting();
     //name it
     view.Name = "Form Sample";
     
     // create a text note and feed in the text from the form
     // the last variable is the form's text value that the user supplied 
     // which i called by using form.TextString 
     // (a public variable that was set in the form's class)
     TextNote note = doc.Create.NewTextNote(
            view, 
            new XYZ(0,0,0),
            XYZ.BasisX,
            XYZ.BasisY,
            1,
            TextAlignFlags.TEF_ALIGN_CENTER,
            form.TextString
            );
     
     //commit the transaction
     t.Commit();
     
     //set the active view to the new view created
     uidoc.ActiveView = view;
     
    }//end using statement for transaction
   }//end using statement for form
  }

The key parts to this code is the initiation of the form and the use of the form variable “TextString”. So let’s break it down a bit

using(var form = new Form1())
{
  form.ShowDialog();
  
  if(form.DialogResult == forms.DialogResult.Cancel) return;
  
}

This snippet is predicated with the use of the using statement using forms = System.Windows.Forms; to allow access to the windows form library without getting confused with any Autodesk library. In the code snippet, I create a new instance of the Form1 class and as soon as it’s called i display the form with form.ShowDialog() which shows the form as a modal dialog box. Meaning, I can figure out what button was pushed when the dialog closed and do something with it. In our case, we use the DialogResult.Cancel to determine if the dialog was canceled and if it is, just return and do nothing else. This is determined by the behavior of the buttons we made when creating the form. In our case, the cancel button was mapped to DialogResult.Cancel. Since, I disabled all other controls except for the [2] buttons i made, it’s very easy for me to track the dialog results.

Once we move past the result of the dialog, we want to use that input we added to the text box on the form right? Right. The form code which is in the Form1 class has a public variable added to it as shown below. When we execute the Create Text button, I’m passing the text that is in the textbox to that public variable to be retrieved by our main method. Hopefully the code below can illustrate that well.

Form1.cs

public partial class Form1 : Form
 {
  //Public variable added for retrieval in main method
  public string TextString {get;set;}
  
  public Form1()
  {
   InitializeComponent();
  }
  
  //When OK is clicked return the TextBox Text 
  void OK_BtnClick(object sender, EventArgs e)
  {
   TextString = TXT_Box.Text;
  }
 }

ThisApplication.cs (Macro Module) – Inside of testForm Method

// create a text note and feed in the text from the form
// the last variable is the form's text value that the user supplied 
// which i called by using form.TextString
// (a public variable that was set in the form's class)
TextNote note = doc.Create.NewTextNote(
  view, 
  new XYZ(0,0,0),
  XYZ.BasisX,
  XYZ.BasisY,
  1,
  TextAlignFlags.TEF_ALIGN_CENTER,
  form.TextString //returned value from public variable in form1.cs
);

Within the doc.Create.NewTextNote method, im passing form.TextString as the value for the string in the new TextNote and this allows us to pull the value directly from the form class. In essense, I setup the variable in the form code and then access it within the macro as a variable from the form iteself. As I said, Im not a pro coder or anything like that. I know this works for me and has been stable for many of the addins that I have built. If there is a better way, feel free to add it in the comments below.

This is not the most expansive sample that I could have built, but i wanted to show a simple example of how a form could be intergrated into a Revit macro. I hope I made some sense in there.

Some Bonus tips.

Getting Rid of the Default Icon

Im anal about this, so I hope it helps someone, somewhere. I absolutely hate the default icon in windows forms. When i see a custom app,application,addin or macro that leaves the ugly icon present, I judge it. Sorry, I do. It’s so fast to get rid of it, so I wonder why it’s still there. So here is the settings That I use to make sure that it does not show in the form.

Properties of the Form

Form Properties

I make sure that the FormBorderStyle is set to FixedDialog to clean up the style of the dialog. This does remove the icon on its own. However, I also like to remove the ControlBox (the minimize, maximize, close buttons) to make sure the user does what I want them to. Use this functionality at your discretion.

Locating the Dialog Box

I like the dialog to be front and center. This makes me feel like i have paid close attention to the details and makes sure the user is not hunting around for the dialog. So here is a simple property to check out.

Properties of the Form

Form Properties

I use the StartPosition set to CenterParent to make sure it is always right in the middle of the revit interface when it loads up. It may be a pain in the arse for some dialog but I like to start there.

I hope that I did not botch this too much and that someone found value in this approach. Thanks for reading.