Revit API Forum
Welcome to Autodesk’s Revit API Forums. Share your knowledge, ask questions, and explore popular Revit API topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Modifying Family Types

4 REPLIES 4
SOLVED
Reply
Message 1 of 5
ChristianMolino
412 Views, 4 Replies

Modifying Family Types

ChristianMolino
Enthusiast
Enthusiast

I am working on building a windows form add-in that will allow easier modification of a custom family we use instead of going into edit type every time. 

 

I am starting with just trying to get a single parameter and populate that parameters value inside a text box. Once I get that working, the text box will be able to be edited to change the value of the type and apply it back to the type to update the model when the user clicks save at the bottom.

 

I am very new to coding and the API and seem to have hit a wall while trying to get the parameter and show it in the text box. I think I am successfully getting it, but cannot figure out how to show it correctly. It is currently just saying "Autodesk.Revit.DB.FamilyParameter" in the text box.

 

Here is an image of the form and the method I am using

ChristianMolino_0-1720726194971.png

 

 

 

 

        private void comboBoxFamilyType_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (comboBoxFamilyType.SelectedItem is FamilyType selectedFamilyType)
            {
                // Use a filtered element collector to find all instances of the selected family type
                var collector = new FilteredElementCollector(_doc)
                    .OfClass(typeof(FamilyInstance))
                    .WhereElementIsNotElementType()
                    .Where(x => ((FamilyInstance)x).Symbol.Id == selectedFamilyType.Id);

                // Debugging: Output the number of instances found
                MessageBox.Show($"Number of instances found: {collector.Count()}");

                // Try to get the first instance of this family type
                var selectedInstance = collector.FirstOrDefault() as FamilyInstance;

                if (selectedInstance != null)
                {
                    // Debugging: Confirm the instance ID
                    MessageBox.Show($"Instance ID: {selectedInstance.Id.IntegerValue}");

                    Family family = selectedInstance.Symbol.Family;

                    Document familyDoc = _doc.EditFamily( family );
                    
                    FamilyManager familyManager = familyDoc.FamilyManager;

                    FamilyParameter depthParam = familyManager.get_Parameter("DD_Depth");

                    if (depthParam != null)
                    {
                        textBoxDD_Depth.Text = depthParam.ToString();
                        // Debugging: Show the parameter's storage type and value
                        MessageBox.Show($"Parameter storage type: {depthParam.StorageType}");
                    }
                    else
                    {
                        textBoxDD_Depth.Text = "Parameter not found";
                        // Debugging: Parameter not found
                        MessageBox.Show("DD_Depth parameter not found.");
                    }
                }
                else
                {
                    MessageBox.Show("No instances found for the selected family type.");
                }
            }
        }

 

 

 

 

0 Likes

Modifying Family Types

I am working on building a windows form add-in that will allow easier modification of a custom family we use instead of going into edit type every time. 

 

I am starting with just trying to get a single parameter and populate that parameters value inside a text box. Once I get that working, the text box will be able to be edited to change the value of the type and apply it back to the type to update the model when the user clicks save at the bottom.

 

I am very new to coding and the API and seem to have hit a wall while trying to get the parameter and show it in the text box. I think I am successfully getting it, but cannot figure out how to show it correctly. It is currently just saying "Autodesk.Revit.DB.FamilyParameter" in the text box.

 

Here is an image of the form and the method I am using

ChristianMolino_0-1720726194971.png

 

 

 

 

        private void comboBoxFamilyType_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (comboBoxFamilyType.SelectedItem is FamilyType selectedFamilyType)
            {
                // Use a filtered element collector to find all instances of the selected family type
                var collector = new FilteredElementCollector(_doc)
                    .OfClass(typeof(FamilyInstance))
                    .WhereElementIsNotElementType()
                    .Where(x => ((FamilyInstance)x).Symbol.Id == selectedFamilyType.Id);

                // Debugging: Output the number of instances found
                MessageBox.Show($"Number of instances found: {collector.Count()}");

                // Try to get the first instance of this family type
                var selectedInstance = collector.FirstOrDefault() as FamilyInstance;

                if (selectedInstance != null)
                {
                    // Debugging: Confirm the instance ID
                    MessageBox.Show($"Instance ID: {selectedInstance.Id.IntegerValue}");

                    Family family = selectedInstance.Symbol.Family;

                    Document familyDoc = _doc.EditFamily( family );
                    
                    FamilyManager familyManager = familyDoc.FamilyManager;

                    FamilyParameter depthParam = familyManager.get_Parameter("DD_Depth");

                    if (depthParam != null)
                    {
                        textBoxDD_Depth.Text = depthParam.ToString();
                        // Debugging: Show the parameter's storage type and value
                        MessageBox.Show($"Parameter storage type: {depthParam.StorageType}");
                    }
                    else
                    {
                        textBoxDD_Depth.Text = "Parameter not found";
                        // Debugging: Parameter not found
                        MessageBox.Show("DD_Depth parameter not found.");
                    }
                }
                else
                {
                    MessageBox.Show("No instances found for the selected family type.");
                }
            }
        }

 

 

 

 

4 REPLIES 4
Message 2 of 5

jeremy_tammik
Autodesk
Autodesk
Accepted solution

Welcome to coding and the Revit API.

   

Yes. As you have defined it, depthParam is a FamilyParameter. That is a FamilyParameter object, not a value. It is a container for a parameter value, but only in associaton with a FamilyType object. It can contain different kinds of data, e.g., integer, real, string element id, etc., and they can differ for each type. Therefore, when you convert it to a string, you receive a .NET class type, not the value it contains for a given type. You have to use a FamilyType in conjunction with the FamilyParameter to access the values they contain. Look at these FamilyType methods:

  

https://www.revitapidocs.com/2024/27c11ecd-c601-4081-71aa-43a330037996.htm

 

I explored and documented that topic when I was learning the Revit API myself 15 years ago:

 

https://thebuildingcoder.typepad.com/blog/2009/11/family-parameter-value.html

   

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

Welcome to coding and the Revit API.

   

Yes. As you have defined it, depthParam is a FamilyParameter. That is a FamilyParameter object, not a value. It is a container for a parameter value, but only in associaton with a FamilyType object. It can contain different kinds of data, e.g., integer, real, string element id, etc., and they can differ for each type. Therefore, when you convert it to a string, you receive a .NET class type, not the value it contains for a given type. You have to use a FamilyType in conjunction with the FamilyParameter to access the values they contain. Look at these FamilyType methods:

  

https://www.revitapidocs.com/2024/27c11ecd-c601-4081-71aa-43a330037996.htm

 

I explored and documented that topic when I was learning the Revit API myself 15 years ago:

 

https://thebuildingcoder.typepad.com/blog/2009/11/family-parameter-value.html

   

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 3 of 5

Mohamed_Arshad
Advisor
Advisor
Accepted solution

HI @ChristianMolino 

 

   As @jeremy_tammik told you have directly converted Parameter Object to string, you need to get value from the parameter and pass it to textbox.Text. Kindly check the below code and Reference Image.

 

Code Snippet (AsValueString)

textBoxDD_Depth.Text = depthParam.AsValueString();

Sometimes unit will come in the AsValueString() method so best method is to take AsDouble value and convert feet to current project units and then convert it to string. Kindly check the below code snippet

 

AsDouble

double depthValue = depthParam.AsDouble();
textBoxDD_Depth.Text=UnitUtils.ConvertFromInternalUnits(depthValue , UnitTypeId.Millimeters).ToString();//Converting Feet to Millimeter, My Project is in millimeters

 

Reference Image

Mohamed_Arshad_0-1720930595878.png

 

 

Hope this will Helps 🙂

 

Thanks & Regards,
Mohamed Arshad K
0 Likes

HI @ChristianMolino 

 

   As @jeremy_tammik told you have directly converted Parameter Object to string, you need to get value from the parameter and pass it to textbox.Text. Kindly check the below code and Reference Image.

 

Code Snippet (AsValueString)

textBoxDD_Depth.Text = depthParam.AsValueString();

Sometimes unit will come in the AsValueString() method so best method is to take AsDouble value and convert feet to current project units and then convert it to string. Kindly check the below code snippet

 

AsDouble

double depthValue = depthParam.AsDouble();
textBoxDD_Depth.Text=UnitUtils.ConvertFromInternalUnits(depthValue , UnitTypeId.Millimeters).ToString();//Converting Feet to Millimeter, My Project is in millimeters

 

Reference Image

Mohamed_Arshad_0-1720930595878.png

 

 

Hope this will Helps 🙂

 

Thanks & Regards,
Mohamed Arshad K
Message 4 of 5

ChristianMolino
Enthusiast
Enthusiast

Thank you both @jeremy_tammik and @Mohamed_Arshad, I did get this working as seen below!

        private void comboBoxFamilyType_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (comboBoxFamilyType.SelectedItem is FamilyTypeItem selectedFamilyType)
            {
                // Use a filtered element collector to find all instances of the selected family type
                var collector = new FilteredElementCollector(_doc)
                    .OfClass(typeof(FamilyInstance))
                    .WhereElementIsNotElementType()
                    .Where(x => ((FamilyInstance)x).Symbol.Id == selectedFamilyType.Id);

                // Attempt to retrieve the first instance found; this will be used to access the family data
                var selectedInstance = collector.FirstOrDefault() as FamilyInstance;

                if (selectedInstance != null)
                {

                    Family family = selectedInstance.Symbol.Family; // Retrieve the family from the instance symbol

                    Document familyDoc = _doc.EditFamily( family ); // Open the family for editing which returns the family document

                    FamilyManager familyManager = familyDoc.FamilyManager; // Get the family manager which manages the parameters of the family

                    // Retrieve and print the number of parameters in the family
                    int n = familyManager.Parameters.Size; 

                    Debug.Print("\nFamily {0} has {1} parameter{2}", _doc.Title, n, Util.PluralSuffix( n ) );

                    // Create a dictionary to map parameter names to their corresponding FamilyParameter objects
                    Dictionary<string, FamilyParameter> fps = new Dictionary<string, FamilyParameter>(n);

                    foreach (FamilyParameter fp in familyManager.Parameters)
                    {
                        string name = fp.Definition.Name;
                        fps.Add (name, fp );
                    }
                    // Sort the keys (parameter names) for better manageability
                    List<string> keys = new List<string>( fps.Keys );
                    keys.Sort();

                    // Print the number of types in the family and their names
                    n = familyManager.Types.Size;

                    //Debug.Print("\nFamily {0} has {1} type{2}{3}", _doc.Title, n, Util.PluralSuffix(n), Util.DotOrColon(n));

                    string matchName = selectedFamilyType.ToString()
                            .Replace("DD Mirror: ", "")
                            .Replace("DD Adjust: ", "");

                    Dictionary<string, string> parameterValues = new Dictionary<string, string>(); // Dictionary to store parameter values

                    // Iterate through each type in the family
                    foreach (Autodesk.Revit.DB.FamilyType t in familyManager.Types)
                    {
                        // Get the match name and remove "DD Mirror: " or "DD Adjust: " from it
                        if (t.Name == matchName)
                        {
                            // For each parameter key, check if the type has a value set and print it
                            foreach (string key in keys)
                            {
                                FamilyParameter fp = fps[key];
                                if (t.HasValue(fp))
                                {
                                    string value = FamilyParamValueString(t, fp, _doc);
                                    parameterValues[key] = value; // Store the parameter value in the dictionary
                                    Debug.Print("    {0} = {1}", key, value);
                                }
                            }
                        }
                        else
                        {
                            continue;
                        }
                    }

                    // Set text box values
                    foreach (var entry in ControlMappings.TextBoxMappings)
                    {
                        var textBox = this.Controls.Find(entry.Key, true).FirstOrDefault() as System.Windows.Forms.TextBox;
                        if (textBox != null)
                        {
                            textBox.Text = parameterValues.ContainsKey(entry.Value) ? parameterValues[entry.Value] : "Error";
                        }
                    }

                    // Set checkbox values
                    foreach (var entry in ControlMappings.CheckBoxMappings)
                    {
                        var checkBox = this.Controls.Find(entry.Key, true).FirstOrDefault() as System.Windows.Forms.CheckBox;
                        if (checkBox != null)
                        {
                            checkBox.Checked = parameterValues.ContainsKey(entry.Value) && parameterValues[entry.Value] == "1";
                        }
                    }
                }
                else
                {
                    MessageBox.Show("No instances of the selected family type were found.");
                }
            }
        }
0 Likes

Thank you both @jeremy_tammik and @Mohamed_Arshad, I did get this working as seen below!

        private void comboBoxFamilyType_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (comboBoxFamilyType.SelectedItem is FamilyTypeItem selectedFamilyType)
            {
                // Use a filtered element collector to find all instances of the selected family type
                var collector = new FilteredElementCollector(_doc)
                    .OfClass(typeof(FamilyInstance))
                    .WhereElementIsNotElementType()
                    .Where(x => ((FamilyInstance)x).Symbol.Id == selectedFamilyType.Id);

                // Attempt to retrieve the first instance found; this will be used to access the family data
                var selectedInstance = collector.FirstOrDefault() as FamilyInstance;

                if (selectedInstance != null)
                {

                    Family family = selectedInstance.Symbol.Family; // Retrieve the family from the instance symbol

                    Document familyDoc = _doc.EditFamily( family ); // Open the family for editing which returns the family document

                    FamilyManager familyManager = familyDoc.FamilyManager; // Get the family manager which manages the parameters of the family

                    // Retrieve and print the number of parameters in the family
                    int n = familyManager.Parameters.Size; 

                    Debug.Print("\nFamily {0} has {1} parameter{2}", _doc.Title, n, Util.PluralSuffix( n ) );

                    // Create a dictionary to map parameter names to their corresponding FamilyParameter objects
                    Dictionary<string, FamilyParameter> fps = new Dictionary<string, FamilyParameter>(n);

                    foreach (FamilyParameter fp in familyManager.Parameters)
                    {
                        string name = fp.Definition.Name;
                        fps.Add (name, fp );
                    }
                    // Sort the keys (parameter names) for better manageability
                    List<string> keys = new List<string>( fps.Keys );
                    keys.Sort();

                    // Print the number of types in the family and their names
                    n = familyManager.Types.Size;

                    //Debug.Print("\nFamily {0} has {1} type{2}{3}", _doc.Title, n, Util.PluralSuffix(n), Util.DotOrColon(n));

                    string matchName = selectedFamilyType.ToString()
                            .Replace("DD Mirror: ", "")
                            .Replace("DD Adjust: ", "");

                    Dictionary<string, string> parameterValues = new Dictionary<string, string>(); // Dictionary to store parameter values

                    // Iterate through each type in the family
                    foreach (Autodesk.Revit.DB.FamilyType t in familyManager.Types)
                    {
                        // Get the match name and remove "DD Mirror: " or "DD Adjust: " from it
                        if (t.Name == matchName)
                        {
                            // For each parameter key, check if the type has a value set and print it
                            foreach (string key in keys)
                            {
                                FamilyParameter fp = fps[key];
                                if (t.HasValue(fp))
                                {
                                    string value = FamilyParamValueString(t, fp, _doc);
                                    parameterValues[key] = value; // Store the parameter value in the dictionary
                                    Debug.Print("    {0} = {1}", key, value);
                                }
                            }
                        }
                        else
                        {
                            continue;
                        }
                    }

                    // Set text box values
                    foreach (var entry in ControlMappings.TextBoxMappings)
                    {
                        var textBox = this.Controls.Find(entry.Key, true).FirstOrDefault() as System.Windows.Forms.TextBox;
                        if (textBox != null)
                        {
                            textBox.Text = parameterValues.ContainsKey(entry.Value) ? parameterValues[entry.Value] : "Error";
                        }
                    }

                    // Set checkbox values
                    foreach (var entry in ControlMappings.CheckBoxMappings)
                    {
                        var checkBox = this.Controls.Find(entry.Key, true).FirstOrDefault() as System.Windows.Forms.CheckBox;
                        if (checkBox != null)
                        {
                            checkBox.Checked = parameterValues.ContainsKey(entry.Value) && parameterValues[entry.Value] == "1";
                        }
                    }
                }
                else
                {
                    MessageBox.Show("No instances of the selected family type were found.");
                }
            }
        }
Message 5 of 5

ChristianMolino
Enthusiast
Enthusiast

@Mohamed_Arshad Thank you for the response. This was very helpful in converting, but it appears to be behaving oddly with the units I am seeking.

 

If I convert it to millimeters it has no problem displaying that as a string, however if I convert to FeetFractionalInches, it seems to be reverting it back to decimal feet.

 

I had to instead do this:

 

ChristianMolino_0-1721157478623.png

 

 

 

@Mohamed_Arshad Thank you for the response. This was very helpful in converting, but it appears to be behaving oddly with the units I am seeking.

 

If I convert it to millimeters it has no problem displaying that as a string, however if I convert to FeetFractionalInches, it seems to be reverting it back to decimal feet.

 

I had to instead do this:

 

ChristianMolino_0-1721157478623.png

 

 

 

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report