UIHierarchyItem from a ProjectItem

Hi,
 
I need to find a UIHierarchyItem from a ProjectItem. My current solution involves getting the UIHierarchy from the Solution Explorer, and searching depth-first for the hierarchy item with a corresponding project item. For a large project it takes 15-20 seconds to find it, and the Solution Explorer window flickers the whole time.
 
Is there a better way
 
Ivo


Answer this question

UIHierarchyItem from a ProjectItem

  • wfsCA

    While you can go from a UIHierarchyItem to a ProjectItem, there is no way to go in reverse. There are a few reasons for this, such as a project can be hidden from the solution explorer window, and so going from the ProjectItem to the UIHierarchyItem is impossible, but mostly it was because the project objects were in place long before the UIHierarchyItem object was added to the object model, and adding new methods to the ProjectItem object would break compatibility with existing code, so we never added it.

    Craig



  • lisa52

    You can call ProjectItem.Collection to get to the collection containin the item (a ProjectItems object), then call Parent to get to the item representing the collection. Be careful with what you do with this object! It can be either a ProjectItem or a Project object, depending on where you are in the hierarchy.

    Craig



  • The_Drewster

    Do I do QueryInterface to find which one it is, or just compare the pointer to get_ContainingProject

    Thanks

    Ivo


  • Jordi73757

    You will want to do a QI.

    Craig



  • Daniel Bachler

    I was able to do the same using much simpler solution (VS 2008):

    Code Block

    item.ExpandView();

    var hitem = _findUIHierarchyItem(items, item);

    ...

    UIHierarchyItem _findUIHierarchyItem(UIHierarchyItems items, ProjectItem item) {

    foreach (UIHierarchyItem child in items) {

    if (child.Object == item) return child;

    var result = _findUIHierarchyItem(child.UIHierarchyItems, item);

    if (result != null) return result;

    }

    return null;

    }

    My only problem with this is when there are "Solution Folders" (i.e. virtual folders, VS lets you create) and they are collapsed - ExpandView() throws exception. Note that the solution above (by 280Z28) returns null in such case (the clause handling Project, returns no result because "items" collection is empty).

    The only workaround I could find is to perform fake expand/collapse of "Solution Folders" using the following method. It's not as slow as expanding the whole tree, so it will perform OK in most cases

    Code Block

    try {

    item.ExpandView();

    } catch {

    _loadSolutionItems(items);

    item.ExpandView();

    }

    var hitem = _findUIHierarchyItem(items, item);

    ...

    void _loadSolutionItems(UIHierarchyItems items) {

    var xitems = new List<UIHierarchyItem>();

    foreach (UIHierarchyItem child in items) {

    var pi = child.Object as ProjectItem;

    var pis = child.Object as ProjectItems;

    var project = child.Object as Project;

    var expand = false;

    if ((pi != null) && (pi.Kind == Constants.vsProjectItemKindSolutionItems)) expand = true;

    if ((pis != null) && (pis.Kind == Constants.vsProjectItemsKindSolutionItems)) expand = true;

    if ((project != null) && (project.Kind == Constants.vsProjectKindSolutionItems)) expand = true;

    if (expand && (child.UIHierarchyItems != null) && (child.UIHierarchyItems.Expanded == false)) {

    child.UIHierarchyItems.Expanded = true;

    xitems.Add(child);

    }

    _loadSolutionItems(child.UIHierarchyItems);

    }

    foreach (var item in xitems) {

    item.UIHierarchyItems.Expanded = false;

    }

    }

    Looks ugly, but seems to work OK.


  • sParc134758

    I don't think you realize quite how much speed difference the DFS is compared to the way I did it...

    It's fine on small projects but it's death on big ones. It almost made me want to find the item myself...

    I haven't needed to find solution items yet, but I was aware mine didn't find them. I'll take a look at that sometime.


  • SD Diver

    Takes milliseconds on a solution with 15 projects/6000+ files. Pass a ProjectItem as the second parameter. (See below for a sample call.

    Code Block

    public static EnvDTE.UIHierarchyItem FindHierarchyItem( EnvDTE.UIHierarchyItems items, object item )
    {
    if ( items == null || item == null )
    return null;

    EnvDTE.UIHierarchyItem hitem = ( from i in items.Cast()
    where i.Object == item
    select i )
    .FirstOrDefault();

    if ( hitem != null )
    return hitem;

    EnvDTE.UIHierarchyItem parent = null;

    if ( item is EnvDTE.ProjectItem )
    {
    parent = FindHierarchyItem( items, ( item as EnvDTE.ProjectItem ).Collection.Parent );
    }
    else if ( item is EnvDTE.Project )
    {
    EnvDTE.UIHierarchyItem result = ( from child in items.Cast()
    where !( child.Object is EnvDTE.Project )
    where !( child.Object is EnvDTE.ProjectItems )
    select FindHierarchyItem( child.UIHierarchyItems, item ) )
    .FirstOrDefault();

    return result;
    }
    else if ( item is EnvDTE.Solution )
    {
    // solutions have no parent
    return null;
    }
    else
    {
    parent = ( from child in items.Cast()
    where child != null
    select FindHierarchyItem( child.UIHierarchyItems, item ) )
    .FirstOrDefault();
    }

    if ( parent != null )
    {
    bool expanded = parent.UIHierarchyItems.Expanded;

    if ( !expanded && parent.UIHierarchyItems.Count == 0 )
    {
    try
    {
    parent.UIHierarchyItems.Expanded = true;
    }
    catch
    {
    }
    }

    EnvDTE.UIHierarchyItem found = FindHierarchyItem( parent.UIHierarchyItems, item );

    if ( !expanded && parent.UIHierarchyItems.Expanded )
    {
    try
    {
    parent.UIHierarchyItems.Expanded = false;
    }
    catch
    {
    }
    }

    return found;
    }

    return null;
    }

    Call the function like this:

    Code Block

    // Find the project item for the document

    EnvDTE.ProjectItem item = applicationObject.Solution.FindProjectItem( filename );

    // Get the UIHierarchyItems

    EnvDTE.UIHierarchy uiHierarchy = applicationObject.ToolWindows.SolutionExplorer;

    EnvDTE.UIHierarchyItems items = uiHierarchy.UIHierarchyItems;

    // Convert the ProjectItem into UIHierarchyItem

    EnvDTE.UIHierarchyItem hitem = SolutionFileListControl.FindHierarchyItem( items, item );


  • pxgator

    Thanks. I was expecting that...

    Now another related question - if I have a ProjectItem how do I get the parent ProjectItem And can I assume that the hierarchy of the UIHierarchyItems is the same as the hierarchy of the ProjectItems

    If I have both of these I can do a much smarter search.

    Ivo

     


  • UIHierarchyItem from a ProjectItem