Hello Xiadong,
I'm very curious on this question too. And I'm still trying to get that list as fast as Navis does. I tried several scenarios and now I’m stopped at those:
1. Use Search() class to collect all items in model. Why Search() and not ActiveDocument.Model[0].RootItem.DescendantAndSelf ? Because second collection is accessed very slowly. So I do:
Search s1 = new Search();
s1.PruneBelowMatch = false;
s1.SearchConditions.Clear();
ModelItemCollection micTmp = new ModelItemCollection();
micTmp.Add(activeDoc.Models[0].RootItem);
s1.Selection.CopyFrom(micTmp);
searchResults = new ModelItemCollection();
SearchCondition oGroup1_sc = new SearchCondition(new NamedConstant("Item"), new NamedConstant(""), SearchConditionOptions.IgnoreNames, SearchConditionComparison.HasCategory, VariantData.FromNone());
s1.SearchConditions.Add(oGroup1_sc);
searchResults = s1.FindAll(Autodesk.Navisworks.Api.Application.ActiveDocument, true);
var cats = (from mi in searchResults from cats in mi.PropertyCategories select cats.DisplayName).Distinct();
FindAll() runs fast even on model with 500k ModelItems. And next LINQ runs faster too - we get list with unique PropertyCategories for whole model! But then we try to access that list just by
MessageBox.Show(String.Join("\n", cats.ToArray()));
Navis gets stuck on that for a very long time...
Does we can optimize that piece of code to run as faster as Navis?
2. Second approach that somewhat successful and dirt workaround at once:
Document activeDoc = NWApi.Application.ActiveDocument;
int iCnt = 0;
Search s1 = null;
ModelItemCollection searchResults = null;
List<string> lstCats = new List<string>();
public override CommandState CanExecuteCommand(String commandId)
{
if (s1 == null && activeDoc.Models.Count > 0)
{
s1 = new Search();
s1.PruneBelowMatch = false;
s1.SearchConditions.Clear();
ModelItemCollection micTmp = new ModelItemCollection();
micTmp.Add(activeDoc.Models[0].RootItem);
s1.Selection.CopyFrom(micTmp);
searchResults = new ModelItemCollection();
SearchCondition oGroup1_sc = new SearchCondition(new NamedConstant("Item"), new NamedConstant(""), SearchConditionOptions.IgnoreNames, SearchConditionComparison.HasCategory, VariantData.FromNone());
s1.SearchConditions.Add(oGroup1_sc);
searchResults = s1.FindAll(Autodesk.Navisworks.Api.Application.ActiveDocument, true);
}
if (s1 != null && iCnt < searchResults.Count)
{
for (int i = 0; i < 100; i++)
{
ModelItem mi;
try
{
mi = searchResults[iCnt];
}
catch { MessageBox.Show("Searching categories in background complited"); break; }
foreach (var cat in mi.PropertyCategories)
{
if (!lstCats.Contains(cat.DisplayName)) lstCats.Add(cat.DisplayName);
}
iCnt++;
}
}
//process over things
}
It is an attempt to simulate threading and it works. On models with 500k MI it finishes during 3 minutes on Core i5 2.5mhz. In that period of time Navis UI behaves a bit slowly but enough for user interaction. And after it finished we will get unique list of PropertyCategories in lstCats.
It is very interesting that LINQ is used by Navis. Loading even large model takes several seconds and after that if we open "Find Items" dialog and click on "Properties" tab we will see the whole categories tree list with its properties and values. I can suppose that Navis stores that list somewhere in Document(). For example in ActiveDocument.DocumentInfo.PropertyCategories. But that list is always is empty...
Xiadong, may be you can take us some clues?
With regards. Sergey.