前文介紹 Solution、Project、ProjectItem 的物理層面操作,而方案總管是管理它們的核心 UI 元素。本文專講方案總管的程式化操作。
觀察方案總管與伺服器總管,皆以樹狀結構呈現資料。AOM 中以 UIHierarchy(根節點)、UIHierarchyItems(子節點集合)、UIHierarchyItem(單一節點)表達此結構,遞迴構成完整樹狀,與 Solution、Project、ProjectItem 邏輯對應。
Parent、SelectedItems、UIHierarchyItems、DoDefaultAction()、GetItem()、SelectDown/Up()Expanded、Parent、Item()IsSelected、Name、Select()專案增多時,尋找特定專案/檔案很麻煩。若有一鍵摺疊所有專案的命令,效率大增。

將命令加入方案總管的上下文選單(名稱 "Solution"):
CommandBar slnCommandBar = GetCommandBarByName("Solution");
AddNamedCommand2(slnCommandBar, COLLAPSE_ALL_PROJECTS_COMMAND_NAME,
"Collapse All Projects", "Collapse All Projects", false, 0, slnCommandBar.Controls.Count + 1);
因存在「方案資料夾」(本身也是 Project 但可包含真正專案),查找邏輯需分兩層:
protected UIHierarchy SolutionExplorerNode {
get { return _applicationObject.ToolWindows.SolutionExplorer; }
}
public List<UIHierarchyItem> GetProjectNodes(Solution solution) {
string solutionName = solution.Properties.Item("Name").Value.ToString();
return GetProjectNodes(SolutionExplorerNode.GetItem(solutionName).UIHierarchyItems);
}
public List<UIHierarchyItem> GetProjectNodes(UIHierarchyItems topLevelItems) {
List<UIHierarchyItem> projects = new List<UIHierarchyItem>();
foreach (UIHierarchyItem item in topLevelItems) {
if (IsProjectNode(item)) projects.Add(item);
else if (IsSolutionFolder(item)) GetProjectNodesInSolutionFolder(projects, item);
}
return projects;
}
private void GetProjectNodesInSolutionFolder(List<UIHierarchyItem> projects, UIHierarchyItem item) {
if (!IsSolutionFolder(item)) return;
foreach (UIHierarchyItem subItem in item.UIHierarchyItems) {
if (IsProjectNode(subItem)) projects.Add(subItem);
}
}
private bool IsSolutionFolder(UIHierarchyItem item) {
return (item.Object is Project) && ((item.Object as Project).Kind == ProjectKinds.vsProjectKindSolutionFolder);
}
private bool IsProjectNode(UIHierarchyItem item) {
return IsDirectProjectNode(item) || IsProjectNodeInSolutionFolder(item);
}
private bool IsDirectProjectNode(UIHierarchyItem item) {
return (item.Object is Project) && ((item.Object as Project).Kind != ProjectKinds.vsProjectKindSolutionFolder);
}
private bool IsProjectNodeInSolutionFolder(UIHierarchyItem item) {
return (item.Object is ProjectItem) && ((ProjectItem)item.Object).Object is Project
&& ((Project)((ProjectItem)item.Object).Object).Kind != ProjectKinds.vsProjectKindSolutionFolder;
}
private void CollapseAllProjects() {
Solution sln = _applicationObject.Solution;
List<UIHierarchyItem> projects = GetProjectNodes(sln);
foreach (UIHierarchyItem item in projects) CollapseProject(item);
}
private void CollapseProject(UIHierarchyItem project) {
if (project.UIHierarchyItems.Expanded) {
if (IsDirectProjectNode(project)) project.UIHierarchyItems.Expanded = false;
else if (IsProjectNodeInSolutionFolder(project)) {
project.Select(vsUISelectionType.vsUISelectionTypeSelect);
SolutionExplorerNode.DoDefaultAction();
}
}
}
判斷 Expanded 屬性,若展開則摺疊。直接專案設 Expanded = false;方案資料夾內專案需先選取再觸發預設動作(相當於雙擊/Enter)。
以後面對數十個專案的方案也不必發愁了 :)
本文介紹方案總管樹狀結構操作,以「一鍵摺疊所有專案」為實例,示範 UIHierarchy 族群 API 的實戰應用。下一篇將進入 Add-In 開發重頭戲——文字編輯器操作。
出處:https://anderslly.cnblogs.com
程式碼下載:原始碼 | 可執行 Add-In(解壓後放入 [My Documents]\Visual Studio 2008\Addins)