BIM World
A Professional BIM Learning Platform


Revit API: Accessing Component Material Appearance Information

Revit does not directly support reading material appearance information through simple lookup, which makes the process somewhat complex. However, the official Revit SDK tutorials provide detailed guidance on this.

Using a wall as an example, we can extract all the appearance data of the wall’s materials (see the image below). This mainly applies to Autodesk’s official material library. For unofficial material libraries, please refer to the commented-out code sections provided later. The overall approach to reading materials is straightforward and involves the following steps:

  1. Obtain the material IDs using eCollection<ElementId> matId = elem.GetMaterialIds(true);
  2. Access the Revit standard material library via AssetSet objlibraryAsset = revitApp.get_Assets(AssetType.Appearance);
  3. Retrieve materials from the Compound Structure Layer.
  4. Read material data in two different scenarios.

Revit secondary development - reading material appearance information of components

Further recursion is required when handling two types of assets: APT-Asset and APT-Reference. The detailed implementation is shown in the following code snippet:

using System;
using System.Collections.Generic;
using Autodesk.Revit.UI;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI.Selection;

namespace ReadWallMaterials
{
    [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
    [Autodesk.Revit.Attributes.Journaling(Autodesk.Revit.Attributes.JournalingMode.NoCommandData)]
    [Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
    public class MyClass : IExternalCommand
    {
        public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
        {
            Document revitDoc = commandData.Application.ActiveUIDocument.Document; 
            Application revitApp = commandData.Application.Application;
            UIDocument uiDoc = commandData.Application.ActiveUIDocument;
            Selection sel = uiDoc.Selection;
            Reference ref1 = sel.PickObject(ObjectType.Element, "Select a family instance");
            Element elem = revitDoc.GetElement(ref1);

            // Access Revit standard material library
            AssetSet objlibraryAsset = revitApp.get_Assets(AssetType.Appearance);

            Wall wall = elem as Wall; 
            ICollection matId = elem.GetMaterialIds(true);

            #region Retrieve materials from CompoundStructureLayer
            WallType wallType = wall.WallType;
            CompoundStructure compoundStructure = wallType.GetCompoundStructure();
            IList layers = compoundStructure.GetLayers();
            ReadAssetProperty readAssetProperty = new ReadAssetProperty();
            foreach (var layer in layers)
            {
                Material mat2 = revitDoc.GetElement(layer.MaterialId) as Material;
                ElementId assetElementId = mat2.AppearanceAssetId;
                if(assetElementId != ElementId.InvalidElementId)
                {
                    AppearanceAssetElement appearanceAssetElement = revitDoc.GetElement(assetElementId) as AppearanceAssetElement;
                    Asset currentAsset = appearanceAssetElement.GetRenderingAsset();
                    ReadAsset(currentAsset, objlibraryAsset, readAssetProperty, assetElementId.ToString());
                }
            }
            #endregion

            Form1 form = new Form1();
            form.ShowDialog();

            return Result.Succeeded;
        }

        public void ReadAsset(Asset currentAsset, AssetSet objlibraryAsset, ReadAssetProperty readAssetProperty, string matId)
        {
            IList listProperty = new List();
            if (currentAsset.Size == 0)
            {
                foreach (Asset objCurrentAsset in objlibraryAsset)
                {
                    if (objCurrentAsset.Name == currentAsset.Name && objCurrentAsset.LibraryName == currentAsset.LibraryName)
                    {
                        for (int i = 0; i < objCurrentAsset.Size; i++)
                        {
                            listProperty.Add(objCurrentAsset[i]);
                        }
                        foreach (var property in listProperty)
                        {
                            ReadAutodeskAssetProperty(property, readAssetProperty, objlibraryAsset, matId);
                        }
                    }
                }
            }
            else
            {
                for (int i = 0; i < currentAsset.Size; i++)
                {
                    listProperty.Add(currentAsset[i]);
                }
                foreach (var property in listProperty)
                {
                    ReadAutodeskAssetProperty(property, readAssetProperty, objlibraryAsset, matId);
                }
            }
        }

        public void ReadAutodeskAssetProperty(AssetProperty assetProperty, ReadAssetProperty readAssetProperty, AssetSet objlibraryAsset, string matId)
        {
            switch (assetProperty.Type)
            {
                case AssetPropertyType.APT_Integer:
                    var integerProp = assetProperty as AssetPropertyInteger;
                    if(readAssetProperty.CheckMaterialMxExists(matId, assetProperty.Name))
                    {
                        readAssetProperty.ReadAssetPropertyFromRevit(matId, assetProperty.Name, assetProperty.Type.ToString(), integerProp.Value.ToString());
                    }
                    break;

                case AssetPropertyType.APT_Distance:
                    var distanceProp = assetProperty as AssetPropertyDistance;
                    if (readAssetProperty.CheckMaterialMxExists(matId, assetProperty.Name))
                    {
                        readAssetProperty.ReadAssetPropertyFromRevit(matId, assetProperty.Name, assetProperty.Type.ToString(), distanceProp.Value.ToString());
                    }
                    break;

                case AssetPropertyType.APT_Double:
                    var doubleProp = assetProperty as AssetPropertyDouble;
                    if (readAssetProperty.CheckMaterialMxExists(matId, assetProperty.Name))
                    {
                        readAssetProperty.ReadAssetPropertyFromRevit(matId, assetProperty.Name, assetProperty.Type.ToString(), doubleProp.Value.ToString());
                    }
                    break;

                case AssetPropertyType.APT_DoubleArray2d:
                    var doubleArray2dProp = assetProperty as AssetPropertyDoubleArray2d;
                    if (readAssetProperty.CheckMaterialMxExists(matId, assetProperty.Name))
                    {
                        readAssetProperty.ReadAssetPropertyFromRevit(matId, assetProperty.Name, assetProperty.Type.ToString(), doubleArray2dProp.Value.ToString());
                    }
                    break;

                case AssetPropertyType.APT_DoubleArray4d:
                    var doubleArray4dProp = assetProperty as AssetPropertyDoubleArray4d;
                    if (readAssetProperty.CheckMaterialMxExists(matId, assetProperty.Name))
                    {
                        string value4d = $"{doubleArray4dProp.Value.get_Item(0)},{doubleArray4dProp.Value.get_Item(1)},{doubleArray4dProp.Value.get_Item(2)},{doubleArray4dProp.Value.get_Item(3)}";
                        readAssetProperty.ReadAssetPropertyFromRevit(matId, assetProperty.Name, assetProperty.Type.ToString(), value4d);
                    }
                    break;

                case AssetPropertyType.APT_String:
                    var stringProp = assetProperty as AssetPropertyString;
                    if (readAssetProperty.CheckMaterialMxExists(matId, assetProperty.Name))
                    {
                        readAssetProperty.ReadAssetPropertyFromRevit(matId, assetProperty.Name, assetProperty.Type.ToString(), stringProp.Value);
                    }
                    break;

                case AssetPropertyType.APT_Boolean:
                    var boolProp = assetProperty as AssetPropertyBoolean;
                    if (readAssetProperty.CheckMaterialMxExists(matId, assetProperty.Name))
                    {
                        readAssetProperty.ReadAssetPropertyFromRevit(matId, assetProperty.Name, assetProperty.Type.ToString(), boolProp.Value.ToString());
                    }
                    break;

                case AssetPropertyType.APT_Double44:
                    var double44Prop = assetProperty as AssetPropertyDoubleArray4d;
                    if (readAssetProperty.CheckMaterialMxExists(matId, assetProperty.Name))
                    {
                        readAssetProperty.ReadAssetPropertyFromRevit(matId, assetProperty.Name, assetProperty.Type.ToString(), double44Prop.Value.ToString());
                    }
                    break;

                case AssetPropertyType.APT_List:
                    var propList = assetProperty as AssetPropertyList;
                    IList subProps = propList.GetValue();
                    if (subProps.Count == 0) break;
                    if(subProps[0].Type == AssetPropertyType.APT_Integer)
                    {
                        foreach (AssetProperty subProp in subProps)
                        {
                            var intProp = subProp as AssetPropertyInteger;
                            if (readAssetProperty.CheckMaterialMxExists(matId, assetProperty.Name))
                            {
                                readAssetProperty.ReadAssetPropertyFromRevit(matId, assetProperty.Name, assetProperty.Type.ToString(), intProp.Value.ToString());
                            }
                        }
                    }
                    break;

                case AssetPropertyType.APT_Asset:
                    var assetProp = assetProperty as Asset;
                    ReadAsset(assetProp, objlibraryAsset, readAssetProperty, matId);
                    break;

                case AssetPropertyType.APT_Reference:
                    var referenceProp = assetProperty as AssetPropertyReference;
                    IList connectedProps = referenceProp.GetAllConnectedProperties();
                    foreach (var connectedProp in connectedProps)
                    {
                        var asset = connectedProp as Asset;
                        for (int i = 0; i < asset.Size; i++)
                        {
                            var subProperty = asset[i];
                            switch (subProperty.Type)
                            {
                                case AssetPropertyType.APT_Integer:
                                    var intProp2 = subProperty as AssetPropertyInteger;
                                    if (readAssetProperty.CheckMaterialMxExists(matId, subProperty.Name))
                                    {
                                        readAssetProperty.ReadAssetPropertyFromRevit(matId, subProperty.Name, subProperty.Type.ToString(), intProp2.Value.ToString());
                                    }
                                    break;

                                case AssetPropertyType.APT_Distance:
                                    var distanceProp2 = subProperty as AssetPropertyDistance;
                                    if (readAssetProperty.CheckMaterialMxExists(matId, subProperty.Name))
                                    {
                                        readAssetProperty.ReadAssetPropertyFromRevit(matId, subProperty.Name, subProperty.Type.ToString(), distanceProp2.Value.ToString());
                                    }
                                    break;

                                case AssetPropertyType.APT_Double:
                                    var doubleProp2 = subProperty as AssetPropertyDouble;
                                    if (readAssetProperty.CheckMaterialMxExists(matId, subProperty.Name))
                                    {
                                        readAssetProperty.ReadAssetPropertyFromRevit(matId, subProperty.Name, subProperty.Type.ToString(), doubleProp2.Value.ToString());
                                    }
                                    break;

                                case AssetPropertyType.APT_DoubleArray2d:
                                    var doubleArray2dProp2 = subProperty as AssetPropertyDoubleArray2d;
                                    if (readAssetProperty.CheckMaterialMxExists(matId, subProperty.Name))
                                    {
                                        readAssetProperty.ReadAssetPropertyFromRevit(matId, subProperty.Name, subProperty.Type.ToString(), doubleArray2dProp2.Value.ToString());
                                    }
                                    break;

                                case AssetPropertyType.APT_DoubleArray4d:
                                    var doubleArray4dProp2 = subProperty as AssetPropertyDoubleArray4d;
                                    if (readAssetProperty.CheckMaterialMxExists(matId, subProperty.Name))
                                    {
                                        readAssetProperty.ReadAssetPropertyFromRevit(matId, subProperty.Name, subProperty.Type.ToString(), doubleArray4dProp2.Value.ToString());
                                    }
                                    break;

                                case AssetPropertyType.APT_String:
                                    var stringProp2 = subProperty as AssetPropertyString;
                                    if (readAssetProperty.CheckMaterialMxExists(matId, subProperty.Name))
                                    {
                                        readAssetProperty.ReadAssetPropertyFromRevit(matId, subProperty.Name, subProperty.Type.ToString(), stringProp2.Value);
                                    }
                                    break;

                                case AssetPropertyType.APT_Boolean:
                                    var boolProp2 = subProperty as AssetPropertyBoolean;
                                    if (readAssetProperty.CheckMaterialMxExists(matId, subProperty.Name))
                                    {
                                        readAssetProperty.ReadAssetPropertyFromRevit(matId, subProperty.Name, subProperty.Type.ToString(), boolProp2.Value.ToString());
                                    }
                                    break;

                                case AssetPropertyType.APT_Double44:
                                    var double44Prop2 = subProperty as AssetPropertyDoubleArray4d;
                                    if (readAssetProperty.CheckMaterialMxExists(matId, subProperty.Name))
                                    {
                                        readAssetProperty.ReadAssetPropertyFromRevit(matId, subProperty.Name, subProperty.Type.ToString(), double44Prop2.Value.ToString());
                                    }
                                    break;

                                case AssetPropertyType.APT_List:
                                    var propList2 = subProperty as AssetPropertyList;
                                    IList subProps2 = propList2.GetValue();
                                    if (subProps2.Count == 0) break;
                                    if(subProps2[0].Type == AssetPropertyType.APT_Integer)
                                    {
                                        foreach (AssetProperty subProp in subProps2)
                                        {
                                            var intProp2 = subProp as AssetPropertyInteger;
                                            if (readAssetProperty.CheckMaterialMxExists(matId, subProperty.Name))
                                            {
                                                readAssetProperty.ReadAssetPropertyFromRevit(matId, subProperty.Name, subProperty.Type.ToString(), intProp2.Value.ToString());
                                            }
                                        }
                                    }
                                    break;
                            }
                        }
                    }
                    break;

                default:
                    // Unhandled property types can be logged here if needed.
                    break;
            }
        }
    }
}

Additionally, there is a helper class dedicated to reading material properties from a database. It provides two main functions:

  • Inserting material properties into the database.
  • Checking whether the material property information already exists in the database.

The database connection string varies depending on the user’s setup. Below is an example connection string:

private string str = "Data Source=USER-20161016YAMEDICINE;Initial Catalog=MyMaterials;Integrated Security=True";
using System;
using System.Data.SqlClient;

namespace ReadWallMaterials
{
    public class ReadAssetProperty
    {
        private string str = "Data Source=USER-20161016YAMEDICINE;Initial Catalog=MyMaterials;Integrated Security=True";

        public void ReadAssetPropertyFromRevit(string materialId, string paramName, string type, string value)
        {
            int n = -1;
            using (SqlConnection con = new SqlConnection(str))
            {
                string sql = string.Format("INSERT INTO MaterialFormRevit(MaterialId, ParamName, MatType, Value) VALUES('{0}', '{1}', '{2}', '{3}')", materialId, paramName, type, value);
                using (SqlCommand cmd = new SqlCommand(sql, con))
                {
                    con.Open();
                    n = cmd.ExecuteNonQuery();
                }
            }
            // Optionally handle success/failure feedback here.
        }

        public bool CheckMaterialMxExists(string strMaterialId, string paramName)
        {
            bool flag = false;
            using (SqlConnection mycon = new SqlConnection(str))
            {
                mycon.Open();
                SqlCommand mycmd = new SqlCommand("SELECT MaterialId FROM MaterialFormRevit WHERE MaterialId=@MaterialId AND ParamName=@ParamName", mycon);
                mycmd.Parameters.AddWithValue("@MaterialId", strMaterialId);
                mycmd.Parameters.AddWithValue("@ParamName", paramName);
                using (SqlDataReader mysdr = mycmd.ExecuteReader())
                {
                    flag = !mysdr.HasRows;
                }
            }
            return flag;
        }
    }
}

The following class defines an intermediate structure for material properties:

using System;

namespace ReadWallMaterials
{
    public class Depart
    {
        private int _MaterialId;
        private string _ParamName;
        private string _Type;
        private string _Value;

        public int MaterialId
        {
            get { return _MaterialId; }
            set { _MaterialId = value; }
        }

        public string ParamName
        {
            get { return _ParamName; }
            set { _ParamName = value; }
        }

        public string Type
        {
            get { return _Type; }
            set { _Type = value; }
        }

        public string Value
        {
            get { return _Value; }
            set { _Value = value; }
        }
    }
}

Finally, here is the code for the form that displays the material properties:

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Data.SqlClient;

namespace ReadWallMaterials
{
    public partial class Form1 : Form
    {
        private string str = "Data Source=USER-20161016YAMEDICINE;Initial Catalog=MyMaterials;Integrated Security=True";

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            LoadData();
        }

        private void LoadData()
        {
            List list = new List();

            using (SqlConnection con = new SqlConnection(str))
            {
                string sql = "SELECT * FROM MaterialFormRevit";
                using (SqlCommand cmd = new SqlCommand(sql, con))
                {
                    con.Open();
                    using (SqlDataReader reader = cmd.ExecuteReader())
                    {
                        if (reader.HasRows)
                        {
                            while (reader.Read())
                            {
                                Depart dk = new Depart
                                {
                                    MaterialId = Convert.ToInt32(reader["MaterialId"].ToString()),
                                    ParamName = reader["ParamName"].ToString(),
                                    Type = reader["MatType"].ToString(),
                                    Value = reader["Value"].ToString()
                                };
                                list.Add(dk);
                            }
                        }
                    }
                }
            }

            dgv.AutoGenerateColumns = false;
            dgv.DataSource = list;
        }
    }
}

The result of reading and displaying the material appearance information is illustrated in the image below:

Revit secondary development - reading material appearance information of components

xuebim
Follow the latest BIM developments in the architecture industry, explore innovative building technologies, and discover cutting-edge industry insights.
← Scan with WeChat
Like(0) 打赏
BIM WORLD » Revit API: Accessing Component Material Appearance Information

Comment Get first!

Must log in before commenting!

 

BIM World, A Professional BIM Learning Platform

Stay updated on the latest architecture trends and share new building technologies.

Contact UsAbout Us

觉得文章有用就打赏一下小编吧

非常感谢你的打赏,我们将继续提供更多优质内容,让我们一起创建更加美好的网络世界!

支付宝扫一扫

微信扫一扫

Account Login

By signing in, you agree toUser Agreement

Sign Up