前言
在可擴展性開發(五)中,我介紹了對於Solution、Project、ProjectItem的基本操 作。可以認為它們面向的是解決方案內容的物理(文件)表示,我們需要使用VS提供的解 決方案管理器(Solution Explorer)來管理它們。毫無疑問,解決方案管理器是VS中最 重要的UI元素之一,本文將介紹對它的操作。
工具窗口內的層次結構
如果你觀察一下解決方案管理器和服務器管理器(Server Explorer),就會發現它們 都使用樹形結構來表現背後的數據。在AOM中,UIHierarchy、UIHierarchyItems和 UIHierarchyItem用於表示這樣的層次結構。UIHierarchy表示根節點,它的 UIHierarchyItems集合表示其所包含的第一級子節點(UIHierarchyItem),每一個 UIHierarchyItem同時也有UIHierarchyItems屬性,如此遞歸下去。這種結構很像它們所 表示的數據:Solution、Project以及ProjectItem。在使用這些對象之前,先大致了解一 下它們的主要成員:
1)UIHierarchy
Parent:節點對象的父節點;
SelectedItems:當前節點選中的子節點集合;
UIHierarchyItems:當前節點的子節點集合;
DoDefaultAction():對節點進行默認操作,類似於進行雙擊或按下回車鍵;
GetItem():按指定路徑返回一個子節點;
SelectDown():選中當前選中節點的下個節點;
SelectUp():選中當前選中節點的上個節點;
更多信息請參看MSDN。
2)UIHierarchyItems集合
Expanded:獲取或設置所表示的節點是否已展開;
Parent:節點集合的父節點;
Item():返回集合中的一項;
更多信息請參看MSDN。
3)UIHierarchyItem
IsSelected:獲取節點是否被選中;
Name:節點對象的名稱;
Select():選中節點;
更多信息請參看MSDN。
有了這些知識,我們現在有能力去探索對解決方案管理器的操作了。
CollapseAllProjects示例
項目剛開始的時候,項目的數量也許還不太多,隨著程序規模的增大,項目數量也會 不斷增加,這時要找到某個項目或者某個文件,就變得越來越麻煩,你得先把大量的項目 折疊起來。如果有一個命令,可以快速地折疊起所有項目,就方便多了:
這裡的思路很簡單,只要找到所有的項目節點,依次查看每個項目,如果項目展開了 ,就把它折疊起來。
0)添加命令
之前我們曾添加過CloseAllDocuments和NPetshopSlnGenerator命令(見可擴展性開發 四、五),它們分別加在文本編輯器的標簽和Tools菜單上,這裡的過程沒什麼不同:
C# Code - 添加CollapseAllProjects命令
OnConnection()
{
// Get "Solution Explorer" command bar
CommandBar slnCommandBar = GetCommandBarByName("Solution");
// Add a new command
AddNamedCommand2(slnCommandBar, COLLAPSE_ALL_PROJECTS_COMMAND_NAME,
"Collapse All Projects", "Collapse All Projects", false, 0, slnCommandBar.Controls.Count + 1);
}
QueryStatus()
{
else if (commandName == GetCommandFullName (COLLAPSE_ALL_PROJECTS_COMMAND_NAME))
{
status = (vsCommandStatus) vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled;
return;
}
}
Exec()
{
else if (commandName == GetCommandFullName (COLLAPSE_ALL_PROJECTS_COMMAND_NAME))
{
CollapseAllProjects();
handled = true;
return;
}
}
這裡通過“Solution”找到解決方案節點的上下文菜單。
1)找到所有項目節點
C# Code - 查找所有的項目節點
/// <summary>
/// Solution Explorer Window
/// </summary>
protected UIHierarchy SolutionExplorerNode
{
get
{
return _applicationObject.ToolWindows.SolutionExplorer;
}
}
/// <summary>
/// Gets project nodes.
/// </summary>
public List<UIHierarchyItem> GetProjectNodes(Solution solution)
{
string solutionName = solution.Properties.Item ("Name").Value.ToString();
return GetProjectNodes(SolutionExplorerNode.GetItem (solutionName).UIHierarchyItems);
}
/// <summary>
/// Gets the project nodes.
/// </summary>
/// <param name="root">The root.</param>
/// <returns></returns>
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);
}
也許比預想的要復雜些,主要的原因是解決方案文件夾的存在,解決方案文件夾本身 也被看作Project對象,同時它又可以包含其它真正的項目,所以在查找項目的時候要分 兩種情況。先查找解決方案下面的項目,然後再查找解決方案文件夾下面的項目。
2)折疊所有項目節點
C# Code - 折疊所有項目節點
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屬性判斷它是否已展開,如果是的話將 其折疊起來,此時也要分兩種情況進行考慮。
以後就不用再為那些包含數十個項目的解決方案發愁了:)
可以從這裡下載代碼,也可以在這裡下載可運行的Add-In(解壓縮後將文件放在[My Documents Path]\Visual Studio 2008\Addins下)。
我們身在何處?
在解決方案、項目和項之後,本文介紹了對解決方案管理器的操作,現在我們有辦法 來解決這些方面的問題了。接下來,我將介紹Add-In開發的重頭戲——文本編輯器的操作 。