We have a need to report the project parameters that are defined in a project, as part of a Quality Assurance tool on which we are working.
While Revit apparently won't let you create two (non-shared) project parameters with the same, case-sensitive name, for some reason it WILL let you add two Shared Parameters with identical, case-sensitive names provided they have each have different GUIDs.
Each of those parameters may be of the same or different types, in the same or different groups, and associated with the same or different categories. So yes, you could have two parameters with identical names appear in the same group of the properties pane for an element, right next to each other.
So for us to accurately report the project parameters that are defined, we have to differentiate between the two definitions. However, those definitions may be identical with the only difference (we can tell) being the shared parameter GUIDs.
But there doesn't seem to be a way to ask for the GUID of a project parameter with the API, not even when we try to resort to using Reflection. Every time we try casting the DefinitionBiningMapIterator.Key to ExternalDefinition we get null, even for parameters we know by testing are shared. It always casts to InternalDefinition, but never to ExternalDefinition. So not only can we not seem to get the GUID, there doesn't seem to be a way to even tell if it's a shared parameter or not in the first place.
What are we missing? Is there some other API methods we simply haven't found yet to get this information? How can we accurately report how the project parameters were defined by the user in the GUI?
Thanks very much for any assistance you can provide.
Solved! Go to Solution.
Solved by CoderBoy. Go to Solution.
This code does appear to work *IF* none of the project parameters are already bound to the ProjectInformation category before it starts to run.
Basically, for example, this line:
if (!cats.Contains(pi.Category))
{
....
}
has no else clause to handle that situation.
What we eventually need to do is report which categories are associated with each project parameter (name & GUID if shared) or (name if not shared, in which case there can be only 1 with that name that is not shared).
So just reporting name-GUID combinations isn't enough, we also need to report which categories go with each exact parameter definition. So it needs to be precise.
The attached project file presents this situation. Each project parameter (shared or not) is bound to both the Project Information category and the Rooms category. Again, I'm having issues getting things unbound cleanly.
However, I have another thought. What if I pre-save the definitions (ala the MyData approach), then using temporary, rolled back transactions, iterate over that list for each item, deleting all but the one project parameter of interest, bind it to the ProjectInformation category (if it isn't already) and then query the ProjectInformation object for the parameter by name?
So I may try that next. Not sure what will happen to the objects in my list if I delete their parent definitions, though. I won't be needing them during the deleted time, so maybe that will work.
(Yes, there are built-in Project Information parameters like "Organization Name" whereby if I added my own Project Parameter with that name, it could be a duplicate in the Project Information object as well, not sure if I can filter those out by BuiltInParameter or not...I'll try to cross that bridge if I can get to it)
SOLUTION ATTACHED.
The code discussed thus far seems to work correctly for all situations except when there is a shared project parameter that is a type parameter.
The API reports that a shared project type parameter binds successfully to the ProjectInformation category, but the associated Parameter does not actually exist in the Project Information object's Parameters collection. This makes some sense, because you can't bind any project parameters (shared or not) that are type parameters to the Project Information category in the Revit GUI. (So in this case the API wrongly reports the binding is successful)
The approach outlined thus far uses a known "singleton" (the ProjectInformation element) which works for instance parameters. So I extended that approach (when needed) to use a known "singleton" (the first Wall Type element, as there must always be at least one) which works for type parameters.
Attached is a text file with C# snippets that reasonably nicely packages all of the code needed to accurately collect information about project parameters, whether or not they are shared, and if shared what their GUIDs are.
Again, many many thanks to Scott Wilson and Ning Zhou for their ideas and code snippets to help solve this problem!
Dear CoderBoy, Scott and Ning,
from me as well.
Thank you very much for your impressive perseverance and for sharing the complete solution with us all!
I'll try to give it a whirl and preserve it for posterity in The Building Coder if you like.
Cheers,
Jeremy
Hi Jeremy.
It was good to see you at AU a couple of weeks ago! (I got the books we talked about, and plan to start reading them very soon over the holidays)
If it could be useful to others, I am happy to share this code on your blog.
Dear CoderBoy,
Oops.
Two years have passed, and it has not been published yet.
I hope you liked the books. No idea any longer what they may have been.
Anyway, this issue is coming up again, repeatedly,, e.g. here, raised by CoderBoy himself:
So maybe a blog post really would be in order, still.
Can you provide a minimal reproducible case for me to test the code in?
Actually, probably a detailed script would be sufficient, explaining the exact script to create a suitable parameter and test accessing and doing something to it.
Better still, of course, a complete minimal reproducible case, if that is not too much to ask:
http://thebuildingcoder.typepad.com/blog/about-the-author.html#1b
Could you provide that?
Thank you very much!
Cheers,
Jeremy
Greetings Jeremy.
Note that my other forum posting, while is also in regards to project parameters, isn't really related the the problem of getting the shared parameter GUIDs from project parameters.
I have sent to you an e-mail with code for a working Revit Command which shows how to get the GUIDs for project parameters. You can feel free to share or publish this code as best you see fit on your blog site.
Regards.
Finally got around to publishing this:
http://thebuildingcoder.typepad.com/blog/2015/12/shared-project-parameter-guid-reporter.html
Thank you very much, CoderBoy, Scott and Ning!
Cheers,
Jeremy
So it's been 5 years since this problem was originally posed, is this still the only way to get the GUID from a project parameter? It seems a little convoluted to get at information that is clearly already there.
Why do these parameters report back as Internal when they're clearly created from ExternalDefinitions? This seems like somewhat of a glaring oversight based on how parameters are supposed to work. I've also never quite understand why the Defintion object isn't the one storing the GUID, it would make far more sense to me since the definition is what already stores the other information about the parameter like it's name and storage type, it doesn't make any sense for the parameter object to have half of its identity data come from the definition and the other half come from the parameter itself, when all of it comes from it is ultimately coming from the definition.