Raise External evenHandler when user drawing new Pipe

Raise External evenHandler when user drawing new Pipe

jose_loaiza5W6L6
Contributor Contributor
477 Views
5 Replies
Message 1 of 6

Raise External evenHandler when user drawing new Pipe

jose_loaiza5W6L6
Contributor
Contributor

Hello everybody

I'm new to developing with Revit API, I have some requests where I need to detect when the user is drawing or edit a pipe. I have an approach using externalEventHandler to detect if there is new pipe; however, this is not working. this is my code

 

 

 

public class UpdatePipeSlopeHandler : IExternalEventHandler
{
    public List<ElementId> ElementIdsToUpdate { get; set; } = new List<ElementId>();
    public void Execute(UIApplication app)
    {
        try
        {
            Document doc = app.ActiveUIDocument.Document;
            PipeHandler.HandlePipes(doc, ElementIdsToUpdate, "A pipe has been modified.");
        }
        catch (Exception ex)
        {
            TaskDialog.Show("Error", $"An error occurred: {ex.Message}");
        }
    }

    public string GetName() => "Update Pipe Slope Handler";
}

///The principal class
    [Transaction(TransactionMode.Manual)]
    public class Class1 : IExternalApplication
    {
        private UIApplication _uiApp;
        private UpdatePipeSlopeHandler _handler;
        private ExternalEvent _externalEvent;

   public Result OnStartup(UIControlledApplication application)
   {
_handler = new UpdatePipeSlopeHandler();
_externalEvent = ExternalEvent.Create(_handler);
application.ControlledApplication.DocumentChanged += new EventHandler<DocumentChangedEventArgs>(OnDocumentChanged);
return Result.Succeeded;
}

///documentChancge
 private void OnDocumentChanged(object sender, Autodesk.Revit.DB.Events.DocumentChangedEventArgs e)
{
     Document doc = e.GetDocument();
     ICollection<ElementId> addedElementIds = e.GetAddedElementIds();
     _handler.ElementIdsToUpdate = addedElementIds.ToList();
     foreach (ElementId id in addedElementIds)
     {
         Element element = doc.GetElement(id);
         if (element is Pipe)
         {
             TaskDialog.Show("raiseeven", "event raise");
             _externalEvent.Raise();
         }
     }
}


     


 

 

 

As you can see i try to raise the externalEvenHandler when the user drawing new pipe and document change, the line 48 is executed however the externalevenHandler in this case (UpdatePipeSlopeHandler) never doesn't lunch.

 

Have you some ideas what Im missing or somethin wrong in my code.

 

Thank you for you help

Jose Loaiza

0 Likes
Accepted solutions (1)
478 Views
5 Replies
Replies (5)
Message 2 of 6

Moustafa_K
Collaborator
Collaborator

It looks like there might be a small issue with your code. Here’s a quick tip to help you out:

  1. Current Approach: Right now, it seems like you’re registering all added elements to the handler, then checking if they’re pipes during the DocumentChanged event. But when you raise the external event, you’re looping through all added elements, not just the pipes.

  2. What You Can Do: First, filter out the elements to get just the pipes. Register only these pipes with your event handler and then raise the event. This way, you’ll avoid processing elements that aren’t pipes.

  3. Watch Out for Re-triggers: Raising the event might cause the DocumentChanged event to trigger again because you’re changing the document. To prevent any loops or issues, you could use a flag to check if your code is already processing. Something like this:

 

 

 

    public class UpdatePipeSlopeHandler : IExternalEventHandler
        {
            public List<ElementId> ElementIdsToUpdate
            {
                get;
                set;
            } = new List<ElementId>();
            public void Execute(UIApplication app)
            {
                try
                {
                    Document doc = app.ActiveUIDocument.Document;
                    PipeHandler.HandlePipes(doc, ElementIdsToUpdate, "A pipe has been modified.");
                }
                catch (Exception ex)
                {
                    TaskDialog.Show("Error", $ "An error occurred: {ex.Message}");
                }
                finally
                {
                    isProcessing = false;
                }

                public string GetName() => "Update Pipe Slope Handler";
            }

            private static bool isProcessing = false;

            private void OnDocumentChanged(
                object sender,
                Autodesk.Revit.DB.Events.DocumentChangedEventArgs e
            )
            {
                if (isProcessing)
                    return;

                try
                {
                    isProcessing = true;

                    Document doc = e.GetDocument();
                    ICollection<ElementId> addedElementIds = e.GetAddedElementIds();
                    List<ElementId> pipes = new();
                    foreach (ElementId id in addedElementIds)
                    {
                        Element element = doc.GetElement(id);
                        if (element is Pipe)
                        {
                            pipes.Add(element);
                        }
                    }
                    if (pipes.Any())
                    {
                        TaskDialog.Show("raiseeven", "event raise");
                        _handler.ElementIdsToUpdate = pipes; // Register only the pipes
                        _externalEvent.Raise(); // Trigger the event
                    }
                    else
                    {
                        isProcessing = false;
                    } catch
                {
                    isProcessing = false;
                }
            } finally {

            }
        }

 

 

 

 

Moustafa Khalil
Cropped-Sharp-Bim-500x125-Autodesk-1
0 Likes
Message 3 of 6

ricaun
Advisor
Advisor
Accepted solution

For what you are trying to do the IUpdater would work better. Removing the need to use DocumentChanged and IExternalEventHandler.

 

You can register a IUpdater to trigger when a pipe is created/changed and run a custom code.

 

Take a look in the document, there is a example for Wall.

 

Or a quick sample using your code PipeHandler.HandlePipes.

 

public class PipeUpdater : IUpdater
{
    private UpdaterId updaterId;
    public PipeUpdater(AddInId id, Guid guid)
    {
        updaterId = new UpdaterId(id, guid);
    }
    public void Execute(UpdaterData data)
    {
        var doc = data.GetDocument();
        PipeHandler.HandlePipes(doc, data.GetAddedElementIds(), "A pipe has been modified.");
        PipeHandler.HandlePipes(doc, data.GetModifiedElementIds(), "A pipe has been modified.");
    }
    public string GetUpdaterName() => "PipeUpdater";
    public string GetAdditionalInformation() => "PipeUpdater";
    public ChangePriority GetChangePriority() => ChangePriority.MEPCalculations;
    public UpdaterId GetUpdaterId() => this.updaterId;
}

 

You probably need to remove the Transaction in the PipeHandler.HandlePipes method, the IUpdater does not require a Transaction.

 

 

Luiz Henrique Cassettari

ricaun.com - Revit API Developer

AppLoader EasyConduit WireInConduit ConduitMaterial CircuitName ElectricalUtils

0 Likes
Message 4 of 6

jose_loaiza5W6L6
Contributor
Contributor

Hi Ricaun Thank you so much for your answer, I think that approach works; however,, I have another question: which ChangeType I should use when I add the Trigger? I have this line of code

 

UpdaterRegistry.AddTrigger(new PipeUpdater(appId).GetUpdaterId(), filter, Element.GetChangeTypeElementAddition());

 

But when the user updated the pipe the updater does not execute.

 

 

 

 

 

0 Likes
Message 5 of 6

ricaun
Advisor
Advisor

You need to add another trigger to trigger modify like:

 

 

  • Change of element geometry (shape or position) - via Element.GetChangeTypeGeometry()
  • Changing value of a specific parameter - via Element.GetChangeTypeParameter()
  • Any change of element - via Element.GetChangeTypeAny().

 

This if from the documentation:

 

Using the GetChangeTypeAny would do the trick.

var pipeUpdater = new PipeUpdater(appId);
UpdaterRegistry.AddTrigger(pipeUpdater.GetUpdaterId(), filter, Element.GetChangeTypeElementAddition());
UpdaterRegistry.AddTrigger(pipeUpdater.GetUpdaterId(), filter, Element.GetChangeTypeAny());

 

 

Luiz Henrique Cassettari

ricaun.com - Revit API Developer

AppLoader EasyConduit WireInConduit ConduitMaterial CircuitName ElectricalUtils

0 Likes
Message 6 of 6

jose_loaiza5W6L6
Contributor
Contributor

Hello guys  thank you so much for your answers, it's been very helpful.

 

Best regards

0 Likes