Set a new XYZ position to FamilyInstance through an EventRegisterHandler or IUpdater

Set a new XYZ position to FamilyInstance through an EventRegisterHandler or IUpdater

mathieu.josserand
Contributor Contributor
686 Views
4 Replies
Message 1 of 5

Set a new XYZ position to FamilyInstance through an EventRegisterHandler or IUpdater

mathieu.josserand
Contributor
Contributor

Hi,

I would like to create a tracker that when it detects a new FamilyInstance element created by the user, the tracker can apply an automatic translation of XYZ(-30,0,0).
In other words, I want to change the position of this instance.

 

Here is some code I have retrieved, which detects the new elements. Only, I can't manage to apply a transaction to apply a new XYZ location.

 

Thank you for you answers 🙂

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;
using System.Windows.Forms;

namespace TestScript
{
    [TransactionAttribute(TransactionMode.Manual)]
    public class EventRegistrationInModelessDialogViaExternalEvent 
        : IExternalCommand
    {
        public Document doc;
        public Autodesk.Revit.ApplicationServices.Application RevitApp;
        ExternalEvent _exEvent;
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            EventRegisterHandler _exeventHander = new EventRegisterHandler();
            _exEvent = ExternalEvent.Create(_exeventHander);
            MyForm form = new MyForm();
            form.ExEvent = _exEvent;
            form.Show();

            return Result.Succeeded;
        }
    }

    public class MyForm : System.Windows.Forms.Form
    {
        public MyForm()
            : base()
        {
            Button btn = new Button();
            btn.Text = "Toggle DocumentChanged Event Registration";
            btn.Click += btn_Click;
            btn.Width = 250;
            this.Controls.Add(btn);
        }

        public ExternalEvent ExEvent { get; set; }

        void btn_Click(object sender, EventArgs e)
        {
            if (ExEvent != null)
                ExEvent.Raise();
            else
                MessageBox.Show("external event handler is null");
        }
    }

    public class EventRegisterHandler : IExternalEventHandler
    {
        public bool EventRegistered { get; set; }
        public void Execute(UIApplication app)
        {
            if (EventRegistered)
            {
                EventRegistered = false;
                app.Application.DocumentChanged -= Application_DocumentChanged;
            }
            else
            {
                EventRegistered = true;
                app.Application.DocumentChanged += Application_DocumentChanged;
            }
        }

        void Application_DocumentChanged(object sender, 
            Autodesk.Revit.DB.Events.DocumentChangedEventArgs e)
        {
            var sb = new StringBuilder();
            var added = "added:" + e.GetAddedElementIds()
                .Aggregate("", (ss, el) => ss + "," + el).TrimStart(',');
            var modified = "modified:" + e.GetModifiedElementIds()
                .Aggregate("", (ss, el) => ss + "," + el).TrimStart(',');
            var deleted = "deleted:" + e.GetDeletedElementIds()
                .Aggregate("", (ss, el) => ss + "," + el).TrimStart(',');
            sb.AppendLine(added);
            sb.AppendLine(modified);
            sb.AppendLine(deleted);
            TaskDialog.Show("Changes", sb.ToString());
            
            //
            // Task To Achieve : move the fresh fi to new position
            //
            Document doc = e.GetDocument();
            Element element = doc.GetElement(e.GetAddedElementIds().First());

            if(element is FamilyInstance)
            {
                FamilyInstance fi = element as FamilyInstance;
                // Set new position
                XYZ translation = new XYZ(-30, 0, 0);
                using (Transaction t = new Transaction(doc))
                {
                    t.Start("t");
                    ElementTransformUtils.MoveElement(doc, fi.Id, translation);
                    t.Commit();
                }
            }
        }

        public string GetName()
        {
            return "EventRegisterHandler";
        }
    }
}

 

0 Likes
687 Views
4 Replies
Replies (4)
Message 2 of 5

RPTHOMAS108
Mentor
Mentor

You are not actually using IUpdater you are instead using IExternalEventHandler to subscibe to the DocumentChangedEvent.

 

You should not make changes to the document in response to DocumentChangedEvent instead use IUpdater. So follow SDK samples where IUpdater is used and then any further questions that arise from that process can be answered.

 

...\Samples\ScheduleAutomaticFormatter\CS

...\Samples\RebarFreeForm\CS

...\Samples\WinderStairs\CS

...\Samples\DynamicModelUpdate\CS

...\Samples\AnalysisVisualizationFramework\MultithreadedCalculation\CS

 

Why do you want to move an element by 30ft anyway?

0 Likes
Message 3 of 5

mathieu.josserand
Contributor
Contributor

I aim to supply the modeler with a "smarter" mouse that adjusts some positions according to the surrounding elements. 30ft is a trivial example to make sure the process works.

Yeah, I've tried with IUpdater in the code below...
I want a form with 2 buttons ON/OFF to start or to stop the IUpdater's track...


When I execute the code below I got this error message : " Updater :: getUpdaterId() :: getAddInId() does not march currently active add-in's AddInId"

using System;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;

namespace HelloWord
{
    [TransactionAttribute(TransactionMode.Manual)]
    public class c_Start : IExternalCommand
    {
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            try
            {
                Document doc = commandData.Application.ActiveUIDocument.Document;
                Form1 f = new Form1(commandData.Application);
                f.Show();
                return Result.Succeeded;
            }
            catch (Exception e)
            {
                //Unique affichage d'erreur dans tout le projet
                f_Error errorProcess = new f_Error(e.Message);
                errorProcess.ShowDialog();

                return Result.Cancelled; //On annule la transaction en cours
            }
        }
    }

    public class Watcher : IUpdater
    {
        Document doc;
        AddInId m_appId;
        public UpdaterId m_updaterId { get; set; }
    
        public Watcher(Document d, AddInId id)
        {
            doc = d;
            m_updaterId = new UpdaterId(id, new Guid("d42d28af-d2cd-4f07-8873-e7cfb61903d8"));

            RegisterUpdater();
            RegisterTriggers();
        }
        public void Execute(UpdaterData data)
        {
            Document doc = data.GetDocument();
            TaskDialog.Show("Revit", "Just say hello if you detect new Element then Try to move the Element (XYZ)");
        }

        void RegisterUpdater()
        {
            if (UpdaterRegistry.IsUpdaterRegistered(m_updaterId, doc))
            {
                UpdaterRegistry.RemoveAllTriggers(m_updaterId);
                UpdaterRegistry.UnregisterUpdater(m_updaterId, doc);
            }
            UpdaterRegistry.RegisterUpdater(this, doc);
        }
        void RegisterTriggers()
        {
            if (m_updaterId != null && UpdaterRegistry.IsUpdaterRegistered(m_updaterId))
            {
                UpdaterRegistry.RemoveAllTriggers(m_updaterId);
                UpdaterRegistry.AddTrigger(m_updaterId,
                    new ElementCategoryFilter(
                        BuiltInCategory.OST_ElectricalFixtures), Element.GetChangeTypeGeometry());
            }
        }
        public string GetAdditionalInformation()
        {
            return "AdditionalInformation str";
        }

        public ChangePriority GetChangePriority()
        {
            return ChangePriority.FloorsRoofsStructuralWalls;
        }

        public UpdaterId GetUpdaterId()
        {
            return m_updaterId;
        }

        public string GetUpdaterName()
        {
            return "NewElementTracker";
        }
    }

    public partial class Form1 : System.Windows.Forms.Form
    {
        public Document doc { get; set; }
        public UIApplication uiapp { get; set; }

        bool m_open;
        Watcher updater;
        AddInId id;
        public Form1(UIApplication a)
        {
            InitializeComponent();
            m_open = false;
            uiapp = a;
            doc = a.ActiveUIDocument.Document;
            id = uiapp.Application.ActiveAddInId;
        }

        // Button 1 : ON : Start tracking
        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                if (!m_open)
                {
                    m_open = true;
                    // Start tracker ...
                    updater = new Watcher(doc, id);
                    //ERROR : Updater :: getUpdaterId() :: getAddInId() does not march currently active add-in's AddInId
                }
            }
            catch 
            {
                UpdaterRegistry.RemoveAllTriggers(updater.m_updaterId);
                UpdaterRegistry.UnregisterUpdater(updater.m_updaterId, doc);
                updater = null;
            }
        }
        //Button 2 : OFF : Stop tracking
        private void button2_Click(object sender, EventArgs e)
        {
            if (m_open)
            {
                m_open = false;
                UpdaterRegistry.RemoveAllTriggers(updater.m_updaterId);
                UpdaterRegistry.UnregisterUpdater(updater.m_updaterId, doc);
                updater = null;
            }
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (m_open)
            {
                m_open = false;
                UpdaterRegistry.UnregisterUpdater(updater.GetUpdaterId());
                updater = null;
            }
        }
    }
}

 

0 Likes
Message 4 of 5

RPTHOMAS108
Mentor
Mentor

I don't see a clear reason why it wouldn't work (you seem to pass the id through) but I don't register updaters this way.

 

Far easier to register your updater during IExternalApplication.OnStartUp, not when you show the form. 

 

Then to enable or disable during session you can use:

 

UpdaterRegistry.DisableUpdater
UpdaterRegistry.EnableUpdater
UpdaterRegistry.IsUpdaterEnabled

 

Note that if your IUpdater has been suspended due to causing an error then for that session EnableUpdater will not enable it.

 

I think your issue stems from the fact you are using a modeless form with IExternalCommand rather than with IExternalEventHandler, you are holding onto old objects such as Document and UIApplication.

0 Likes
Message 5 of 5

mathieu.josserand
Contributor
Contributor

Btw Thanks for answering me !

 

I've also tried the IExternalApplication.OnStartUp solution (through Revit macro), it worked

but I want this process as a external addin and not as a macro (for UX purposes)

 

I ensure that the Document and UIApplication objects are not null, I need to check if it same objects...

 

I'll keep digging

0 Likes