Get Name of Family Type Parameter Associated to Nested Family Instance

Get Name of Family Type Parameter Associated to Nested Family Instance

rvtquestions
Advocate Advocate
3,896 Views
17 Replies
Message 1 of 18

Get Name of Family Type Parameter Associated to Nested Family Instance

rvtquestions
Advocate
Advocate

For simplicity of explanation, I will use an example of a Family of a Radio with (2) speaker outputs, (1) on the left and (1) on the right. The Radio Family has a nested Speaker Family called "SP" with individual types "SP1, SP2, SP3, etc." the "SP" instance on the left is controlled by a Family Type Parameter "LEFT" and the "SP" instance on the right is controlled by a Family Type Parameter "RIGHT" so that once loaded in the project a radio could be composed of different "SP" types switched out such as a Radio made up as (SP1) L (SP1) R, (SP1) L (SP2) R, (SP2) L (SP2) R and the combos go on....

RADIO.png

My question is once this family is loaded and placed, when I select an instance of the Speaker "SP" (not the whole radio but one speaker) is there a method in the Revit API to know which Family Type Parameter it is associated to?

For example, if I select the right speaker instance of a radio, how can I via the API return which Family Type Parameter it is controlled by, in this case "RIGHT"?

 

While I can (Radio Family Instance).Symbol.LookUpParameter("RIGHT") & ("LEFT") of the main radio family and see which types are assigned, this will become tricky when the same type of "SP" is assigned to both.

 

Additionally, I suppose if in the family, the speakers were individually hosted to named reference planes, one could retrieve the name of the reference plane the instance is on, however, I would like to make this operational for all families that may not be set up this way.

 

Any suggestions? Thank you.

0 Likes
3,897 Views
17 Replies
Replies (17)
Message 2 of 18

Moustafa_K
Collaborator
Collaborator

yes there is a away to get the parent family for this.

 

ElementId ParentFamilyinstanceId = myspeaker.SuperComponent() 

if you used the method SuperComponent it will get you the element Id of the parent Family.

 

and by then you can get the current symbol used via

 

var myfamily = doc.GetElement(ParentFamilyinstanceId) as FamilyInstance;
var typename = myfamily.Symbol.Name;

 

 

can you clarify more this statement

Additionally, I suppose if in the family, the speakers were individually hosted to named reference planes, one could retrieve the name of the reference plane the instance is on, however, I would like to make this operational for all families that may not be set up this way.

 

Hope this helps.

Moustafa Khalil
Cropped-Sharp-Bim-500x125-Autodesk-1
0 Likes
Message 3 of 18

rvtquestions
Advocate
Advocate

Thank you @Moustafa_K for your reply. I do know about Super Components and Sub Components. I think you misunderstood my intent or I was not clear enough. I am not looking for the Family Type name but the Family, Family Type Parameter (there is a very specific difference). As shown in my image above, there are (2) Family Type Parameters with names "LEFT" and "RIGHT" those are the names I want to acquire from an instance associated to it.

 

For example if there is a family Radio with (2) nested speakers. In your example if I selected a nested speaker and got its supercomponent symbol name it would return the Radio's Type name. What I want is if I selected the nested speaker, to know whether it is the one controlled by the "LEFT" or "RIGHT" family type parameter.

 

To elaborate on the reference plane explanation. Suppose in the family editor the left nested speaker was snapped and hosted to a ref plane named "LEFT" and the right nested speaker was snapped and hosted to a ref plane named "RIGHT"...then in the project I suppose you can get what reference plane the instance is hosted on and distinguish that way. But as stated, that is not the method I'd like to go for.

0 Likes
Message 4 of 18

Moustafa_K
Collaborator
Collaborator

Ok now I got what you mean... can you share your family sample... I will do some tests on it

Moustafa Khalil
Cropped-Sharp-Bim-500x125-Autodesk-1
0 Likes
Message 5 of 18

BenoitE&A
Collaborator
Collaborator

Hey,

Mostafa did not say it but I would definitely start by using Revit LookUp. There you will see the way to navigate between your family and its nested families and then to the parameters of both...


Benoit FAVRE
CEO of etudes & automates
www.etudesetautomates.com/
0 Likes
Message 6 of 18

Moustafa_K
Collaborator
Collaborator

indeed that is the most fast effective way to do it. the point there is different ways to define nested family, within the parentone. and that is why i asked for the family document file.

for instance, I have this family which declares two type of sinks (top and embedded) it is designed to be switched via visibility within a Family type (Family type A shows bottom, B shows top). so the parameter here was integer.

 

any how so glad you figured it out.

Capture.PNG

Moustafa Khalil
Cropped-Sharp-Bim-500x125-Autodesk-1
0 Likes
Message 7 of 18

rvtquestions
Advocate
Advocate

You are absolutely correct in mentioning Revit LookUp, which I have already snooped. I cannot seem to find any way to the Family Type Parameter.

 

Just to clear things up again...

With all due respect,@Moustafa_K  you seem to keep misunderstanding the parameter I am after. I believe there is only one type of Family Type Parameter. While you can control visibility and such of items through formulas or numbers, a Family, Family Type parameter controls the type of instance that is chosen. It is not a number, string, unit, etc... it is a choice of types available for the instance category. When you are in a family editor environment and select an instance of a nested family, it is the Label: assigned to it.

RADIO_NEST_LABEL.pngRADIO_NEW_NEST_LABEL.png

 

I haven't tested in the API yet but in dynamo a quick getparameterbyname "Label" does not return anything and again I couldn't seem to find anything about it in RevitLookUp (but I may be wrong).

0 Likes
Message 8 of 18

Moustafa_K
Collaborator
Collaborator

I do understand but may be i was not clear on my explanation:

just check this out as an example, isn't this the parameter you are after

 

Family DocumentFamily DocumentProject documentProject document

Moustafa Khalil
Cropped-Sharp-Bim-500x125-Autodesk-1
0 Likes
Message 9 of 18

Moustafa_K
Collaborator
Collaborator

so you can get this parameter via this

var familytypeparameters = famins.Parameters.Cast<Parameter>().Where(p=>p.Definition.ParameterType == ParameterType.FamilyType)
Moustafa Khalil
Cropped-Sharp-Bim-500x125-Autodesk-1
0 Likes
Message 10 of 18

rvtquestions
Advocate
Advocate

Again, thank you for your contribution. As mentioned I have not used the LookUp extensively so I may have missed a path when searching. I will give your suggestion a try and let you know!

0 Likes
Message 11 of 18

rvtquestions
Advocate
Advocate

In your example, are you able to get the name "My Sink" from the family instance?

 

I've ran a few tests including:

e being the family instance

var ftype = e.Parameters.Cast<Parameter>().Where(p => p.Definition.ParameterType.Equals(ParameterType.FamilyType));
TaskDialog.Show("FT Count", ftype.Count().ToString());

Which displays 0

 

Another test (Both as instance and Type (e.Symbol.Parameters)):

foreach (Parameter p in e.Parameters)
{
TaskDialog.Show("Parameter", p.AsString());
}

Runs through a number of parameters but none show the Family Type Parameter.

0 Likes
Message 12 of 18

Moustafa_K
Collaborator
Collaborator

is your label PArameter assigned as instance type or Element Type?

if Element type you need to update your code to get the familyinstance type first then loop through its parameters

 

Moustafa Khalil
Cropped-Sharp-Bim-500x125-Autodesk-1
0 Likes
Message 13 of 18

rvtquestions
Advocate
Advocate

Not sure if you read my response but as I've stated I've iterated both instance and type....using e.Parameters and e.Symbol.Parameters. Can you confirm on your side that you are able to retrieve "My Sink" from an instance?

 

In the case of casting :

 

var ftype = e.Symbol.Parameters.Cast<Parameter>().Where(p => p.Definition.ParameterType.Equals(ParameterType.FamilyType));

From ftype, how does one get the name?

0 Likes
Message 14 of 18

Moustafa_K
Collaborator
Collaborator

@rvtquestions Yes all the below statements are working fine for me

var para = e.LookupParameter("My Sink");
var paras = e.Parameters.Cast<Parameter>().Where(o => o.Definition.ParameterType == ParameterType.FamilyType); var paras = e.Parameters.Cast<Parameter>().Where(o => o.Definition.ParameterType.Equals(ParameterType.FamilyType));
Moustafa Khalil
Cropped-Sharp-Bim-500x125-Autodesk-1
0 Likes
Message 15 of 18

BenoitE&A
Collaborator
Collaborator

Hey,

Just in case, the Lookup method is easier to use than casting the parameters and checking the name.

var ftype = e.Symbol.Lookup("myName");

 


Benoit FAVRE
CEO of etudes & automates
www.etudesetautomates.com/
0 Likes
Message 16 of 18

rvtquestions
Advocate
Advocate

My followup question still remains unanswered.

 

In your case:

var para = e.LookupParameter("My Sink");
var paras = e.Parameters.Cast<Parameter>().Where(o => o.Definition.ParameterType == ParameterType.FamilyType);

The first method would depend on the user knowing which Parameter Name to look up, I am looking for the Parameter Name from the family instance. And even if the user knew which parameter to look up, again if there were more than one family type parameters using the same instance, for example "My Sink" assigned to Family 1 and "My Sink 2" assigned to Family 1 as well, if you took an instance of Family 1 and looked up the parameter "My Sink" or "My Sink 2" it would both return Family 1 and you wouldn't be able to distinguish between the two.

 

The Second example, I am still unsure what to do with paras. After you declare paras, how do you get the name of the parameter casted?

0 Likes
Message 17 of 18

FAIR59
Advisor
Advisor

Your only option is to change a familyType parameter temporary , and see which subComponent changes.

In macro form:    (macro finds type-parameters , not instance parameters)

public ICollection<ElementId> SubComponentsInInstance;
public ElementId SubComponentByParameter;
public void FindSubComponentByParameter()
{
	Document doc = this.ActiveUIDocument.Document;
	Selection sel = this.ActiveUIDocument.Selection;
	StringBuilder sb = new StringBuilder();
			
	if (sel.GetElementIds().Count==0) return;
	FamilyInstance inst = doc.GetElement(sel.GetElementIds().FirstOrDefault()) as FamilyInstance;
	if(inst==null) return;

	Dictionary<ElementId,string> subNames = new Dictionary<ElementId, string>();
	SubComponentsInInstance = inst.GetSubComponentIds();
	if(SubComponentsInInstance.Count==0) return;

	foreach(ElementId id in SubComponentsInInstance)
	{
		Element e = doc.GetElement(id);
		subNames.Add(id,e.Name);
	}
	List<ElementId> subSymbols = new List<ElementId>();
	foreach(ElementId id in SubComponentsInInstance)
	{
		FamilyInstance inst1 = doc.GetElement(id) as FamilyInstance;
		if(!subSymbols.Contains(inst1.Symbol.Id)) subSymbols.Add(inst1.Symbol.Id);
	}

	FamilySymbol symb = inst.Symbol;

	this.Application.DocumentChanged+= DocumentChangedByFamilyParameter;
	using(TransactionGroup tg = new TransactionGroup(doc,"change familytype Parameter"))
	{
		tg.Start();
		foreach(Parameter p in symb.Parameters)
		{
			if (p.Definition.ParameterType == ParameterType.FamilyType && !p.IsReadOnly)
			{
				if (!subSymbols.Contains(p.AsElementId())) continue;
				FamilySymbol s1 = doc.GetElement(p.AsElementId()) as FamilySymbol;
				IEnumerable<ElementId > similar = s1.GetSimilarTypes();
				similar =  similar.Except(new List<ElementId>(){s1.Id});
				if(similar.FirstOrDefault()==null) continue; // TODO duplicate familysymbol to make schange
				using (Transaction t = new Transaction(doc,"dummy"))
				{
					t.Start();
					p.Set(similar.FirstOrDefault());
					t.Commit();
				}
				if(SubComponentByParameter !=ElementId.InvalidElementId)
				{
					sb.AppendLine();
				        sb.AppendLine(string.Format("subcomponent <{0}> {1} {2}",SubComponentByParameter,subNames[SubComponentByParameter],s1.Category.Name));
					sb.AppendLine(string.Format("     associated to parameter {0}",p.Definition.Name));
				}
			}
		}
		tg.RollBack();
	}
	this.Application.DocumentChanged-= DocumentChangedByFamilyParameter;
	TaskDialog.Show("debug", sb.ToString());
} void DocumentChangedByFamilyParameter(object sender, DocumentChangedEventArgs e)
{
       int count = e.GetAddedElementIds().Count+ e.GetDeletedElementIds().Count + e.GetModifiedElementIds().Count;
       if(count ==0return;
       SubComponentByParameter = ElementId.InvalidElementId;
       foreachvar x in e.GetModifiedElementIds())
       {
            if (x == ElementId.InvalidElementId) continue;
            if (SubComponentsInInstance.Contains(x))
            {
                SubComponentByParameter = x;
                break;
            }
       }
}

 

 

0 Likes
Message 18 of 18

FAIR59
Advisor
Advisor

On second thought:

Don't use a "random" similar familysymbol, but use a duplicated symbol.

When you use a "random" familysymbol, you will probably run into a few warnings / errors, as the family can expect the symbol to have certain parameters / reference(planes). Using a duplicate of the existing familysymbol will negate that possibility.

0 Likes