Announcements
Attention for Customers without Multi-Factor Authentication or Single Sign-On - OTP Verification rolls out April 2025. Read all about it here.

PickObject from Windows Form C#

Anonymous

PickObject from Windows Form C#

Anonymous
Not applicable

Hi, I've been messing around with the following code the past few hours, and I cant seem to get it to work. What I'm trying to achieve is to use a button on a windows form to select an object with the mouse in revit (to later store by id in a JSON file)

 

The problem I'm getting is that when it hits the selection.pickobject(...) command, the program just hangs and does not let you click in Revit. I think it has to do with Revit API being single thread, but I'm not sure. 

 

Any ideas would be greatly appreciated!

 

This is the code within the Windows Form.

  public partial class AddToJson : System.Windows.Forms.Form
    {
        ExternalCommandData commandData;
        UIDocument uidoc;
        Selection selection;

        public AddToJson(string optionName, ExternalCommandData cData)
        {
            commandData = cData;

            InitializeComponent();
            comboBox1.Text = optionName;
            label6.Text = optionName;

            populateForm();
            refreshData();
        }


        private void button1_Click(object sender, EventArgs e)
        {
            //this.Hide();
            foreach (System.Windows.Forms.Form f in Application.OpenForms)
            {
                f.Hide();
            }

            UIApplication app = commandData.Application;
            uidoc = app.ActiveUIDocument;
            Document doc = uidoc.Document;
            selection = uidoc.Selection;
            Reference ref1 = selection.PickObject(ObjectType.Element, "Pick element");        
            ElementId elemid = ref1.ElementId;
            this.Show();
        }

 

0 Likes
Reply
Accepted solutions (1)
4,486 Views
6 Replies
Replies (6)

jeremytammik
Autodesk
Autodesk
Accepted solution

Dear Amar,

 

Thank you for your query.

 

Yes, I think the problem is the single threading requirement in the Revit API.

 

The safest way to achieve this is to terminate the Windows form for the duration of the pick operation, and then reopen it again afterwards.

 

I suggest you search the Revit SDK samples for all occurrences of ShowDialog and PickObject.

 

The samples that make use of both of these calls will probably show you how you can easily solve your problem.

 

Another important sample that you should be aware of is ModelessDialog/ModelessForm_ExternalEvent.

 

It demonstrates how show a modeless dialogue, close it to select elements, and set up an external event to pass information from an external modeless context back into the Revit API.

 

Finally, here is an example of a loop switching back and forth between selecting elements and displaying a modal form that I recently worked on:

 

  public class Command : IExternalCommand
  {
    public Result Execute(
      ExternalCommandData commandData,
      ref string message,
      ElementSet elements )
    {
      UIDocument uidoc = commandData.Application.ActiveUIDocument;
      ElementId id;

      while( true )
      {
        id = null;

        Form form = new Form();

        DialogResult rc = form.ShowDialog();

        if( DialogResult.Cancel == rc)
        {
          break;
        }
        if( DialogResult.OK == rc )
        {
          TreeItem item = form.Selecteditem;

          if( null == item )
          {
            TaskDialog.Show( "Nothing to Select",
              "Please select a valid tree node." );
          }
          else
          {
            FilteredElementCollector a
              = new FilteredElementCollector( uidoc.Document )
                .Where...();

            int n = a.GetElementCount();

            if( 0 == n )
            {
              TaskDialog.Show( "Nothing to Select",
                string.Format( "No {0} elements found.",
                bic.Description() ) );
            }
            else if( 1 == n )
            {
              id = a.FirstElementId();
            }
            else
            {
              try
              {
                Pick element ...
              }
              catch operation cancelled
              {
                TaskDialog.Show( "Nothing Selected",
                  "Nothing Selected." );
              }
            }
            if( null != id && ElementId.InvalidElementId != id )
            {
              Debug.Print(
                "Selected element id {0} for tree node {1}",
                id.IntegerValue, item.Name );
            }
          }
        }
      }
      return Result.Succeeded;
    }
  }

 

I hope this helps.

 

Best regards,

 

Jeremy

 



Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

Anonymous
Not applicable

Thanks for your answer, I'll look into it!

0 Likes

Hugo.Bergeron
Contributor
Contributor

Hello Jeremy,

     Three years later, is this answer still the best solution? How about using a Dockable Panel? I am trying my best at creating a floating tool panel outside of the ribbon, with lists and drop downs populated with external data, and I find managing the state of it pretty slow andd combersome if I have to redraw the form after each picking sessions. I also want this panel to hold buttons that call methods in my class. I tried a modeless form, but without something to block the UI Thread (like a pickobject session) it will just open and close, obviously. Is there another approach?

 

Thanks for your BuildingCoder

0 Likes

jeremy_tammik
Autodesk
Autodesk

Dear Hugo,

 

Thank you for your appreciation.

 

Modal form, modeless form, Windows Forms, WPF, dockable panel, stand-alone external executable and many more are all viable approaches.

 

The best solution depends completely on your specific requirements.

 

Cheers,

 

Jeremy

 

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes

Hugo.Bergeron
Contributor
Contributor
using (var p = new ToolPalette(CSVFile.CSVFileChange(uiapp)))
{
    p.Show(_hWndRevit);
    System.Windows.Forms.Application.Run(p);
}

 

This is what i ended up using.

ShambhaveeP2ZMB
Explorer
Explorer

@Hugo.Bergeron, thanks this worked for me!