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

Replicate Graphical Column Schedule Sort Order with C#

Message 1 of 8
1711 Views, 7 Replies

Replicate Graphical Column Schedule Sort Order with C#



I am trying to write an add-in with C# to automate the process of sequentially labeling structural columns to match the sequence in the graphical column schedule.


I have written the following code to get all the concrete columns in the project and then create a list of their Column Location Marks (ie A(2000)-1(2150) )  (Built-in Category):


ElementCategoryFilter filter = new ElementCategoryFilter(BuiltInCategory.OST_StructuralColumns);
StructuralMaterialTypeFilter filter_mat = new StructuralMaterialTypeFilter(StructuralMaterialType.Concrete);

IList<Element> columns = collector.WherePasses(filter).WherePasses(filter_mat).WhereElementIsNotElementType().ToElements();

List<XYZ> locations = new List<XYZ>();
List<string> colmarks = new List<string>();

foreach (Element ele in columns)
string colmark = ele.get_Parameter(BuiltInParameter.COLUMN_LOCATION_MARK).AsString();



My trouble comes at this point. The colmarks.Sort() method does not match the order of the columns in the graphical column schedule.


I have also tried sorting the columns by their XYZ location which doesn't match the order in the graphical column schedule either.


Can anyone provide any insight into how the graphical column schedule orders the columns and how I can replicate this.




Tags (1)
Message 2 of 8

can you snapshot the schedule and the results that doesn't match...

Moustafa Khalil
Message 3 of 8

See attached screenshots.


I've tried a few different ways which involve creating a list of the parameter as strings and then sorting or using orderby as below:


List<Element> sortedElements = columns.OrderBy(x => x.get_Parameter(BuiltInParameter.COLUMN_LOCATION_MARK).AsString()).ToList();

Message 4 of 8

I have the same issue in dynamo too, the order seems to match my code but not the graphical column schedule... (screenshot attached).

Message 5 of 8


sorry to say, It is a well known limitation to this feature see this link

I was able to reproduce the same as well.


Moustafa Khalil
Message 6 of 8

Thanks mostafa,


I did see this thread but I was hoping someone might be able to shed some light on the logic Revit uses to sort the columns in the graphical column schedule so that I could replicate it with my own code in c#.



Tags (1)
Message 7 of 8
in reply to: simon.lewisPC7GZ

LocationMark syntax :


sort order:

  • gridsequence A: alphabetic ascending
  • gridsequence 1: alphabetic ascending
  • xxxx value, first the positive values from smallest to largest, then negative values from smallest to largest
  • yyyy value, first the positive values from smallest to largest, then negative values from smallest to largest
List<FamilyInstance> colums = new FilteredElementCollector(doc)
colums.Sort(new ColumnMarkComparer());

helper classes:

public static class Extensions
	public static string GetColumnLocationMark(this FamilyInstance f)
		Parameter p = f.get_Parameter(BuiltInParameter.COLUMN_LOCATION_MARK);
		if (p==null) return string.Empty;
		return p.AsString();
public class ColumnMarkComparer: IComparer<FamilyInstance>
	int IComparer<FamilyInstance>.Compare(FamilyInstance x, FamilyInstance y)
		if( x ==null)
			return y==null? 0 : -1 ;
		if (y ==null ) return 1;
		string[] mark1 = x.GetColumnLocationMark().Split('(' ,')');
		string[] mark2 = y.GetColumnLocationMark().Split('(',')');
		if (mark1.Length<4)
			return mark2.Length<4? 0 : -1;
		if(mark2.Length<4) return 1;
		//gridsequence A
		int res = string.Compare(mark1[0],mark2[0]);
		if( res!=0) return res ;

		//gridsequence 1
		string m12 = mark1[2].Remove(0,1);
		string m22 = mark2[2].Remove(0,1);
		res = string.Compare(m12,m22);
		if(res!=0) return res ;

		// value xxxx
		double d1 = 0;
		double d2=0;
		double.TryParse(mark1[1],out d1);
		double.TryParse(mark2[1], out d2);
		if (Math.Round(d1-d2,4)!=0)
			if ( d1<0 ^ d2<0)
				return d1<0? 1 : -1;
				return Math.Abs(d1) < Math.Abs(d2) ? -1 : 1 ;

		// value yyyy
		double.TryParse(mark1[3],out d1);
		double.TryParse(mark2[3], out d2);
		if (Math.Round(d1-d2,4)!=0)
			if ( d1<0 ^ d2<0)
				return d1<0? 1 : -1;
				return Math.Abs(d1) < Math.Abs(d2) ? -1 : 1 ;
		return 0;
Message 8 of 8

Many thanks to Fair59 for yet another brilliant and succinct answer.


Edited and saved for posterity on the blog:


Jeremy Tammik
Developer Technical Services
Autodesk Developer Network, ADN Open
The Building Coder

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

Post to forums  

Autodesk Customer Advisory Groups

Rail Community