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: 

Problem with correct ElementIds in List<T>

3 REPLIES 3
SOLVED
Reply
Message 1 of 4
u20.htwr
236 Views, 3 Replies

Problem with correct ElementIds in List<T>

Hello everyone! 

I am having strange issue with following piece of code. Here I'm collecting all elements in current project and iterate through them to see if some of the elements are meets certain requirements. I have object RowItem to store all data. 

Then I am trying to add ElementId of FamilyInstance to the current object. But strange thing is - if there are two elements in one room that are meets requirements their ElementIds don't differ after foreach loop (but differs in the process of cycling). I will try to explain further in code with comments. The problem occurs only when there is two instances of same family in one room, and I need to work it out. But just can't understand what's happening. 

Any help will be highly appreciated!  

 

 

 

 

 

 

AllElements = new FilteredElementCollector(doc) // Filtering all placed elements, works as expected
	.WherePasses(filter) // design option filter
	.WherePasses(multifilter) // multicategory filter
	.WhereElementIsNotElementType()
	.ToElements();

List<RowItem> passedItems = new List<RowItem>();

foreach (Element element in AllElements) // cycling through all placed elements
{
	FamilyInstance elementInstance = element as FamilyInstance;
	FamilySymbol elementSymbol = elementInstance.Symbol;
	IEnumerable<RowItem> rowItem = null;

	if (elementInstance.Room != null)
	{
		rowItem = dataList // List of RowItems from csv
		    .Where(x => x.familyName == elementSymbol.FamilyName) // if family name of element is same as in database
		    .Where(y => y.room == elementInstance.Room!.
					get_Parameter(BuiltInParameter.ROOM_NAME).AsString()); // if element's room is same as in database
			
		if (rowItem != null)
		{
		    foreach (RowItem rw in rowItem) 
			//iterating through IEnumerable of objects to add ElementIds 
			//and add this objects to final List (passedItems)
		    {
		        passedItems.Add(rw);
		        passedItems.Last().element = element.Id;
		        Console.WriteLine(rowItem.Count() + " " + rw.familyName + " " + rw.room + " " 
				+ elementSymbol.FamilyName + " " + passedItems.Last().element);  
				// HERE it is all correct - Element Ids for different instances are different too. 
				// I literally reading the last element's Id correctly. But then..
		    }
		}
	}
}

foreach (RowItem ri in passedItems)
{
	Console.WriteLine(ri.familyName + " " + ri.room + " " + ri.element);
	// HERE ElementIds are no longer differs for two different elements. I just can't understand why 
}

 

 

 

UPD.:  I also tried it other way around, like so, but with same result: 

 

 

rowItem = dataList
		    .Where(x => x.familyName == elementSymbol.FamilyName) // if family name of element is same as in database
		    .Where(y => y.room == elementInstance.Room!.
					get_Parameter(BuiltInParameter.ROOM_NAME).AsString()); // if element's room is same as in database
			
		if (rowItem != null)
		{
		    foreach (RowItem rw in rowItem) 
		    {
				rw.element = element.Id;
		        passedItems.Add(rw);
		    }
		}

 

 

I also tried not to use LINQ, and just for-looping to find matches. Same result. It's all OK while loop is going, but then it looks like ElementIds are just changing by themselves

 

UPD.2: Also just tried to use UniqueId instead of ElementId, and tried passing ElementId as string with conversion. Same result

3 REPLIES 3
Message 2 of 4
RPTHOMAS108
in reply to: u20.htwr

You appear to be changing the same item by reference:

 

rowItem = dataList // List of RowItems from csv

 

This results in adding same object to your final collection multiple times, need to instead make a new object.

 

If you don't duplicate an object elsewhere in memory then that same thing changes at that location in memory wherever you change it i.e. you don't create any copies of 'datalist' subsequent to above so you are changing 'datalist'. You need to use 'new' keyword and transfer the values. In general you can avoid this if you have one type of object for the csv information and another object type for the result of pairing that information with what is in Revit.

 

As a human being it makes more sense to add to the item before adding it to a collection. That is the way I would write it nine times out of ten but it should make no difference in practice.

Message 3 of 4
u20.htwr
in reply to: u20.htwr

Ok, it was C# issue, not a Revit. 

 

If someone interested: The problem was that I was working with direct objects (RowItems) from database, and, eventually, editing same ones over and over again. What I needed is to implement ICloneable interface in my class, like so: 

public class RowItem : ICloneable
    {
        public int idx { get; set; }
        public string familyName { get; set; }
        public string socketFamilyName { get; set; }
        public string socketTypeName { get; set; }
        public string room { get; set; }
        public string height { get; set; }
        public double position { get; set; }
        public ElementId element { get; set; }

        public object Clone()
        {
            var rowitem = (RowItem)MemberwiseClone();
            return rowitem;
        }
    }

 

 

After that I could simply clone object before putting it in the final List (passedItems): 

 

rowItem = dataList
                            .Where(x => x.familyName == elementSymbol.FamilyName)
                            .Where(y => y.room == elementInstance.Room!.get_Parameter(BuiltInParameter.ROOM_NAME).AsString());

                        if (rowItem != null)
                        {
                            foreach (RowItem rw in rowItem)
                            {
                                RowItem rwClone = (RowItem)rw.Clone();

                                rwClone.element = elementInstance.Id;
                                passedItems.Add(rwClone);
                            }
                        }

 

Programming is fun, am I right?

Message 4 of 4
u20.htwr
in reply to: RPTHOMAS108

@RPTHOMAS108  Thanks for the reply! Yes, just figured it out by myself (but in a little bit different way)

 

I will try your proposal with "new RowItem", and see if it works withount ICloneable interface. That way code will be a little lighter

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

Post to forums  

Autodesk Customer Advisory Groups


Rail Community