Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DYN-6377: Restrict where OnNodeModified is called. #14656

Merged
merged 4 commits into from
Dec 4, 2023

Conversation

twastvedt
Copy link
Contributor

@twastvedt twastvedt commented Nov 29, 2023

Purpose

REVIT-215698 & https://jira.autodesk.com/browse/DYN-6377

#14122 fixed an issue where setting a dropdown's value (the SelectedIndex property) programatically didn't cause the node to recompute (OnNodeModified never called, so AST never rebuilt). However, Revit selection nodes change the node's value in BuildOutputAst (populate items and update SelectedIndex), causing an infinite loop. (It's surprising to me that it's ok to modify the node's value in BuildOutputAst. Is this something other nodes do?)

This PR moves the call to OnNodeModified up to UpdateValueCore, which is what is called when changing the node's value programatically, reducing the impact of #14122 and preventing the crash.

Declarations

Check these if you believe they are true

  • The codebase is in a better state after this PR
  • Is documented according to the standards
  • The level of testing this PR includes is appropriate
  • User facing strings, if any, are extracted into *.resx files
  • All tests pass using the self-service CI.
  • Snapshot of UI changes, if any.
  • Changes to the API follow Semantic Versioning and are documented in the API Changes document.
  • This PR modifies some build requirements and the readme is updated
  • This PR contains no files larger than 50 MB

Release Notes

Fix a crash when using Dynamo for Revit dropdown nodes.

Reviewers

(FILL ME IN) Reviewer 1 (If possible, assign the Reviewer for the PR)

(FILL ME IN, optional) Any additional notes to reviewers or testers.

FYIs

(FILL ME IN, Optional) Names of anyone else you wish to be notified of


private void SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (comboBox.SelectedIndex != -1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't -1 actually a valid value ? Unless it is not allowed to clear the current selection here or in a subclass.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you want to avoid introducing the field, I think the sender will be the combobox.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, I need the field anyways for Dispose though.

@@ -106,7 +106,6 @@ public int SelectedIndex
selectedString = GetSelectedStringFromItem(Items.ElementAt(value));
}

OnNodeModified();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it fair to say that an api dev should not call this function and use updatemodelvaluecommand instead ? otherwise the node will not be marked as modified. Perhaps make the set internal at some point in the future ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, we need to be able to set SelectedIndex from the Revit dropdown nodes. I guess it could be protected. But maybe there are other situations where you want to be able to set the value without triggering updates?

@@ -203,6 +202,8 @@ protected override bool UpdateValueCore(UpdateValueParams updateValueParams)
Warning(Dynamo.Properties.Resources.NothingIsSelectedWarning);
}

OnNodeModified();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this function called when SelectedIndex property is set to a different value?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No it's not

Copy link
Contributor

@aparajit-pratap aparajit-pratap Nov 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I didn't get it then, how does moving OnNodeModified here work in that case?

Copy link
Contributor

@aparajit-pratap aparajit-pratap Nov 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When exactly is UpdateValueCore called in this case?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I see, by moving it out of SelectedIndex, you are avoiding chances of an infinite loop, since SelectedIndex is changed in PopulateItems, which is incidentally called here: https://github.com/DynamoDS/DynamoRevit/blob/a1c5384651133ebab113dd0abfef5bd256ef51f0/src/Libraries/RevitNodesUI/GenericClasses.cs#L194 inside the BuildOutputAst function, am I right?
I think I would agree that calling PopulateItems in BuildOutputAst is a bad idea in the first place.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct.
Since it's been that way for a while (7 years!), perhaps we could fix it back to working as it did before #14122 and look at improving in a separate task?

@mjkkirschner
Copy link
Member

@twastvedt can a regression test be written for this or only in DSRevit?

@twastvedt
Copy link
Contributor Author

@twastvedt can a regression test be written for this or only in DSRevit?

I think we don't need DSRevit. We'd just need a test nodeModel that subclasses DSDropdownBase and modifies the selected value in its BuildOutputAst implementation. I guess a stack-overflow exception in a test might cause some downstream issues? But we'll know!

Though, if as @aparajit-pratap suggests, we shouldn't really be allowing this (updating node value in BuildOutputAst) in the first place, should I just put the time for a test into a follow-up task to remove the option of doing what the DSRevit dropdowns do? (Make SelectedIndex call OnNodeModified, and find an alternative to updating the node value in DSRevit's BuildOutputAst.)

@mjkkirschner
Copy link
Member

@twastvedt can a regression test be written for this or only in DSRevit?

I think we don't need DSRevit. We'd just need a test nodeModel that subclasses DSDropdownBase and modifies the selected value in its BuildOutputAst implementation. I guess a stack-overflow exception in a test might cause some downstream issues? But we'll know!

Though, if as @aparajit-pratap suggests, we shouldn't really be allowing this (updating node value in BuildOutputAst) in the first place, should I just put the time for a test into a follow-up task to remove the option of doing what the DSRevit dropdowns do? (Make SelectedIndex call OnNodeModified, and find an alternative to updating the node value in DSRevit's BuildOutputAst.)

  1. I think it's fine to merge this as is - and file a followup for either adding a test or restricting the API somehow... though I'm not sure how that would work.
  2. I think the idea in this PR is sound, but if you inspect the other UpdateValueCore overrides it's not clear to me that each of them will trigger OnNodeModified (it only makes sense in some cases of course) - but it would be nice to unify these or somehow communicate what updates will trigger graph executions for API clients.
  3. Speaking of followups ... if this is the code we are shipping, I'd prefer a test sooner rather than later, followup testing tasks have a habit of never being done - so perhaps mark it higher priority?

@twastvedt
Copy link
Contributor Author

@twastvedt twastvedt merged commit f1f9b74 into master Dec 4, 2023
29 checks passed
@twastvedt twastvedt deleted the REVIT-215698-dropdown-crash branch December 4, 2023 21:15
@saintentropy saintentropy changed the title REVIT-215698: Restrict where OnNodeModified is called. DYN-6377: Restrict where OnNodeModified is called. Dec 8, 2023
saintentropy pushed a commit to saintentropy/Dynamo that referenced this pull request Mar 14, 2024
* Restrict where OnNodeModified is called.

* Clean up.

* Dispose

* No SuppressFinalize

(cherry picked from commit f1f9b74)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants