Cant understand how external event works.

Cant understand how external event works.

Anonymous
Not applicable
4,315 Views
3 Replies
Message 1 of 4

Cant understand how external event works.

Anonymous
Not applicable

Hi everyone I am new to the Forum and to programming as well I work with dynamo to accomplish most of my required tasks and now diving into programming and C#,so kindly bear with me if my questions are so primitive.

 

I am trying to create a form that can import a sketch up model into my revit file for further development.

I  am Stuck with the error that says " Cannot access transaction outside API context" and with other posts and forum I understand that the Revit API lives in a special thread and can be accessed via other thread.. 

 

Here is what I have done :

 

SKP_importer.cs file:

 

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

namespace Skp2Rvt
{
    [Transaction(TransactionMode.Manual)]

    [Regeneration(RegenerationOption.Manual)]

    public class SKP_Importer : IExternalCommand
    {
        public static Document doc;
        public static Application uiapp;
        public static UIDocument UIdoc;

        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            var app = commandData.Application;
            uiapp = app.Application;
            UIdoc = app.ActiveUIDocument;
            doc = UIdoc.Document;

            var UIF = new Form1();
            UIF.Show();

            return Result.Succeeded;
        }

        public void AddSkp(string file)
        {
            using (Transaction ts = new Transaction(doc, "test"))
            {
                var optionSKP = new SKPImportOptions();
                {
                    Transaction trans = new Transaction(doc, "Import SKP file");
                    trans.Start();
                    var ActiveView = doc.ActiveView;
                    var SKP_File_Id = doc.Import(file, optionSKP, ActiveView);
                    var SKP_file = doc.GetElement(SKP_File_Id);
                    var list = new List<ElementId>();
                    list.Add(SKP_File_Id);
                    UIdoc.Selection.SetElementIds(list);
                    trans.Commit();
                }
            }
        }

    }
   //
   //Here Iam trying to create an external command that can be called from my form button.
   // the biggest problem is i am not able to add overload parameters to the methods.
    
    public class Addfile : IExternalEventHandler
    {
        public void Execute(UIApplication app)
        {
            using (Transaction ts = new Transaction(doc, "test"))
            {
                var optionSKP = new SKPImportOptions();
                {
                    Transaction trans = new Transaction(doc, "Import SKP file");
                    trans.Start();
                    var ActiveView = doc.ActiveView;
                    var SKP_File_Id = doc.Import(file, optionSKP, ActiveView);
                    var SKP_file = doc.GetElement(SKP_File_Id);
                    var list = new List<ElementId>();
                    list.Add(SKP_File_Id);
                    UIdoc.Selection.SetElementIds(list);
                    trans.Commit();
                }
            }
        }

        public string GetName()
        {
            throw new NotImplementedException();
        }
    }
}

 

 

Form1 file :

 

 

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;

namespace Skp2Rvt
{
    public partial class Form1 : Form
    {
        public string FileLocation = "";
        public Form1()
        {
            InitializeComponent();
        }

        private void BrowseButton_Click(object sender, EventArgs e)
        {
            // Create OpenFileDialog
            Microsoft.Win32.OpenFileDialog openFileDlg = new Microsoft.Win32.OpenFileDialog();

            var result = openFileDlg.ShowDialog();

            if (result == true)
            {
                FileName.Text = openFileDlg.FileName;
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            FileLocation = FileName.Text;
            var skp = new SKP_Importer();
            skp.AddSkp(FileLocation);
            
        }
    }
}

 

 

Creating a external event was a smaller problem and the biggest problem is that Iam not able to add parameters to my methods in the external command.

 

please help me complete this.

 

0 Likes
Accepted solutions (1)
4,316 Views
3 Replies
Replies (3)
Message 2 of 4

RPTHOMAS108
Mentor
Mentor
Accepted solution

The below files within the samples folder of the SDK below should be your starting point, I make bold the objects that fit the description of your task best.

 

https://www.autodesk.com/developer-network/platform-technologies/revit

 

These files contain content of 'IExternalEvent'
...\Samples\WinderStairs\CS\WinderUpdater.cs
...\Samples\PostCommandWorkflow\CS\PostCommandRevisionMonitor.cs
...\Samples\ModelessDialog\ModelessForm_ExternalEvent\CS\RequestHandler.cs
...\Samples\GetSetDefaultTypes\CS\DefaultElementTypes.xaml.cs
...\Samples\DockableDialogs\CS\ExternalEvents\APIExternalEventHandler.cs

 

This file from SDK contains content of 'Interlocked.Exchange' (passing objects via arguments in threadsafe way).
...\Samples\ModelessDialog\ModelessForm_ExternalEvent\CS\RequestHandler.cs

 

Note that more recently alternative approaches have been put forward and perhaps you would eventually find those preferable:

 

https://thebuildingcoder.typepad.com/blog/2020/03/another-async-await-rex-and-structural-analysis-sd...

 

0 Likes
Message 3 of 4

Anonymous
Not applicable

Thank you so much, I dint Understand this initially I had to read about concepts of external events and how it works to make it work, thanks for pointing me in the right direction.! 

 

I am attaching the code here just in case if you or anybody else can show me a shorter way of doing this.

 

 

 

namespace Skp2Rvt
{
    [Transaction(TransactionMode.Manual)]

    [Regeneration(RegenerationOption.Manual)]

    public class SKP_Importer_command : IExternalCommand
    {
        public static Document doc = null;
        public static UIApplication application = null;

        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            IExternalEventHandler handler_event = new SkpImporter_EventHandler();

            ExternalEvent exEvent
              = ExternalEvent.Create(handler_event);

            application = commandData.Application;
            doc = application.ActiveUIDocument.Document;
            var form = new Form1(exEvent);
            form.Show();
            return Result.Succeeded;
        }
    }

    public class SkpImporter_EventHandler : IExternalEventHandler
    {
        public void Execute(UIApplication uiapp)
        {
            UIDocument uidoc = uiapp.ActiveUIDocument;
            if (null == uidoc)
            {
                return; // no document, nothing to do
            }
            Document doc = uidoc.Document;
            using (Transaction tx = new Transaction(doc,"My event"))
            {
                try
                {
                    Transaction trans = new Transaction(doc, "Import SKP file");
                    trans.Start();
                    var optionSKP = new SKPImportOptions();
                    var ActiveView = doc.ActiveView;
                    var file = Form1.FileLocation;
                    var SKP_File_Id = doc.Import(file, optionSKP, ActiveView);
                    var SKP_file = doc.GetElement(SKP_File_Id);
                    var list = new List<ElementId>();
                    list.Add(SKP_File_Id);
                    uidoc.Selection.SetElementIds(list);
                    trans.Commit();
                }
                catch
                {
                    TaskDialog.Show("Error", "Something went wrong with the import,please check the version of SKP file.");
                }
            }
        }
        public string GetName()
        {
            return "my event";
        }
    }
}

 

 

0 Likes
Message 4 of 4

Kennan.Chen
Advocate
Advocate

I created the Revit.Async library to make the use of external event natural. In the repository I also prepared some material about how external event works and how Revit.Async handle the job.

 

 Hope it helps.

 

KennanChan/Revit.Async: Use task-based asynchronous pattern (TAP) to run Revit API code from any exe...