Revit API Forum
Welcome to Autodesk’s Revit API Forums. Share your knowledge, ask questions, and explore popular Revit API topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Inconsistent Idling Event Handling with Command Binding for Dynamic Updaters

10 REPLIES 10
SOLVED
Reply
Message 1 of 11
Sean_Page
1251 Views, 10 Replies

Inconsistent Idling Event Handling with Command Binding for Dynamic Updaters

I am using a few different Dynamic Updaters in an application, one of which is listening for new Reference Planes to request that users name them. However, when someone wants to "Edit Profile" for a wall, Revit creates one or more Reference Planes to complete the task.  With other Updaters I have successfully bound the CommandId to an EventHandler to Disable the updaters and remove the command binding, which would also add an IdlingEvent to reenable the updater and the command binding.

 

Now, this works PERFECTLY when I apply it to a View Updater during Synchronization or ReloadLatest, but for the Edit Profile command I can bind the command, disable the updater, but then it won't let me actually call the PostCommand for the EditProfile command.

 

Working Example for binding to the Reload Latest command (ID_WORKSETS_RELOAD_LATEST):

1. Bind the Command OnStartup:

        public Result OnStartup(UIControlledApplication application)
        {
            AddCommandBindings(application, "ID_WORKSETS_RELOAD_LATEST");
AddCommandBindings(application, "ID_EDIT_ELEVATION_SKETCH");
RegisterUpdaters(application); return Result.Succeeded; }

2. The AddCommandBindings code:

private Result AddCommandBindings(UIControlledApplication application, string name)
        {
            RevitCommandId rCommandId = RevitCommandId.LookupCommandId(name);
            if (rCommandId.CanHaveBinding)
            {
                try
                {
                    if (name == "ID_INPLACE_COMPONENT")
                    {
                        application.CreateAddInCommandBinding(rCommandId).Executed += new EventHandler<ExecutedEventArgs>(this.DisableCommand);
                    }
                    else if (name == "ID_WORKSETS_RELOAD_LATEST")
                    {
                        application.CreateAddInCommandBinding(rCommandId).Executed += new EventHandler<ExecutedEventArgs>(this.ReloadLatestUpdaters);
                    }
                    else if (name == "ID_EDIT_ELEVATION_SKETCH")
                    {
                        application.CreateAddInCommandBinding(rCommandId).Executed += new EventHandler<ExecutedEventArgs>(this.EditProfileUpdaters);
                    }
                }
                catch
                {
                    MessageBox.Show("Command " + name + " is already bound.");
                }
            }
            return Result.Succeeded;
        }

3. The ReloadLatestUpdaters call

private void ReloadLatestUpdaters(object sender, ExecutedEventArgs args)
        {
            UIDocument uiDoc = new UIDocument(args.ActiveDocument);
            DisableUpdaters(ControlID.application, "all");
            uiDoc.Application.RemoveAddInCommandBinding(args.CommandId);
            ControlID.application.Idling += new EventHandler<IdlingEventArgs>(ReloadLatest_Idling);
            uiDoc.Application.PostCommand(args.CommandId);
        }

4. The ReloadLatest_Idling call

private void ReloadLatest_Idling(object sender, IdlingEventArgs args)
        {
            EnableUpdaters(ControlID.application, "all");
            AddCommandBindings(ControlID.application, "ID_WORKSETS_RELOAD_LATEST");
            ControlID.application.Idling -= ReloadLatest_Idling;
        }

5. The EnableUpdaters call

internal static Result EnableUpdaters(UIControlledApplication application, string name)
        {
            try
            {
                if (name == "view" || name == "all")
                {
                    Updaters.ViewUpdater viewUpdater = new Updaters.ViewUpdater(application.ActiveAddInId);
                    UpdaterRegistry.EnableUpdater(viewUpdater.GetUpdaterId());
                }

                if (name == "grid" || name == "all")
                {
                    Updaters.GridUpdater gridUpdater = new Updaters.GridUpdater(application.ActiveAddInId);
                    UpdaterRegistry.EnableUpdater(gridUpdater.GetUpdaterId());
                }

                if (name == "reference" || name == "all")
                {
                    Updaters.ReferencePlaneUpdater refUpdater = new Updaters.ReferencePlaneUpdater(application.ActiveAddInId);
                    UpdaterRegistry.EnableUpdater(refUpdater.GetUpdaterId());
                }

                if (name == "sheets" || name == "all")
                {
                    Updaters.ViewSheetUpdater sheetUpdater = new Updaters.ViewSheetUpdater(application.ActiveAddInId);
                    UpdaterRegistry.EnableUpdater(sheetUpdater.GetUpdaterId());
                }

                return Result.Succeeded;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(),"Error",MessageBoxButtons.OK,MessageBoxIcon.Error);
                return Result.Failed;
            }
        }

Now, I attempt to do almost the EXACT same thing for the EditProfile Command:

1 & 2 See Code Above.

 

3. The code for the EditProfileUpdaters call

private void EditProfileUpdaters(object sender, ExecutedEventArgs args)
        {
            UIDocument uiDoc = new UIDocument(args.ActiveDocument);
            DisableUpdaters(ControlID.application, "all");
            uiDoc.Application.RemoveAddInCommandBinding(args.CommandId);
            ControlID.application.Idling += new EventHandler<IdlingEventArgs>(EditProfile_Idling);
            uiDoc.Application.PostCommand(args.CommandId);
        }

4. The EditProfile_Idling call

private void EditProfile_Idling(object sender, IdlingEventArgs args)
        {
            MessageBox.Show("Idling Event Added");
            EnableUpdaters(ControlID.application, "all");
            AddCommandBindings(ControlID.application, "ID_EDIT_ELEVATION_SKETCH");
            ControlID.application.Idling -= EditProfile_Idling;
        }

5. Same Call as Above to Enable updaters

 

I may just be missing something simple as that tends to be the case, but why is there different behavior here? As you can see, the code is essentially identical, but it seems like the Idling event is being called BETWEEN adding the IdlingEvent and the PostCommand which is interrupting the PostCommand (Edit Profile) and keeping it from working? Could this be because the Edit Profile command needs a selection so it isn't working as I would expect?  As you can see from the video, I am getting all the way to the "Idling Event Added" message in the Idling event call.

 

Thanks in Advance for any suggestions or comments!

10 REPLIES 10
Message 2 of 11
jeremytammik
in reply to: Sean_Page

Dear Sean,

 

Thank you for your interesting (and impressive) query.

 

First of all, congratulations on setting up this tricky system so it works in most cases.

 

Secondly, what video are you talking about?

 

Third, it seems to me that we will have to pass this on to the development team, and they will require a complete, minimal, reproducible case in order to analyse and debug the behaviour live, and also to verify that any potential fixes they can apply do actually solve the problem:

 

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

 

Can you provide that as well?

 

Thank you.

 

Best regards,

 

Jeremy

 



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

Message 3 of 11
Sean_Page
in reply to: jeremytammik

Jeremy,

Thanks for your response. I missed the "Insert" for the screencast on my first posting.

 

 

I will work to package up a small test case from my larger application, I was hoping it was something simple I was missing!

Message 4 of 11
Sean_Page
in reply to: jeremytammik

Jeremy,

I have created a small app that reproduces the results I am seeing when testing. How do I get this to the dev team? As an attachment on this forum, or in a different way?

 

Thank you!

Message 5 of 11
jeremytammik
in reply to: Sean_Page

Dear Sean,

 

Yes, sure, attaching a zip file containing the reproducible case to this thread is perfect.

 

App in a state ready for compilation and debugging, minimal sample model, expected behaviour, problem observed and exact steps for reproducing the problem will help.

 

Thank you.

 

Best regards,

 

Jeremy

 



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

Message 6 of 11
Sean_Page
in reply to: jeremytammik

Thanks again, I have included a .zip file with a model, a solution folder, and a txt document with observations and expectations. Please let me know if you require additional information or files.

Message 7 of 11
jeremytammik
in reply to: Sean_Page

Dear Sean,

 

Thank you for the reproducible case.

 

I logged the issue REVIT-149311 [Inconsistent Idling Event Handling with Command Binding for Dynamic Updaters -- 15488603] with our development team for this on your behalf as it requires further exploration and possibly a modification to our software. Please make a note of this number for future reference.

 

You are welcome to request an update on the status of this issue or to provide additional information on it at any time quoting this change request number.

 

This issue is important to me. What can I do to help?

 

This issue needs to be assessed by our engineering team and prioritised against all other outstanding change requests. Any information that you can provide to influence this assessment will help. Please provide the following where possible:

 

  • Impact on your application and/or your development.
  • The number of users affected.
  • The potential revenue impact to you.
  • The potential revenue impact to Autodesk.
  • Realistic timescale over which a fix would help you.
  • In the case of a request for a new feature or a feature enhancement, please also provide detailed Use cases for the workflows that this change would address.

 

This information is extremely important. Our engineering team have limited resources, and so must focus their efforts on the highest impact items. We do understand that this will cause you delays and affect your development planning, and we appreciate your cooperation and patience.

 

Best regards,

 

Jeremy

 



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

Message 8 of 11
jeremytammik
in reply to: Sean_Page

Dear Sean,

 

Thank you for your patience.

 

The development team analysed the issue REVIT-149311 [Inconsistent Idling Event Handling with Command Binding for Dynamic Updaters -- 15488603] and respond:

 

The original command is bound with the customised EditProfileUpdaters.

 

After clicking "Edit Profile" button, we see message boxes indicating that the binding is working.

 

In EditProfileUpdaters, it tries to relaunch the "Edit Profile" command and fails with the exception:

 

  ' 1:< API_ERROR {  Autodesk.Revit.Exceptions.ArgumentException exception(The commandId must be in Autodesk.Revit.UI.PostableCommand or an external command.
    'Parameter name: commandId) was thrown from a handler of Executed event. The API event handler was registered by application ADSK Testing (b382ad39-6349-449a-97a3-5e2ac9eeb517). Changes made by this handler are going to be discarded. }

   

"ID_EDIT_ELEVATION_SKETCH" is not listed by PostableCommand.

 

This is why the profile editor doesn't appear.

 

I hope this answer helps solve the problem.

 

Best regards,

 

Jeremy

 



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

Message 9 of 11
Sean_Page
in reply to: jeremytammik

Jeremy,

Thanks for the follow up, I now see a little "try" block could have saved me some time, but I guess I just assumed that since I could bind to the command I could also post it similar to the Reload Latest.

 

Is PostCommand the only way of calling a built in command? Can you access or "press" a button by cycling the buttons on a panel / tab?

Message 10 of 11
jeremytammik
in reply to: Sean_Page

Dear Sean,

 

PostCommand is the only official way of calling a built-in command, supported by the Revit API.

 

Yes, you can indeed access or 'press' a button by cycling the buttons on a panel / tab using the .NET Automation library.

 

Here are a whole bunch of discussions of unsupported workarounds implemented using that:

 

https://thebuildingcoder.typepad.com/blog/automation

 

I hope you find a viable reliable solution. Looking forward to hearing how you end up solving it.

 

Thank you!

 

Best regards,

 

Jeremy

 



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

Message 11 of 11
ankofl
in reply to: jeremytammik

Dear Jeremy, Earlier it was written that "ID_EDIT_ELEVATION_SKETCH" is not listed by Portable Command. In this case, how, using the standard Revit API, without application.NET Automation, can I click on the  "Edit Profile" wall button?

ankofl_0-1684503238307.png

and press this "Green Button" after ?

ankofl_0-1684503524077.png

@jeremytammik 

 

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Forma Design Contest


Rail Community