Retrieving Materials

Some people have reported issues using the Document.Settings.Materials collection.
For instance, its Contains method may throw an exception when used with Revit Structure 2012, while it works fine with Revit Architecture 2012.

The problem actually probably has nothing to do with the flavour of Revit being used, but is caused by the template file that the project is based on.
If you retrieve materials in a project based on the architectural template in Revit Structure, it also works fine.

In any case, here is a workaround you can use instead.
Simply retrieve the materials using a filtered element collector instead of the Materials collection, for example like this:


  FilteredElementCollector collector
    = new FilteredElementCollector( document )
      .OfClass( typeof( Material ) );
 
  IEnumerable<Material> materialsEnum
    = collector.ToElements().Cast<Material>();
 
  var materialReturn1
    = from materialElement in materialsEnum
      where materialElement.Name == "Default"
      select materialElement;

Comments

9 responses to “Retrieving Materials”

  1. Hi Jeremy,
    Is there an easy way to know if a material is being used by an object in the active file?
    Thanks,
    Dan

  2. Hello, Jeremy.
    Today I’ve got NullReferenceException when I used document.Settings.Materials.get_Item(“Concrete”);
    I’ve got this error on big real project. I discovered that Document.Materials collection caontains null item. Why is it possible? Is it error in Revit internal database or something else?
    P.S. I solved my problem using Linq:
    var material = document
    .Settings
    .Materials
    .OfType()
    .FirstOrDefault(m => m.Name.Equals(“Concrete”));

  3. Dear Victor,
    Yes, indeed, I have heard about this before.
    The materials collection in the Document.Settings.Materials property may contain empty entries.
    You need to check for null values and skip these invalid materials before trying to access them.
    Here is an example of handling this by Rudolf Honke to create a sorted generic .NET list of materials. Note that the comment editor mangles all the ‘less than and greater than signs!
    ///
    /// Return a list of the document’s
    /// non-null materials sorted by name.
    ///
    List GetSortedMaterials( Document doc )
    {
    Materials doc_materials = doc.Settings.Materials;
    int n = doc_materials.Size;
    List(Material) materials_sorted
    = new List(Material)( n );
    foreach( Material m in doc_materials )
    {
    if( m != null )
    {
    materials_sorted.Add( m );
    }
    }
    materials_sorted.Sort(
    delegate( Material m1, Material m2 )
    {
    return m1.Name.CompareTo( m2.Name );
    }
    );
    return materials_sorted;
    }
    I guess that in your code snippet, the OfType filter eliminates the null entries.
    Cheers, Jeremy.

  4. Dear Dan,
    I am not aware of any other method than iterating over all elements and checking what they use, which is presumably exactly what you are NOT looking for.
    Cheers, Jeremy.

  5. Hi, Jeremy. Thanks for answer.
    Yeah, of course I skip null entries when I iterate materials in loop or using Ling query.
    But Materials.get_Item(string) it is a standard Revit method and it doesn’t work when collection contains null entries. So it is a bug.
    I used this method many times in my project because I thought this method work correctly and it must work in spite of collections contains null. But now unfortunately for me, I must rewrite my code and change this method to my own:(
    Do you know does Autodesk know this bug? May be write them bug report?
    Regards, Victor.

  6. Dear Victor,
    In order to submit a report to development I need to provide a reproducible test case.
    Please provide complete compilation-ready sample code and project and a minimal sample building model which demonstrates the problem.
    Are you an ADN member now? If so, please submit an ADN DevHelp Online query for this.
    Thank you!
    Cheers, Jeremy.

  7. Hello, Dan.
    As Jeremy said there only way iterate all materials in all elements.
    I used following code to get all elements used be material
    var elementsWithMaterials =
    (from el in elements
    from Material m in el.Materials
    select new ElementMaterial(el, m))
    .ToList();
    Here I get Element and materials in each element collection
    var groupedElementsInMaterial =
    elementsWithMaterials
    .GroupBy(x => x.Material, new ElementComparer())
    .OrderBy(x => x.Key.Name);
    Here, I grouped elements by material.
    So I get result that you can see here:
    http://s005.radikal.ru/i209/1112/18/c22f9d4b44bf.png
    Regards, Victor

  8. Hi, Jeremy.
    I have decided to check was the bug with null material fixed in Revit 2013 and didn’t find Document.Settings.Material property. Is this property really was deprecated in the Revit 2013? I didn’t find mention about it anywhere.
    How to get all document materials now? But I think there is only one way to retrieve materials. Using FilteredElementCollector.OfClass(typeof(Material)). Am I right?
    The good news – when I retrieve materials via FilteredElementCollector I didn’t get null material.
    But there is the bad news as well. I opened the file which was created in Revit 2012 and contained null material (I sent it for you by e-mail 16.12.2012). Then I try to perform MAnage-MAterials command in UI. Revit thought and didn’t response anymore..
    I created the case an ADN support about it.
    Have a nice day, Victor.

  9. Sorry, Jeremy.
    I just had to wait more time to open Materials. The case has canceled.

Leave a Reply to Victor ChekalinCancel reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading