Keep Windows Form Open after running plugin!

Keep Windows Form Open after running plugin!

zrodgersTSSSU
Advocate Advocate
1,139 Views
1 Reply
Message 1 of 2

Keep Windows Form Open after running plugin!

zrodgersTSSSU
Advocate
Advocate

Hey Everyone! I looked around on the forum and I couldnt find a solution for this.... So how do I keep my windows form up after running the plugin? My work around before was to copy the body of my code into the  form itself, but i figured there has to be a better way... I want the form to stay open so I can run it multiple times on different selections. I think it has something to do with it being a dialog result but not sure. Can anyone give me some guidance on this?

 

 

Here is my FormCode:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.DB.Plumbing;

namespace DynamoToRevitPlugin
{
    public partial class PipeCreationForm : System.Windows.Forms.Form
    {
        public PipeCreationForm(Autodesk.Revit.UI.ExternalCommandData commandData)
        {
            InitializeComponent();

            UIDocument uidoc = commandData.Application.ActiveUIDocument;
            Document doc = uidoc.Document;

            //levels
            FilteredElementCollector levels = new FilteredElementCollector(uidoc.Document);
            List<Level> levelCol = levels.OfClass(typeof(Level)).OfType<Level>().OrderBy(lev => lev.Elevation).ToList();
            sLevel.DataSource = new List<Level>(levelCol);
            sLevel.DisplayMember = "Name";
            if (levelCol.Any())
            {
                sLevel.SelectedIndex = 0;
            }

            //System Type
            FilteredElementCollector mepSystem = new FilteredElementCollector(uidoc.Document);
            List<PipingSystemType> systemTypeCol = mepSystem.OfClass(typeof(PipingSystemType)).OfType<PipingSystemType>().OrderBy(x => x.Name).ToList();
            pSysType.DataSource = new List<PipingSystemType>(systemTypeCol);
            pSysType.DisplayMember = "Name";
            if (systemTypeCol.Any())
            {
                pSysType.SelectedIndex = 0;
            }

            //pipe types
            FilteredElementCollector pipeType = new FilteredElementCollector(uidoc.Document);
            List<PipeType> pipeTypeCol = pipeType.OfClass(typeof(PipeType)).OfType<PipeType>().ToList();
            pType.DataSource = new List<PipeType>(pipeTypeCol);
            pType.DisplayMember = "Name";
            if (pipeTypeCol.Any())
            {
                pType.SelectedIndex = 0;
            }

        }

        private void btnOK_Click(object sender, EventArgs e)
        {

        }

        private void PipeCreationForm_Load(object sender, EventArgs e)
        {

        }

        private void pType_SelectedIndexChanged(object sender, EventArgs e)
        {
            //find pipe segment sizes
        }
    }
}

 

 

here is code for the plugin:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.DB.Plumbing;

namespace DynamoToRevitPlugin
{
    [Transaction(TransactionMode.Manual)]
    class PipeCreation : IExternalCommand
    {
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            //need to select elements before

            // Get the handle of current document
            UIDocument uidoc = commandData.Application.ActiveUIDocument;
            Document doc = uidoc.Document;
            Autodesk.Revit.ApplicationServices.Application app = doc.Application;

            // reference the form
            PipeCreationForm form = new PipeCreationForm(commandData);


            


            // Get the element selection of current document.
            Selection selection = uidoc.Selection;
            ICollection<ElementId> selectedIds = uidoc.Selection.GetElementIds();

            //check if selction is empty
            if (0 == selectedIds.Count)
            {
                // If no elements selected.
                TaskDialog.Show("Revit", "Select Columns Before Running Plugin.");
            }
            else
            {
                if (form.ShowDialog() == DialogResult.OK)
                {
                    //gets the level from form
                    ElementId slvlId = null;
                    if (form.sLevel.SelectedIndex > -1)
                    {
                        slvlId = (form.sLevel.SelectedItem as Level).Id;
                    }


                    //gets the system type from form
                    ElementId sysTypeId = null;
                    if (form.pSysType.SelectedIndex > -1)
                    {
                        sysTypeId = (form.pSysType.SelectedItem as PipingSystemType).Id;
                    }


                    //gets the pipe type from form
                    ElementId pTypeId = null;
                    if (form.pType.SelectedIndex > -1)
                    {
                        pTypeId = (form.pType.SelectedItem as PipeType).Id;
                    }

                    using (Transaction tx = new Transaction(doc))
                    {
                        tx.Start("Create Pipes");

                        List<XYZ> points = new List<XYZ>();
                        List<ElementId> elemLi = new List<ElementId>();
                        foreach (ElementId elemId in selectedIds)
                        {
                            Element elem = uidoc.Document.GetElement(elemId);

                            //bounding box around solid
                            BoundingBoxXYZ elemBB = elem.get_BoundingBox(doc.ActiveView);
                            //gets center of bounding box
                            XYZ bbCentroid = (elemBB.Max + elemBB.Min) / 2;
                            //add centroid points to list
                            points.Add(bbCentroid);
                            elemLi.Add(elemId);
                        }

                        
                        foreach (XYZ pt in points)
                        {
                            XYZ closestPoint = null;
                            foreach (XYZ point2 in points) //loop to find closest point
                            {
                                if(pt != point2)
                                {
                                    if (closestPoint == null)
                                    {
                                        closestPoint = point2;
                                    }
                                    if (pt.DistanceTo(point2) < pt.DistanceTo(closestPoint))
                                    {
                                        closestPoint = point2;
                                    }
                                }  
                            }
                            Pipe pipe = Pipe.Create(doc, sysTypeId, pTypeId, slvlId, pt, closestPoint);
                        }
                        tx.Commit();
                    }
                }
            }
            return Result.Succeeded;
        }
    }
}
0 Likes
Accepted solutions (1)
1,140 Views
1 Reply
Reply (1)
Message 2 of 2

jeremy_tammik
Alumni
Alumni
Accepted solution

The answer is easy and has been discussed many times, both here and by The Building Coder:

 

A modal form displayed by ShowDialog must be closed before the thread can continue and the external command complete.

 

https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.form.showdialog?view=net-5.0

 

A modeless form displayed by the Show method runs in a separate thread and can continue running even after 

the external command completes:

 

https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.form.show?view=net-5.0

 

The modeless form, being in a separate thread, has no access to the single-threaded Revit API.

 

So, it is easy to keep your form open, but you will have to change the way you interact with the Revit API.

 

The most common (and maybe the only clean) way to achieve that is to use an external event.

 

Lots more on that topic:

 

https://thebuildingcoder.typepad.com/blog/about-the-author.html#5.28

  

 

 

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