Setting Parameter Varies Between Groups
Originally Published inWe already looked at the topic of setting the SetAllowVaryBetweenGroups
flag on a shared parameter in Scott Conover’s parameter definition overview.
The setting was introduced in the Revit 2014 API, cf. Parameter variance among group instances.
Now Miroslav Schonauer raised it again, asking:
Question: Is the following option for group behaviour of shared param instance bindings exposed to API?
If yes, that solves all the issues :-)
If not – the default outcome seems to be aligned per group type.
Is there any way to set can vary by group instance (what I need) the default for API-created bindings?
Later: I found this Revit API discussion forum ↗ thread on creating a project parameter with values can vary by group instance selected ↗ which explains that it is kind-of possible.
The problem remains that SetAllowVaryBetweenGroups
is available only on InternalDefinition
, while my programmatically created shared param has ExternalDefinition
.
That thread explains that getting the binding after it has been created (i.e., in a ‘Step 2’) does return InternalDefinition
, so this method can be used.
Can someone at least confirm that there is nothing simpler to do than the above 2-step process?
Answer: Yes. You need to do the two-step process:
- Register the shared parameter
- Find the internal definition
- Set the appropriate value for this property
The easiest way to go from one to the other:
Response: I implemented this method to handle the setting of the SetAllowVaryBetweenGroups
flag:
/// <summary>
/// Helper method to control `SetAllowVaryBetweenGroups`
/// option for instance binding param
/// </summary>
static void SetInstanceParamVaryBetweenGroupsBehaviour(
Document doc,
Guid guid,
bool allowVaryBetweenGroups = true )
{
try // last resort
{
SharedParameterElement sp
= SharedParameterElement.Lookup( doc, guid );
// Should never happen as we will call
// this only for *existing* shared param.
if( null == sp ) return;
InternalDefinition def = sp.GetDefinition();
if( def.VariesAcrossGroups != allowVaryBetweenGroups )
{
// Must be within an outer transaction!
def.SetAllowVaryBetweenGroups( doc, allowVaryBetweenGroups );
}
}
catch { } // ideally, should report something to log...
}
It assumes that guid
comes from a known shared parameter.
Further good news: this can be called not only immediately after programmatically binding a new shared param, but also to silently change this specific setting for an existing shared parameter.
For example, we all typically have our own helper methods to get-or-create a shared parameter binding, cf., e.g., my method to add a category to a shared parameter binding.
Here is a code snippet providing enough to get the gist of how the above can be used (ignore my helper classes and error handling):
// Assumes outer transaction
public static Parameter GetOrCreateElemSharedParam(
Element elem,
string paramName,
string grpName,
ParameterType paramType,
bool visible,
bool instanceBinding,
bool userModifiable,
Guid guid,
bool useTempSharedParamFile,
string tooltip = "",
BuiltInParameterGroup uiGrp = BuiltInParameterGroup.INVALID,
bool allowVaryBetweenGroups = true )
{
try
{
// Check if existing
Parameter param = elem.LookupParameter( paramName );
if( null != param )
{
// NOTE: If you don't want forcefully setting
// the "old" instance params to
// allowVaryBetweenGroups =true,
// just comment the next 3 lines.
if( instanceBinding && allowVaryBetweenGroups )
{
SetInstanceParamVaryBetweenGroupsBehaviour(
elem.Document, guid, allowVaryBetweenGroups );
}
return param;
}
// If here, need to create it (my custom
// implementation and classes…)
BindSharedParamResult res = BindSharedParam(
elem.Document, elem.Category, paramName, grpName,
paramType, visible, instanceBinding, userModifiable,
guid, useTempSharedParamFile, tooltip, uiGrp );
if( res != BindSharedParamResult.eSuccessfullyBound
&& res != BindSharedParamResult.eAlreadyBound )
{
return null;
}
// Set AllowVaryBetweenGroups for NEW Instance
// Binding Shared Param
if( instanceBinding )
{
SetInstanceParamVaryBetweenGroupsBehaviour(
elem.Document, guid, allowVaryBetweenGroups );
}
// If here, binding is OK and param seems to be
// IMMEDIATELY available from the very same command
return elem.LookupParameter( paramName );
}
catch( Exception ex )
{
System.Windows.Forms.MessageBox.Show(
string.Format(
"Error in getting or creating Element Param: {0}",
ex.Message ) );
return null;
}
}
I added Miro’s method SetInstanceParamVaryBetweenGroupsBehaviour
to The Building Coder samples release 2018.0.134.11 ↗ in the module CmdCreateSharedParams.cs L441-L470 ↗.
Many thanks to Miro for raising this issue and sharing his approach to solve it!