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
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.");
}
}
}
Solved! Go to Solution.
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
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.");
}
}
}
Solved! Go to Solution.
Solved by Mohamed_Arshad. Go to Solution.
Solved by jeremy_tammik. Go to 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
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
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
Hope this will Helps 🙂
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
Hope this will Helps 🙂
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.");
}
}
}
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.");
}
}
}
@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:
@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:
Can't find what you're looking for? Ask the community or share your knowledge.