0

I am using c# to create Macros through REVIT. what I am trying to do is to number objects in a certain order, they are sorted by level of placement. I want the code to loop through the first level, count the objects and number them, then go to the second level where it counts and start numbering with a reference from the level before for example if the first set of objects were numbered from 1 to 10 then the next set of object will start numbering from 11 and till the count of this new set of objects so if they are 5 the numbering will be till 15 and so on

This is the code I tried. The problem is that the numbering now start each time at 1.

public void UniqueTag()
{   
    Document document = Application.ActiveUIDocument.Document;
    FilteredElementCollector collector = new FilteredElementCollector(document);
    IList<Element> AllWindows = collector.OfCategory(BuiltInCategory.OST_Windows).OfClass(typeof(FamilyInstance)).ToList();  // gets only placed instances       

    Transaction tran = new Transaction(document, "Tags Modification");
    tran.Start();
 int start = 1;
    foreach (Element window in AllWindows)
    {
        string WindowLevel = window.LookupParameter("Level").AsValueString();

        FilteredElementCollector LevelCollector = new FilteredElementCollector(document);
        ICollection<Element> levels = LevelCollector.OfClass(typeof(Level)).ToElements();  

        foreach (Level le in levels)
        {
            var LevelName = le.Name;
            if (WindowLevel == LevelName)
            {      
                var query = from element in LevelCollector where element.Name == LevelName select element;
                List<Element> level = query.ToList<Element>();
                ElementId levelId = level[0].Id;    

                ElementLevelFilter levelFilter = new ElementLevelFilter(levelId);
                LevelCollector = new FilteredElementCollector(document);
                ICollection<Element> allWindowssOnLevel = LevelCollector.OfCategory(BuiltInCategory.OST_Windows).OfClass(typeof(FamilyInstance)).WherePasses(levelFilter).ToElements();


                int count = allWindowssOnLevel.Count;

                for (int i = start; i <= count ; i++) // work correct for the first loop, need to be changed for the second loop
                {
                    foreach (Element e in allWindowssOnLevel)
                    {
                        var tag = e.GetParameters("Tag#")[0].Set(i++);
                        start=count+1;
                    }//End of foreach allWindowssOnLevel
                }//End of for
            }//End of if
       }//End of foreach levels
    }//End of foreachAllWindows

tran.Commit();

} // End of UniqueTag

Update this version of the code with the start of the count outside all the loops number the windows correctly at the first level then skip the second level and number windows in the third level correctly starting from the the last tag+1. in case of having more levels after the third one, none of the windows in them are numbered.

Dalia
  • 7
  • 4

1 Answers1

0

I think your mistake is that you're making the tag # local to the loop. You should be declaring the int outside of all the loops, as you want to be modifying it within the layers of the loop. As it is, you set it to start at 1 at each level, which is the source of all your woes.

I also see what I believe to be a slight structural error to your whole loop: You're first loop is to look at each window in the ENTIRE DOCUMENT. Then, you look at the level, then you look back at the windows on the level. That means you're looking at every Element at least twice. Not only that, but you're going to be executing a potentially insanely long loop. If you have 15 level each with 50 windows, that means you're going to execute this as follows:

foreach (Element window in AllWindows)  //750 iterations
{
    foreach (Level le in levels)        //15 iterations
    {
        for (int i = start; i <= count ; i++) //50 iterations
        {
            foreach ((Element e in allWindowssOnLevel)  //50 iterations
            {   //It should also be noted that this is going through the same set of elements as the for loop.

By the time you get through the final foreach loop, you've gone through 50 iterations; by the end of the for loop - 2500 iterations; by the end of the foreach (Level le in levels) loop - 37,500 iterations; and by the end of the foreach (Element window in AllWindows) loop - 28,125,000 iterations. All to number 750 windows. I think you should refine it to something like:

int iCtr = 1;
foreach (Level le in levels)
{
    var query = from element in LevelCollector where element.Name == LevelName select element;
    List<Element> level = query.ToList<Element>();
    ElementId levelId = level[0].Id;    

    ElementLevelFilter levelFilter = new ElementLevelFilter(levelId);
    var LevelCollector = new FilteredElementCollector(document);
    ICollection<Element> allWindowssOnLevel = LevelCollector.OfCategory(BuiltInCategory.OST_Windows).OfClass(typeof(FamilyInstance)).WherePasses(levelFilter).ToElements();


    foreach (Element pElt in allWindowsOnLevel)
    {
        var tag = e.GetParameters("Tag#")[0].Set(iCtr);
        iCtr+=1; //only increments when we set a tag #
    }  //End of foreach - only runs #OfWindowsOnLevel times/level
}//end of foreach (Level ... ) - only runs #OfLevels
//if we had 15 floor of 50 windows, we only looped 750 times - not 28mil...

I hope this helps. I've had to deal with node tags in Revit a lot, and it's not always easy.

Uchiha Itachi
  • 1,251
  • 1
  • 16
  • 42
  • thanks a lot for your reply.I have a question. how will I look up the "windowLevel" fot the if condition if I don't have the first foreach loop?foreach (Element window in AllWindows) ? – Dalia Mar 14 '17 at 06:50
  • The same way you are now - just not in a loop. You can still use your `FilteredElementCollector` to put your `Level`s in a `List`. I wouldn't cast them as an `Element` though - they already inherit from that, so you're potentially losing some of the `Level` properties when you do that. Just: `FilteredElementCollector fecLevels = new FilteredElementCollector(document); var lLevels = fecLevels.OfClass(typeof(Level)).ToList();` – Uchiha Itachi Mar 14 '17 at 14:07
  • lookup parameter is not working with me unless I use the foreach to address each window in the list of windows, is there another way to lookup the parameter of the window level other than the forach. I cannot do it like string WindowLevel = AllWindows.LookupParameter("Level").AsValueString(); – Dalia Mar 15 '17 at 17:16
  • I think that whole check is unnecessary. You were checking it because you wanted to see if the `Window` from your original loop was on the `Level` you're on. If you run your loop to find every `Element` (window) on the floor, you've already verified it's there. Just scrap it. I revised the code - check it out – Uchiha Itachi Mar 15 '17 at 17:47
  • Thanks a lot for your help, your code actually worked but it needed one modification, with this line LevelCollector = new FilteredElementCollector(document); the code fails to run. it required a new collector FilteredElementCollector NewLevelCollector = new FilteredElementCollector(document); ICollection allWindowssOnLevel = NewLevelCollector.OfCategory(BuiltInCategory.OST_Windows).OfCl‌​ass(typeof(FamilyIns‌​tance)).WherePasses(‌​levelFilter).ToEleme‌​nts(); thanks again for the help. I edited in your post the final code that worked – Dalia Mar 15 '17 at 18:58
  • So my code worked, and I helped you with your solution, but you unmarked my answer as the solution? Why? – Uchiha Itachi Mar 17 '17 at 17:04
  • first so sorry for any misunderstanding, I really appreciate the help, it is great that you give time to help me. I was just waiting for the edit I made to be approved so I can mark it again as a solution because the code with its current version fail when it runs. i just didn't want anyone to be trying it and see it as an answer while it still need one small modification. I have been in that situation before where I am trying something from a forum while it is not complete or has a mistake, it can be really frustrating. so sorry again and thanks a lot – Dalia Mar 18 '17 at 08:34