Dynamic Hierarchy Sample

This sample demonstrates how to create a hierarchy window that dynamically adds hierarchy nodes to the existing hierarchy. The sample also demonstrates how to nest hierarchies (how to create hierarchy shortcuts). The hierarchy is a file hierarchy where the folders and files of a root node are added as child nodes. However, you can expand folder nodes at any hierarchy level to see subfolders and files.
The implementation has two points of interest:
  • Subfolders and files are queried dynamically when you expand the hierarchy node.
  • If a folder is a system folder, a new hierarchy represented that system folder is created and nested into the parent hierarchy.
Package source code:

using System.Runtime.InteropServices;
using Microsoft.VisualStudio.Shell;
using VSXtra.Commands;
using VSXtra.Package;

namespace DeepDiver.DynamicHierarchy
{
  [PackageRegistration(UseManagedResourcesOnly = true)]
  [DefaultRegistryRoot("Software\\Microsoft\\VisualStudio\\9.0")]
  [InstalledProductRegistration(false, "#110", "#112", "1.0", IconResourceID = 400)]
  [ProvideLoadKey("Standard", "1.0", "DynamicHierarchy", "DeepDiver", 1)]
  [ProvideMenuResource(1000, 1)]
  [XtraProvideToolWindow(typeof(DynamicUIHierarchyWindow))]
  [Guid(GuidList.guidDynamicHierarchyPkgString)]
  public sealed class DynamicHierarchyPackage : PackageBase
  {
    [CommandExecMethod]
    [CommandId(GuidList.guidDynamicHierarchyCmdSetString, CmdIDs.cmdidShowDynamicHierarchy)]
    [ShowToolWindowAction(typeof(DynamicUIHierarchyWindow))]
    private static void ShowBasicUIHierarchyWindow()
    {
    }
  }
}
Hierarchy tool window pane source code:

using VSXtra.Hierarchy;
using VSXtra.Windows;

namespace DeepDiver.DynamicHierarchy
{
  [InitialCaption("Dynamic Hierarchy Window")]
  [BitmapResourceId(301)]
  [LinesAtRoot]
  [DoNotSortRootNodes]
  public sealed class DynamicUIHierarchyWindow : UIHierarchyToolWindow<DynamicHierarchyPackage>
  {
    protected override HierarchyManager<DynamicHierarchyPackage> HierarchyManager
    {
      get { return new FileHierarchyManager("C:\\"); }
    }
  }
}
File hierarchy manager class source code:

using System;
using System.IO;
using VSXtra.Hierarchy;

namespace DeepDiver.DynamicHierarchy
{
  public sealed class FileHierarchyManager : HierarchyManager<DynamicHierarchyPackage>
  {
    private readonly string _FullPath;
    public FileHierarchyManager(string fullPath)
    {
      _FullPath = fullPath;
    }
    protected override HierarchyNode CreateHierarchyRoot()
    {
      return new RootNode(null, _FullPath, _FullPath);
    }
    protected override void InitializeHierarchyRoot(HierarchyNode root)
    {
      var fileRoot = root as FileHierarchyNode;
      if (fileRoot == null) return;
      ScanContent(fileRoot);
    }
    public void ScanContent(FileHierarchyNode node)
    {
      if (node == null) throw new ArgumentNullException("node");
      try
      {
        var dirInfo = new DirectoryInfo(node.FullPath);
        foreach (var dir in dirInfo.GetDirectories())
        {
          var dirName = dir.Name;
          FolderNode folderNode;
          if ((dir.Attributes & FileAttributes.System) != 0)
          {
            folderNode = new SystemFolderNode(this, dir.FullName, dirName);
            folderNode.NestHierarchy(new FileHierarchyManager(dir.FullName));
          }
          else
          {
            folderNode = new FolderNode(this, dir.FullName, dirName);
            folderNode.AddChild(new NotLoadedNode(this));
          }
          node.AddChild(folderNode);
          folderNode.IsExpanded = false;
        }
        foreach (var file in Directory.GetFiles(node.FullPath))
        {
          var fileNode = new FileNode(this, file, Path.GetFileName(file));
          node.AddChild(fileNode);
        }
      }
      catch (SystemException)
      {
        // --- This exception is intentionally supressed.
      }
    }
  }
}
Abstract file hierarchy node source code:

using VSXtra.Hierarchy;

namespace DeepDiver.DynamicHierarchy
{
  [SortPriority(-1)]
  public abstract class FileHierarchyNode : HierarchyNode
  {
    private readonly FileHierarchyManager _Manager;
    protected FileHierarchyNode(FileHierarchyManager manager, string caption)
      : base(manager, caption)
    {
      Loaded = false;
      _Manager = manager;
    }
    public FileHierarchyNode(FileHierarchyManager manager, string fullPath, string caption) : 
      base(manager, caption)
    {
      FullPath = fullPath;
      _Manager = manager;
    }
    public bool Loaded { get; set; }
    public string FullPath { get; private set; }
    protected override void OnBeforeExpanded()
    {
      if (!Loaded && FirstChild is NotLoadedNode)
      {
        RemoveChild(FirstChild);
        if (_Manager != null) _Manager.ScanContent(this);
        InvalidateItem();
      }
      Loaded = true;
    }
  }
}
Root hierarchy node source code:

using VSXtra.Hierarchy;

namespace DeepDiver.DynamicHierarchy
{
  [HierarchyBitmap("RootImage")]
  public sealed class RootNode : FileHierarchyNode
  {
    public RootNode(FileHierarchyManager manager, string fullPath, string caption) : 
      base(manager, fullPath, caption)
    {
    }
  }
}
Folder node source code:

using VSXtra.Hierarchy;

namespace DeepDiver.DynamicHierarchy
{
  [HierarchyBitmap("FolderImage")]
  [SortPriority(20)]
  public class FolderNode : FileHierarchyNode
  {
    public FolderNode(FileHierarchyManager manager, string fullPath, string caption) : 
      base(manager, fullPath, caption)
    {
    }
  }
}
File node source code:

using VSXtra.Hierarchy;

namespace DeepDiver.DynamicHierarchy
{
  [HierarchyBitmap("FileImage")]
  [SortPriority(30)]
  public sealed class FileNode : FileHierarchyNode
  {
    public FileNode(FileHierarchyManager manager, string fullPath, string caption) : 
      base(manager, fullPath, caption)
    {
    }
  }
}
Node representing that the children of a folder are not yet loaded:

using VSXtra.Hierarchy;

namespace DeepDiver.DynamicHierarchy
{
  [HierarchyBitmap("NotLoadedImage")]
  [SortPriority(10)]
  public sealed class NotLoadedNode : FileHierarchyNode
  {
    public NotLoadedNode(FileHierarchyManager manager)
      : base(manager, "The content of the node has not been loaded yet")
    {
    }
  }
}
Node representing a system folder (root node of a nested hierarchy):

using VSXtra.Hierarchy;

namespace DeepDiver.DynamicHierarchy
{
  [HierarchyBitmap("SystemFolderImage")]
  public sealed class SystemFolderNode : FolderNode
  {
    public SystemFolderNode(FileHierarchyManager manager, string fullPath, string caption) : 
      base(manager, fullPath, caption)
    {
    }
  }
}
Screenshots:

DynamicHierarchyToolWindow1.png

Last edited Dec 14, 2008 at 6:45 PM by INovak, version 2

Comments

No comments yet.