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: 

Getting the multiple element IDs for materials in a wall

5 REPLIES 5
SOLVED
Reply
Message 1 of 6
Anonymous
1341 Views, 5 Replies

Getting the multiple element IDs for materials in a wall

I am trying to get a list of the materials that are contained within each wall type. Ideally I would like the names but as a start I am just trying to get the material IDs. I am using the following code (adapted from the Revit Intro Lab 1) where I iterate through the wall types and have a sub-routine to iterate through the materialIds of each WallType. Using this code it seems that the sub-foreach routine is not working and the string p that I create is left unfilled. Any advice would be much appreciated. 

 

 

        FilteredElementCollector wallTypes // 2014
          = new FilteredElementCollector(rvtDoc)
            .OfClass(typeof(WallType));

        string s = "";
        

        foreach (WallType wallType in wallTypes)
        {

string p = ""; foreach (ElementId mat3 in wallType.GetMaterialIds(false)) { p += mat3.ToString() + "\r\n"; } s += wallType.Name + p + "\r\n"; } // Show the result: TaskDialog.Show( "Revit Intro Lab", "Wall Types (in main instruction):\n\n" + s);
Tags (1)
5 REPLIES 5
Message 2 of 6
GonçaloFeio1321
in reply to: Anonymous

Try this:

 

 

public IEnumerable<Material> Get(WallType wallType)
{
if (wallType== null)
{
throw new ArgumentNullException(nameof(wallType));
}
var document = wallType.Document; var layers = wallType.GetCompoundStructure().GetLayers(); foreach (var layer in layers) { var materialId = layer.MaterialId; if (materialId != ElementId.InvalidElementId) { yield return document.GetElement(layer.MaterialId) as Material; } } }

 

 

 

The Element GetMaterialIds method works only for model instances, not their types.

 

Edit: Added a nice check for null

Message 3 of 6
Anonymous
in reply to: GonçaloFeio1321

Thanks for your reply. I have tried implementing your Get() method as follows: 

 

 

FilteredElementCollector wallTypes // 2014
              = new FilteredElementCollector(rvtDoc)
                .OfClass(typeof(WallType));

string s = "";

foreach (WallType wallType in wallTypes)
{
s += Get(wallType) + "\r\n";
}

TaskDialog.Show(
          "Revit Intro Lab",
          "Wall Types (in main instruction):\n\n" + s);

However when I print the result to dialog I get the following message: 

 

"Material_Select_2 + <Get>d__0" for each instance 

 

Material_Select_2 is the name of my class, I am guessing this has something to do with the variable it is stored in, do you have any idea how I can convert this to a string? 

 

Thanks

Message 4 of 6
GonçaloFeio1321
in reply to: Anonymous

The Get method returns a IEnumerable<Material>, even duplicates. And you are just adding that to the string.

 

Try replacing the line s += Get(wallType) + "\r\n"; wih this:

 

 

 

foreach (var material in Get(wallType))
{
    builder.AppendLine($"Material: {material.Name}");
}

 

Message 5 of 6
Anonymous
in reply to: GonçaloFeio1321

Thanks again for your reply. I incorporated this method and now the code is generating this error " System.NullReferenceException: Object reference not set to an instance of an object . at Material_Select_2.<Get>d__0.MoveNext()" 

 

I tried to incorporate an exception, as you can see below, but I am still getting the same error: 

 

 

StringBuilder builder = new StringBuilder();
        
        string s = "";
                
        foreach (WallType wallType in wallTypes)
        {
        
            foreach (var material in Get(wallType))
            {
                if (material == null)
                {
                    throw new ArgumentNullException(nameof(material));
                }
                
                builder.AppendLine($"Material: {material.Name}");
            }
        }
Message 6 of 6
GonçaloFeio1321
in reply to: Anonymous

Allan, here is the refactored method.

 

public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
    var uiDoc = commandData.Application.ActiveUIDocument;
    var rvtDoc = uiDoc.Document;

    using (var collector = new FilteredElementCollector(rvtDoc))
    {
        using (var filtered = collector.OfClass(typeof(WallType)))
        {
            var builder = new StringBuilder();

            foreach (var wallType in filtered.OfType<WallType>())
            {
                if (wallType.Kind == WallKind.Basic)
                {
                    builder.AppendLine($"WallType: {wallType.Name}");

                    foreach (var material in Get(wallType))
                    {
                        builder.AppendLine($"Material: {material.Name}");
                    }
                }
            }

            TaskDialog.Show("Output", builder.ToString());
        }
    }            

    return Result.Succeeded; // Why Failed?
} 

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

Post to forums  

Forma Design Contest


Rail Community