Unpin Command Binding - Ribbon vs Toggle

Sean_Page
Collaborator
Collaborator

Unpin Command Binding - Ribbon vs Toggle

Sean_Page
Collaborator
Collaborator

After a string of unfortunate events, I am trying to bind to the Unpin command to ask users are they sure they want to unpin the element. This is working great when I bind to the "ID_UNLOCK_ELEMENTS" command.

 

However, if the element is locked, and then a users toggles it with the visual "pin" in the view, the bound event does not fire.  So, I think looked and found that the Command Id for that was actually different. So, I check and it said that it allows binding as well, bound to it using the same method and event, however nothing fires when the toggle is clicked.

 

Anyone have any idea why it would be acting different?

 

startup:

AddCommandBindings(application, "ID_UNLOCK_ELEMENTS");
AddCommandBindings(application, "ID_PIN_CTRL_TOGGLE");

 

Method:

private void AddCommandBindings(UIControlledApplication application, string name)
		{
			RevitCommandId rCommandId = RevitCommandId.LookupCommandId(name);
			if(rCommandId.CanHaveBinding)
			{
				try
				{
					switch(name)
					{
						case "ID_UNLOCK_ELEMENTS":
							application.CreateAddInCommandBinding(rCommandId).Executed += new EventHandler<ExecutedEventArgs>(DisableCommand);
							break;
						case "ID_PIN_CTRL_TOGGLE":
							application.CreateAddInCommandBinding(rCommandId).Executed += new EventHandler<ExecutedEventArgs>(UnPinToggle);
							break;
						case "ID_INPLACE_COMPONENT":
							application.CreateAddInCommandBinding(rCommandId).Executed += new EventHandler<ExecutedEventArgs>(DisableCommand);
							break;
						case "ID_FILE_IMPORT":
							application.CreateAddInCommandBinding(rCommandId).Executed += new EventHandler<ExecutedEventArgs>(DisableCommand);
							break;
						case "ID_WORKSETS_RELOAD_LATEST":
							application.CreateAddInCommandBinding(rCommandId).Executed += new EventHandler<ExecutedEventArgs>(ReloadLatestUpdaters);
							break;
						default:
							break;
					}

				}
				catch
				{
					MessageBox.Show("Command " + name + " is already bound.");
				}
			}
		}

 

Event (Essentially just presents a dialog tot he user with the command info and why they shouldn't be doing what they are doing, general utility):

		private void DisableCommand(object sender, ExecutedEventArgs args)
		{
			using(Forms.RevitPostCommandForm rpc = new Forms.RevitPostCommandForm(args.CommandId))
			{
				if(rpc.ShowDialog() == DialogResult.OK)
				{
					ControlParams.postCommand = args.CommandId.Name;
					UIDocument uiDoc = new UIDocument(args.ActiveDocument);
					uiDoc.Application.RemoveAddInCommandBinding(args.CommandId);
					ControlParams.application.Idling += new EventHandler<IdlingEventArgs>(PostCommand_Idling);
					idleCheck = false;
					uiDoc.Application.PostCommand(args.CommandId);
				}
			}
		}
Sean Page, AIA, NCARB, LEED AP
Partner, Computational Designer, Architect
0 Likes
Reply
1,121 Views
17 Replies
Replies (17)

ricaun
Advisor
Advisor

That's interesting... I create a test plugin to look at how this command binding works.
And I was not able to make the toggle binding work.


How did you get the ID_PIN_CTRL_TOGGLE name? I was trying to find the PostableCommand related to this lock/unlock toggle and it does not exist on the Revit API.

ID_PIN_CTRL_TOGGLE 	 34967	PostableCommand.????
ID_UNLOCK_ELEMENTS 	 33001	PostableCommand.Unpin

Maybe it's not possible to add the binding command on this toggle event.

 

Should an IUpdater with the BuiltInParameter.ELEMENT_LOCKED_PARAM works better, to prevent unlocking the elements.

Should be annoying to add on each type of element but should work.

Gonna make some tests...

Luiz Henrique Cassettari

ricaun.com - Revit API Developer

AppLoader EasyConduit WireInConduit ConduitMaterial CircuitName ElectricalUtils

Sean_Page
Collaborator
Collaborator

Thanks @ricaun, I found that ID in the journal files. If you use the CanHaveBinding it says true, as does Has binding after, but it doesn't fire.

 

I also did look at using the locked param in an updated as that was my go-to, however using that param specifically as a param trigger doesn't work, but it does initiate the AnyChange trigger. So, I didn't want to try and use an any change and check for the param on all elements, or I'd like not to anyways.

 

And yes, it would also mean a lot of categories, which I'm not sure I'm keen on either for performance.

Sean Page, AIA, NCARB, LEED AP
Partner, Computational Designer, Architect

Sean_Page
Collaborator
Collaborator

I also tried this with a category filter as well and neither worked for me.

Updaters.ElementUnpinUpdater PinnedUpdater = new Updaters.ElementUnpinUpdater(application.ActiveAddInId);
UpdaterRegistry.RegisterUpdater(PinnedUpdater, true);
ElementClassFilter wallFilter = new ElementClassFilter(typeof(Wall));				UpdaterRegistry.AddTrigger(PinnedUpdater.GetUpdaterId(), wallFilter, Element.GetChangeTypeParameter(new ElementId(BuiltInParameter.ELEMENT_LOCKED_PARAM)));

 

Sean Page, AIA, NCARB, LEED AP
Partner, Computational Designer, Architect

ricaun
Advisor
Advisor

I'm not able to trigger the ELEMENT_LOCKED_PARAM parameter on the updater too.

 

I'm using the invert option to make all the category to trigger.

new ElementCategoryFilter(BuiltInCategory.INVALID, true);

And I tested with the ALL_MODEL_INSTANCE_COMMENTS and works fine.

Element.GetChangeTypeParameter(new ElementId(BuiltInParameter.ALL_MODEL_INSTANCE_COMMENTS))

The instance comments work fine but the locked parameter still does not trigger.

 

I also try to set the trigger on each valid BuiltInParameter.

var values = Enum.GetValues(typeof(BuiltInParameter)).Cast<BuiltInParameter>();
var changeTypes = values.Select(e => Element.GetChangeTypeParameter(new ElementId(e))).ToArray();

On the updater, I'm using the IsChangeTriggered to check each BuiltInParameter to find what makes the updater activate.

public void Execute(UpdaterData data)
{
    var document = data.GetDocument();
    var ids = new List<ElementId>();
    ids.AddRange(data.GetModifiedElementIds());
    var elements = ids.Select(id => document.GetElement(id));
    var values = Enum.GetValues(typeof(BuiltInParameter)).Cast<BuiltInParameter>();
    foreach (var element in elements)
    {
        Console.WriteLine($"{element.Id}");
        foreach (var value in values)
        {
            var isChange = data.IsChangeTriggered(element.Id, Element.GetChangeTypeParameter(new ElementId(value)));
            if (isChange)
                Console.WriteLine($"{element.Id} {value} {isChange}");
        }
    }
}

Works fine with all parameters I tested the only exception is the ELEMENT_LOCKED_PARAM parameter that does not trigger for some reason.

 

I tested on Revit 2018, 2021 and 2023 and nothing I tried makes the ELEMENT_LOCKED_PARAM updater to trigger.

 

Maybe is a bug...

 

 

Luiz Henrique Cassettari

ricaun.com - Revit API Developer

AppLoader EasyConduit WireInConduit ConduitMaterial CircuitName ElectricalUtils

Sean_Page
Collaborator
Collaborator

@jeremytammik any chance we could get the Dev team to weigh in here?

Sean Page, AIA, NCARB, LEED AP
Partner, Computational Designer, Architect
0 Likes

jeremy_tammik
Autodesk
Autodesk

Sure thing. I asked them whether they can take a look at this thread in its current state or whether I need to raise a ticket for them to analyse in more depth. Can you reformulate and reduce the issue to the bare minimal problem in a succinct form and possibly add a minimal reproducible case with step by step description for them to analyse, so they don't have to read and understand the entire discussion above? Thank you!

 

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

Sean_Page
Collaborator
Collaborator

I have attached a minimal reproducible case project.

 

This case includes two updaters both firing on walls to make it simple.

1. Updater 1 should be firing against the BuiltInParameter.ELEMENT_LOCKED_PARAM

    A. This does NOT work

2. Updater 2 should be firing against the BuiltInParameter.ALL_MODEL_MARK

    A. This DOES work

 

spage_0-1656417370636.png

 

spage_1-1656418089422.png

 

 

Sean Page, AIA, NCARB, LEED AP
Partner, Computational Designer, Architect
0 Likes

RPTHOMAS108
Mentor
Mentor

Did you get the result you expect from below line of your code:

 

RevitCommandId rCommandId = RevitCommandId.LookupCommandId(name);

 

i.e. why wasn't the below used instead:

 

public static RevitCommandId LookupPostableCommandId(PostableCommand postableCommand)

 

Assuming you are going to need to post the command if user selects ok then the command needs to be both post-able and bind-able. Most things outside of the ribbon can't be posted.

 

I've not reviewed the updater approach yet, I would assume that should work but some parameter changes have been known not to trigger the updater. Not sure execute method of IUpdater should be used to interact with user however i.e. ask user what to do next (updater should know what to do and do it transparently).

 

You can post pin and unpin it seems but the state of the selected element should be found i.e. on the Ribbon it is a toggle but there are two separate post-able commands.

0 Likes

Sean_Page
Collaborator
Collaborator

Not exactly sure what you mean by "expected result" of my code. As shown, I am successfully using that to bind to several commands without any issue. This one states that is it bindable, and that the biding is happening, but then then doesn't do anything when the command is run.

 

The other event handlers are how I am proceeding with posting the actual command if user selects OK.

 

1. Bind to Command.

    A. Execution Event to Handle Command

    B. Idling Event within Execution to handle a "YES" response

3. Ask User "Are you Sure"

    A. If user says NO, then nothing happens

    B. If user says Yes

        1. Unbind Command

        2. Submit Command

       3. Idling Event to rebind after Command Executed normally

        3. Rebind Command with Event

 

I guess in short, my code works as intended (doesn't mean its the best :)) for other command bindings on a similar nature, and works as intended when the ribbon "Pin" is pressed, just not the Graphical UI pin within the view.

Sean Page, AIA, NCARB, LEED AP
Partner, Computational Designer, Architect

RPTHOMAS108
Mentor
Mentor

Was wondering specifically if you got a command id back when you looked for it by name:

"ID_PIN_CTRL_TOGGLE"

Was the binding created?

 

Regardless it doesn't appear in post-able command enum so I wouldn't think you could post it even if it fires the command binding event. Although you could perhaps find the current state of the element(s) and post the pin/unpin on the main UI, or change parameter.

Sean_Page
Collaborator
Collaborator

Yes, I get Id that are different, and it states it can be bound.

 

spage_0-1656422956319.png

 

The Journal files are also showing that the binding is successful:

 

' 0:< API_SUCCESS { Replacing command id 'ID_UNLOCK_ELEMENTS' Executed implementation with implementation from application 'Testing' dll 'C:\ProgramData\Autodesk\Revit\Addins\2022\PinnedUpdater.dll'. }
' 0:< API_SUCCESS { API registering command Allow change of element position
'Unpin Executed event by application Testing (2b51409d-cb10-4a88-8a59-f94b6324847c). }
' 0:< API_SUCCESS { Replacing command id 'ID_PIN_CTRL_TOGGLE' Executed implementation with implementation from application 'Testing' dll 'C:\ProgramData\Autodesk\Revit\Addins\2022\PinnedUpdater.dll'. }
' 0:< API_SUCCESS { API registering command Prevent or allow change of element position
'Toggle Pin
'&Toggle Pin Executed event by application Testing (2b51409d-cb10-4a88-8a59-f94b6324847c). }

Sean Page, AIA, NCARB, LEED AP
Partner, Computational Designer, Architect

ricaun
Advisor
Advisor

@Sean_Page and @jeremy_tammik

 

I gonna create a separate Topic related to the IUpdater problem. So this topic could focus on the Binding Command problem.

 

I create an application and test a lot of things and found some problems not only with the ELEMENT_LOCKED_PARAM not triggering.

 

Here is the application: https://github.com/ricaun-io/RevitAddin.UpdaterTester/

Luiz Henrique Cassettari

ricaun.com - Revit API Developer

AppLoader EasyConduit WireInConduit ConduitMaterial CircuitName ElectricalUtils

jeremy_tammik
Autodesk
Autodesk

OK. Sorry to hear that there appear to be some issues in this area. Let's see what the development team say about this thread, and point out the new one and possibly raise a ticket with them once you have done some research and started a new separate thread for that. Thank you very much for that!

  

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

jeremy_tammik
Autodesk
Autodesk

The devteam confirmed some weirdness and are exploring further. Thank you very much for raising this!

  

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

ggranadosNFAMX
Contributor
Contributor

Hi all, is there any update to this issue, I have been testing a Hook code for "ID_PIN_CTRL_TOGGLE" Command Id, but nothing happens when the pin toggle is pressed.

Thank You!

dgoff96
Enthusiast
Enthusiast

I'm also interested in a solution to this. I'm running into the same issue and I definitely think that designers use the graphic "Pin" toggle more than the ribbon button.

0 Likes

Sean_Page
Collaborator
Collaborator

Running into more issues related to bindings and thought I'd ask to see if there were any updates on this topic?

 

I am now trying to bind to the Viewport Activated / Deactivated commands which work AS LONG as it's done through the Right Click Context menu. The Double Click In/Out of the Viewport doesn't fire the command for binding although the journal shows that it is. 

Sean Page, AIA, NCARB, LEED AP
Partner, Computational Designer, Architect
0 Likes