逐步解說: 將整合至 [屬性] 視窗、 工作清單,輸出] 視窗中及選項] 對話方塊 (步驟 4 之 4)
藉由使用Visual Studio SDK,您可以啟用程式碼能夠存取中的任何工具視窗Visual Studio。 比方說,您可以在其中新增項目至工作清單,新增文字至 輸出 ] 視窗中,或整合到您的擴充 屬性視窗,讓使用者可以藉由設定屬性來設定擴充功能。 這個逐步解說會示範如何將您的擴充功能整合至工具視窗中Visual Studio。
藉由完成這個逐步解說中,您可以瞭解如何執行下列動作:
使用封裝範本,以建立 VSPackage。
實作產生的工具視窗。
實作功能表命令處理常式。
建立選項] 頁面。
讓資料可用於屬性視窗。
如果需要整合的 [屬性] 視窗。
新增文字至輸出 ] 視窗和項目 工作清單。
這個逐步解說會教導如何擴充 Visual Studio 的 IDE 的一系列的一部份。 如需詳細資訊,請參閱 使用 VSPackages 自訂 Visual Studio 的逐步解說。
必要條件
若要完成這個逐步解說中,您必須安裝Visual Studio 2010 SDK。
注意事項 |
---|
如需有關 Visual Studio 的 SDK 的詳細資訊,請參閱擴充 Visual Studio 的概觀。若要了解如何下載 Visual Studio 的 SDK,請參閱Visual Studio 擴充性開發人員中心 MSDN 網站上。 |
Visual Studio 的封裝專案範本的位置
Visual Studio 的封裝的專案範本,請參閱以下三個不同的位置,在新的專案對話方塊:
在 [Visual Basic 擴充性。 專案的預設語言是 Visual Basic。
在 [C# 擴充性。 專案的預設語言是 C#。
在 [其他專案的型別擴充性。 專案的預設語言是 c + +。
使用 Visual Studio 的封裝範本來建立 VSPackage
若要建立 VSPackage
建立 VSPackage。 如需有關如何建立 VSPackage 的詳細資訊,請參閱逐步解說: 使用 Visual Studio 的封裝範本建立功能表命令。
為專案名稱, TodoList,視覺 C# 或 Visual Basic,然後在設定的語言 選取 VSPackage 選項 頁面上,選取兩個 功能表命令 和 工具視窗。
在命令選項頁面上,設定 指令名稱到 Todo 管理員 和 命令 ID 到 cmdidTodoCommand。
在工具視窗選項頁面上,設定 視窗名稱 到 Todo 管理員 和 命令 ID 到 cmdidTodoTool。
按一下 [完成] 按鈕。
實作產生的工具視窗
封裝範本會產生基本的工具視窗,在使用者控制項的表單。 不過,它會有任何功能。 若要為功能,您必須加入子控制項,並修改 MyControl.xaml.cs 或 MyControl.vb 中的程式碼。
工具視窗會包含TextBox供輸入新的 ToDo 項目中, Button將新的項目新增至] 清單中,以及ListBox的項目顯示在清單上。 已完成的工具視窗應該類似下圖:
若要將控制項加入至 [工具] 視窗
刪除方格中的按鈕、 文字和 StackPanel 控制項。
注意事項 這並不會刪除 button1_Click 的事件處理常式中,您要重複用於後續的步驟。
從所有的 WPF 控制項 一節的 工具箱,拖曳 畫布控制項至格線。
將文字方塊控制項、 按鈕控制項,以及 [ListBox] 控制項拖曳到畫布上。 將它們排列如上圖所示。
選取 [按鈕]。 設定其內容 屬性,以 新增。
在 [XAML] 窗格中,重新連線] 按鈕事件處理常式至按鈕控制項加上,按一下 ="button1_Click"屬性。 產生 XAML 行,看起來應該像這樣:
Public _parent As MyToolWindow Public Sub New(ByVal parent As MyToolWindow) InitializeComponent() _parent = parent End Sub
<Button Content="Add" Height="21" Name="button1" Width="50" Canvas.Left="345" Canvas.Top="6" Click="button1_Click" />
儲存您的工作。
預設情況下,在 MyControl.xaml.cs 或 MyControl.xaml.vb 檔案中的使用者控制項建構函式會接受任何參數。 不過,您可以自訂建構函式,加入其他參數,讓您可以儲存以供稍後使用父代。
若要自訂建構函式
從設計工具] 頁面上,以滑鼠右鍵按一下檢視程式碼。
下列程式碼取代現有的建構函式:
public MyToolWindow _parent; public MyControl(MyToolWindow parent) { InitializeComponent(); _parent = parent; }
如此一來可讓建構函式的參數型別的MyToolWindow。
儲存您的工作。
現在,加入一個參數來呼叫建構函式的程式碼。
在方案總管] 中,開啟 MyToolWindow.cs 或 MyToolWindow.vb。
尋找類似下列的程式碼的 MyToolWindow 建構函式中的行。
Me.Content = New MyControl()
base.Content = new MyControl();
變更線條如下所示。
Me.Content = New MyControl(Me)
base.Content = new MyControl(this);
執行這項操作時,會將工具視窗的執行個體傳遞至使用者控制項。 (這是接下來的步驟中建立所需的 ToDoItem 類別的建構函式。)
實作功能表命令處理常式
當建立 TodoList 專案後時,它會包含功能表項目的預設處理常式。 這個處理常式是在 TodoListPackage 檔案中。 現在,加入要顯示 [工具] 視窗的處理常式的程式碼。 您可以在幾個步驟中因為 TodoListPackage 已包含名為 ShowToolWindow 的函式。
若要實作功能表項目處理常式
開啟 TodoListPackage.cs 或 TodoListPackage.vb。 請注意功能表項目處理常式會包含下列的範例程式碼。
Private Sub MenuItemCallback(ByVal sender As Object, ByVal e As EventArgs) ' Show a Message Box to prove we were here Dim uiShell As IVsUIShell = TryCast(GetService(GetType(SVsUIShell)), IVsUIShell) Dim clsid As Guid = Guid.Empty Dim result As Integer Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(uiShell.ShowMessageBox(0, clsid, "TodoList", String.Format(CultureInfo.CurrentCulture, "Inside {0}.MenuItemCallback()", Me.GetType().Name), String.Empty, 0, OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST, OLEMSGICON.OLEMSGICON_INFO, 0, result)) End Sub
private void MenuItemCallback(object sender, EventArgs e) { // Show a Message Box to prove we were here IVsUIShell uiShell = (IVsUIShell)GetService(typeof(SVsUIShell)); Guid clsid = Guid.Empty; int result; Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(uiShell.ShowMessageBox( 0, ref clsid, "TodoList", string.Format(CultureInfo.CurrentCulture, "Inside {0}.MenuItemCallback()", this.ToString()), string.Empty, 0, OLEMSGBUTTON.OLEMSGBUTTON_OK, OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST, OLEMSGICON.OLEMSGICON_INFO, 0, // false out result)); }
在函式中,移除所有項目,然後取代成呼叫ShowToolWindow ,如下所示。
Private Sub MenuItemCallback(ByVal sender As Object, ByVal e As EventArgs) ShowToolWindow(sender, e) End Sub
private void MenuItemCallback(object sender, EventArgs e) { ShowToolWindow(sender, e); }
儲存您的工作,然後按下 F5 以建置專案,並在 Visual Studio 的實驗建置中開啟它。 測試是否在 [工具] 視窗隨即開啟,即可 ToDo 管理員 的 工具功能表。
在繼續前,請關閉實驗性質的組建。
建立選項頁
您可以提供頁面選項 ,讓使用者可以變更 [工具] 視窗中的設定] 對話方塊。 建立選項] 頁面需要兩個類別所描述的選項和 TodoListPackage.cs 或 TodoListPackage.vb 檔案中的項目。
若要建立的 [選項] 頁面
在方案總管] 中ToDoList 專案上按一下滑鼠右鍵,指向 新增,然後按一下 類別。
在加入新項目 對話方塊中,為檔案命名 ToolsOptions.cs,或 ToolsOptions.vb ,然後按一下 [ 新增。
Visual Studio建立類別,名為 ToolsOptions,在這個檔案中,但您必須先修改類別的標頭檔,使類別衍生自DialogPage。
新增Microsoft.VisualStudio.Shell加入現有的命名空間使用/imports 指示詞,如下所示。
Imports Microsoft.VisualStudio.Shell
using Microsoft.VisualStudio.Shell;
修改ToolsOptions類別宣告,以繼承自DialogPage。
Inherits DialogPage
class ToolsOptions : DialogPage
在這個逐步解說中的 [選項] 頁面只會提供一種名為 DaysAhead 的選項。 若要加入此選項,新增名為 DaysAhead 到 ToolsOptions 類別,如下所示。
Private _daysAhead As Double Public Property DaysAhead() As Double Get Return _daysAhead End Get Set(ByVal value As Double) _daysAhead = value End Set End Property
private double _daysAhead; public double DaysAhead { get { return _daysAhead; } set { _daysAhead = value; } }
這個類別會儲存為私用成員,名為 _daysAhead 的單一選項。 然後此類別會提供名為 DaysAhead,用來存取選項的公用屬性。
儲存檔案。
現在您必須先專案掌握這個 [選項] 頁面,讓它將會正確地註冊並提供給使用者。
若要讓使用者可以使用 [選項] 頁面
在方案總管,開啟 TodoListPackage.cs 或 TodoListPackage.vb。
尋找內含ProvideToolWindowAttribute屬性,然後再新增ProvideOptionPageAttribute屬性之後,如下所示。
<PackageRegistration(UseManagedResourcesOnly:=True), _ InstalledProductRegistration("#110", "#112", "1.0", IconResourceID:=400), _ ProvideMenuResource("Menus.ctmenu", 1), _ ProvideToolWindow(GetType(MyToolWindow)), _ ProvideOptionPage(GetType(ToolsOptions), "To-Do", "General", 101, 106, True), _ Guid(GuidList.guidTodoListPkgString)> _ Public NotInheritable Class TodoListPackage Inherits Package
[ProvideToolWindow(typeof(MyToolWindow))] [ProvideOptionPage(typeof(ToolsOptions), "To-Do", "General", 101, 106, true)]
注意事項 您沒有將這個字 '屬性' 包含在屬性宣告。
儲存檔案。
ProvideOptionPage 建構函式的第一個參數是類別的 ToolsOptions,您稍早建立型別。 第二個參數,也就是 「 待辦事項 」 是類別目錄中的名稱選項對話方塊。 第三個參數中,[一般],就是子類別名稱選項會使用 [選項] 頁面的對話方塊。 接下來的兩個參數是資源識別碼字串。 第一個是類別的名稱,而第二個是子類別的名稱。 最後一個參數會設定是否可以使用自動化來存取此頁面。
存取您的 [選項] 頁面時,程式碼應該類似下列的圖片。
請注意 [待辦事項] 類別目錄,一般的子類別。
提供資料給 [屬性] 視窗
以下為良好的物件導向設計原則,您可以讓類別,名為 ToDoItem 儲存待辦事項清單中的個別項目的相關資訊。
若要使 [屬性] 視窗中的可用資料
在方案總管] 中ToDoList 專案上按一下滑鼠右鍵,指向 新增,然後按一下 類別。
在加入新項目 對話方塊中,為檔案命名 ToDoItem.cs 或 ToDoItem.vb,然後按一下 [ 新增。
使用者可以使用 [工具] 視窗時,清單方塊中的項目就會以 ToDoItem 執行個體來表示。 當使用者選取其中一個項目在清單方塊中, 屬性視窗會顯示項目的相關資訊。
若要使資料屬性 ] 視窗中,使資料類別的公用屬性加入,然後記錄下來,使用兩個特殊的屬性,描述和類別。 描述會顯示在底部的文字屬性視窗。 分類會定義屬性應該會出現的時機屬性會顯示在 [分類] 檢視。 在下列圖片中, 屬性 視窗是在 [分類] 檢視中, 名稱 屬性在 待辦事項欄位 選取分類時,和描述 名稱屬性會顯示在視窗的底部。
現有使用/imports 陳述式之後,請將加入 ToDoItem.cs 或 ToDoItem.vb 檔案,上方的下列命名空間。
Imports System.ComponentModel Imports System.Windows.Forms Imports Microsoft.VisualStudio.Shell.Interop
using System.ComponentModel; using System.Windows.Forms; using Microsoft.VisualStudio.Shell.Interop;
開始實作 ToDoItem 類別,如下所示。 請加入public在類別宣告的存取修飾詞。
Private _name As String <Description("Name of the To-Do item")> _ <Category("To-Do Fields")> _ Public Property Name() As String Get Return _name End Get Set(ByVal value As String) _name = value _parent.UpdateList(Me) End Set End Property Private _dueDate As Date <Description("Due date of the To-Do item")> _ <Category("To-Do Fields")> _ Public Property DueDate() As Date Get Return _dueDate End Get Set(ByVal value As Date) _dueDate = value _parent.UpdateList(Me) _parent.CheckForErrors() End Set End Property
public class ToDoItem { private string _name; [Description("Name of the To-Do item")] [Category("To-Do Fields")] public string Name { get { return _name; } set { _name = value; _parent.UpdateList(this); } } private DateTime _dueDate; [Description("Due date of the To-Do item")] [Category("To-Do Fields")] public DateTime DueDate { get { return _dueDate; } set { _dueDate = value; _parent.UpdateList(this); _parent.CheckForErrors(); } } }
請注意這段程式碼有兩個屬性的名稱和 DueDate。 這些是兩個屬性,會出現在屬性 ] 視窗中,如上圖所示。 每個屬性的開頭的描述和類別屬性,提供的資訊,以顯示在屬性視窗。 請檢查名稱] 屬性中 ; 這兩種屬性 字串必須符合圖片中。
在類別的頂端加入下列建構函式。
Private _parent As MyControl Public Sub New(ByVal parent As MyControl, ByVal name As String) _parent = parent _name = name _dueDate = Date.Now Dim daysAhead As Double = 0 Dim package As IVsPackage = TryCast(_parent._parent.Package, IVsPackage) If package IsNot Nothing Then Dim obj As Object package.GetAutomationObject("To-Do.General", obj) Dim options As ToolsOptions = TryCast(obj, ToolsOptions) If options IsNot Nothing Then daysAhead = options.DaysAhead End If End If _dueDate = _dueDate.AddDays(daysAhead) End Sub
private MyControl _parent; public ToDoItem(MyControl parent, string name) { _parent = parent; _name = name; _dueDate = DateTime.Now; double daysAhead = 0; IVsPackage package = _parent._parent.Package as IVsPackage; if (package != null) { object obj; package.GetAutomationObject("To-Do.General", out obj); ToolsOptions options = obj as ToolsOptions; if (options != null) { daysAhead = options.DaysAhead; } } _dueDate = _dueDate.AddDays(daysAhead); }
首先,這段程式碼會宣告名為 _parent,相對於使用者控制項,其中包含您稍早建立的文字方塊、 按鈕和清單方塊控制項的私用成員。 建構函式會接受使用者控制項,做為參數,加上這個 ToDo 的項目名稱的字串。 建構函式中的前三行儲存的使用者控制項、 變更名稱、 和目前日期和時間。
您可以使用 [為基礎的目前日期和時間,啟用您稍早建立的 [選項] 頁面上的 [DaysAhead] 選項。 因為目前的日期和時間平常不會用為到期的日期,可以繼續目前的日期,由 [選項] 頁面中指定的天數。 .
程式碼宣告區域變數呼叫daysAhead ,使用設定的值中的 [DaysAhead] 選項。 下一行會取得使用者控制項,並從該處,套件成員的父系。 (這是在此您可以使用您先前加入至 MyControl.xaml.cs 類別 _parent 成員)。
如果此套件成員不是 null 時,所要包含的 ToolsOptions 執行個體宣告的物件。 若要取得之執行個體,程式碼會呼叫 GetAutomationObject 成員的封裝和傳遞類別和次類別的名稱做為單一點分隔的字串,為 Do.General。 結果會在回 obj 變數當做輸出參數傳遞。
Obj 變數然後轉換為 ToolsOptions 類別並儲存在變數中名為options。 如果這個變數不是 null,程式碼會取得DaysAhead成員,並儲存成_daysAhead變數。
程式碼再往前推進 _duedate變數根據往前所使用的天數AddDays方法。
因為執行個體的ToDoItem類別就會儲存在清單方塊和清單方塊會呼叫ToString函式,這個類別會繼承自基底Object類別來擷取要顯示項目的字串,您必須多載ToString函式。
建構函式之後,以及類別結尾之前,則您可以加入 ToDoItem.cs,下列程式碼。
Public Overloads Overrides Function ToString() As String Return (_name & " Due: ") + _dueDate.ToShortDateString() End Function
public override string ToString() { return _name + " Due: " + _dueDate.ToShortDateString(); }
開啟 MyControl.xaml.cs 或 MyControl.xaml.vb。
將虛設常式的方法加入至 MyControl 類別,如CheckForError和UpdateList方法。 將指令碼放在 ProcessDialogChar 之後,以及檔案的結尾之前。
Public Sub CheckForErrors() End Sub Public Sub UpdateList(ByVal item As ToDoItem) End Sub Public Sub CheckForErrors() End Sub Public Sub UpdateList(ByVal item As ToDoItem) End Sub
public void CheckForErrors() { } public void UpdateList(ToDoItem item) { }
CheckForError方法會呼叫在父物件,具有相同名稱的方法,該方法會檢查是否發生任何錯誤,並正確地處理它們。 UpdateList方法會更新的清單方塊中的父控制項。 當呼叫此方法Name和DueDate屬性,這個類別的變更。 在接下來的步驟中,您將實作這些方法。
在 [屬性] 視窗中整合
現在撰寫程式碼,可管理清單方塊中,將會繫結至屬性視窗。
您必須加入讀取文字方塊、 建立 ToDoItem 執行個體,並將該執行個體加入至清單方塊的按鈕之控制代碼。
使用 [屬性] 視窗來整合
切換至 [設計] 檢視的 MyControl.xaml,然後按兩下 [Button] 控制項
取代現存的button1_Click藉由使用下列程式碼的處理函式。
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles Button1.Click If TextBox1.Text.Length > 0 Then Dim item = New ToDoItem(Me, TextBox1.Text) ListBox1.Items.Add(item) TrackSelection() CheckForErrors() End If End Sub
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1300:SpecifyMessageBoxOptions")] private void button1_Click(object sender, EventArgs e) { if (textBox1.Text.Length > 0) { var item = new ToDoItem(this, textBox1.Text); listBox1.Items.Add(item); TrackSelection(); CheckForErrors(); } }
這段程式碼會建立新的 ToDoItem 執行個體,並將使用者控制項執行個體傳遞做為參數加上文字方塊控制項中的使用者輸入的文字。 接下來,程式碼會將項目加入至清單方塊。 (清單方塊會呼叫 ToString 方法來擷取要顯示在清單方塊中的字串的 ToDoItem 執行個體)。 接下來,程式碼會呼叫 TrackSelection 函式,您將撰寫在接下來的步驟。 最後,程式碼會檢查有錯誤。
切換至 [設計] 檢視的 MyControl.xaml,若要新增處理使用者選取新的項目,清單方塊中的程式碼。
按一下 [ListBox] 控制項。 在屬性 視窗中,連按兩下 [SelectionChanged 事件。 執行這項操作時,新增 SelectionChanged 的處理常式的虛設常式,並將它設定為該事件。
請填入 SelectionChanged 處理常式中,如下所示,並設定虛設常式的方法中呼叫。
Private Sub ListBox1_SelectionChanged(ByVal sender As System.Object, ByVal e As System.Windows.Controls.SelectionChangedEventArgs) Handles ListBox1.SelectionChanged TrackSelection() End Sub Private Sub TrackSelection() End Sub
private void listBox1_SelectionChanged(object sender, EventArgs e) { TrackSelection(); } private void TrackSelection() { }
儲存您的工作。 您可以建置專案,並尋找錯誤的校正。
現在,在 TrackSelection 函式,將會提供與整合填滿屬性視窗。 當使用者新增到清單方塊的項目,或按一下清單方塊中的項目時,會呼叫此函數。
您已經有一個類別, 屬性 視窗可以使用,您可以將整合 屬性與 [工具] 視窗的視窗。 當使用者按一下 [工具] 視窗中,在清單方塊中的項目屬性視窗應該隨之更新。 同樣地,當使用者變更中的 ToDo 項目時,才屬性 ] 視窗中,應更新關聯的項目。
注意事項 或者,您可能會產生PropertyChanged直接藉由實作的事件INotifyPropertyChanged介面。
將更新程式碼置於屬性 TrackSelection 函式中的視窗。 執行此動作會將繫結的 ToDoItem 物件,以屬性視窗。 您不需要撰寫任何額外的程式碼在使用者變更中的值時,請修改 ToDoItem 屬性視窗。 屬性 ] 視窗會自動呼叫set屬性存取子,以更新值。 不過,您必須完成您所撰寫的 ToDoItem 類別的程式碼時,您所建立的 UpdateList 方法。
現有使用/imports 陳述式之後,則您可以加入 MyControl.xaml.cs 或 MyControl.vb 檔案中,頂端的下列命名空間宣告。
Imports System Imports System.Runtime.InteropServices Imports Microsoft.VisualStudio.Shell.Interop Imports Microsoft.VisualStudio Imports Microsoft.VisualStudio.Shell
using System.Runtime.InteropServices; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Shell;
請實作 TrackSelection 函式,如下所示。
Private mySelContainer As SelectionContainer Private mySelItems As System.Collections.ArrayList Private frame As IVsWindowFrame = Nothing Private Sub TrackSelection() If frame Is Nothing Then Dim shell = TryCast(GetService(GetType(SVsUIShell)), IVsUIShell) If shell IsNot Nothing Then Dim guidPropertyBrowser = New Guid(ToolWindowGuids.PropertyBrowser) shell.FindToolWindow(CUInt(__VSFINDTOOLWIN.FTW_fForceCreate), guidPropertyBrowser, frame) End If End If If frame IsNot Nothing Then frame.Show() End If If mySelContainer Is Nothing Then mySelContainer = New SelectionContainer() End If mySelItems = New System.Collections.ArrayList() Dim selected = TryCast(listBox1.SelectedItem, ToDoItem) If selected IsNot Nothing Then mySelItems.Add(selected) End If mySelContainer.SelectedObjects = mySelItems Dim track = TryCast(GetService(GetType(STrackSelection)), ITrackSelection) If track IsNot Nothing Then track.OnSelectChange(mySelContainer) End If End Sub
private SelectionContainer mySelContainer; private System.Collections.ArrayList mySelItems; private IVsWindowFrame frame = null; private void TrackSelection() { if (frame == null) { var shell = GetService(typeof(SVsUIShell)) as IVsUIShell; if (shell != null) { var guidPropertyBrowser = new Guid(ToolWindowGuids.PropertyBrowser); shell.FindToolWindow((uint)__VSFINDTOOLWIN.FTW_fForceCreate, ref guidPropertyBrowser, out frame); } } if (frame != null) { frame.Show(); } if (mySelContainer == null) { mySelContainer = new SelectionContainer(); } mySelItems = new System.Collections.ArrayList(); var selected = listBox1.SelectedItem as ToDoItem; if (selected != null) { mySelItems.Add(selected); } mySelContainer.SelectedObjects = mySelItems; var track = GetService(typeof(STrackSelection)) as ITrackSelection; if (track != null) { track.OnSelectChange(mySelContainer); } }
只在 TrackSelection 函式結尾之後,加入下列程式碼。
Protected Function GetService(ByVal service As Type) As Object Dim obj As Object = Nothing If _parent IsNot Nothing Then obj = _parent.GetVsService(service) End If Return obj End Function
protected object GetService(Type service) { if (_parent != null) { return _parent.GetVsService(service); } return null; }
這段程式碼會呼叫 GetService 函式。 這個函式第一次嘗試取得服務從父代的工具視窗藉由呼叫它的 GetService 函式。 如果這樣仍然失敗,它會嘗試取得物件的 GetService 函式。 在父代的工具視窗中的 GetService 函式不是公用的因為程式碼會呼叫而 GetVsService。 您必須將 GetVsService 函式。
開啟 MyToolWindow.cs 或 MyToolWindow.vb。 下列程式碼加入類別,在檔案結尾之前的結尾。
Friend Function GetVsService(ByVal service As Type) As Object Return GetService(service) End Function
internal object GetVsService(Type service) { return GetService(service); }
儲存檔案。
第一次 TrackSelection 函式在執行時,它會呼叫以取得的執行個體的 GetService Visual Studio殼層。 然後,它使用該執行個體來取得物件的屬性視窗。 若要取得屬性 window 物件,藉由使用 GUID,表示在程式碼啟動 屬性視窗。 ([工具] 視窗的 Guid 是成員的ToolWindowGuids80類別。) 程式碼然後呼叫 FindToolWindow 函式的介面,藉由傳遞的 GUID,以取得屬性視窗物件。 如此一來儲存在框架變數,讓函式呼叫時,取得這個處理程序屬性視窗不會重複出現。
接下來,方法會呼叫 Show 方法顯示框架變數的屬性視窗。
下一個程式碼會蒐集的清單方塊中選取的項目。 若要啟用 [多重選取未設定清單方塊。 要傳遞至選取的項目屬性 ] 視窗中,您必須使用容器。 因此,程式碼蒐集選取的項目,並將它放在陣列清單中,然後再使該陣列清單 SelectionContainer 型別的容器中。
接下來,程式碼會呼叫以取得的 ITrackSelection,也就是執行個體的 GetService Visual Studio會追蹤所選取的物件的使用者介面 (UI) 中的物件,並顯示其屬性。 然後程式碼直接呼叫 ITrackSelection OnSelectChange 事件處理常式,並傳遞為存有選取的項目 SelectionContainer。 結果是屬性 ] 視窗會顯示所選項目的內容。
在使用者變更中的 ToDoItem 物件屬性 ] 視窗中, 屬性 ] 視窗會自動呼叫set ToDoItem 物件中的存取子函式。 可更新的物件,但您仍要更新的清單方塊。
在先前步驟中,您會增加程式碼,在set呼叫 MyControl.xaml.cs 或 MyControl.xaml.vb 的 UpdateList 函式的存取子函式。 現在,加入 UpdateList 函式程式碼的其餘部分。
從 MyControl.xaml.cs 或 MyControl.xaml.vb,實作 UpdateList 方法,如下所示。
Public Sub UpdateList(ByVal item As ToDoItem) Dim index As Integer = ListBox1.SelectedIndex listBox1.Items.RemoveAt(index) listBox1.Items.Insert(index, item) ListBox1.SelectedItem = index End Sub
public void UpdateList(ToDoItem item) { var index = listBox1.SelectedIndex; listBox1.Items.RemoveAt(index); listBox1.Items.Insert(index, item); listBox1.SelectedItem = index; }
這段程式碼會判斷哪些項目已選取,並將對應於要修改之 ToDoItem。 程式碼會從清單方塊中,移除項目,並再重新插入。 如此一來,更新項目的清單方塊中的行。 然後程式碼會設定選取範圍至相同的項目。
儲存您的工作。
將文字加入至輸出視窗] 和 [工作清單的項目
若要加入字串,以工作清單 和 輸出 ] 視窗中,您必須先取得參考的兩個視窗物件。 然後,您也可以在物件上呼叫方法。 對於工作清單,您建立新的物件型別工作,然後再新增 [該 Task 物件,以 工作清單藉由呼叫它的 Add 方法。 要寫入至輸出 ] 視窗中,您呼叫 GetPane 方法來取得 pane 物件,然後再呼叫 pane 物件的 OutputString 方法。
若要將文字加入至輸出視窗] 和 [工作清單
開啟 MyControl.xaml.cs 或 MyControl.xaml.vb。
插入下列程式碼來呼叫之前將它展開 button1_Click 方法TrackSelection()。
Dim outputWindow = TryCast(GetService(GetType(SVsOutputWindow)), IVsOutputWindow) Dim pane As IVsOutputWindowPane Dim guidGeneralPane As Guid = VSConstants.GUID_OutWindowGeneralPane outputWindow.GetPane(guidGeneralPane, pane) If pane IsNot Nothing Then pane.OutputString(String.Format("To Do item created: {0} \r\n", item.ToString())) End If
private void button1_Click(object sender, EventArgs e) { if (textBox1.Text.Length > 0) { var item = new ToDoItem(this, textBox1.Text); listBox1.Items.Add(item); //Insert this section------------------ var outputWindow = GetService( typeof(SVsOutputWindow)) as IVsOutputWindow; IVsOutputWindowPane pane; Guid guidGeneralPane = VSConstants.GUID_OutWindowGeneralPane; outputWindow.GetPane(ref guidGeneralPane, out pane); if (pane != null) { pane.OutputString(string.Format( "To Do item created: {0}\r\n", item.ToString())); } //------------------------------------- TrackSelection(); CheckForErrors(); }
這段程式碼會取得該物件的輸出視窗。 物件會公開 IVsOutputWindow 介面。 程式碼,然後取得 IVsOutputWindowPane 物件,其中包含 OutputString 函式,最後將寫入輸出視窗。
現在實作 CheckForErrors 方法,,如下所示。
Public Sub CheckForErrors() For Each item As ToDoItem In ListBox1.Items If item.DueDate < DateTime.Now Then ReportError("To Do Item is out of date: " & item.ToString()) End If Next End Sub
public void CheckForErrors() { foreach (ToDoItem item in listBox1.Items) { if (item.DueDate < DateTime.Now) { ReportError("To Do Item is out of date: " + item.ToString()); } } }
這段程式碼會呼叫 ReportError 方法中,您將接下來,建立與其他方法,以新增項目一起工作清單。
下列程式碼加入類別,在兩個右大括號之前的結尾。
<Guid("72de1eAD-a00c-4f57-bff7-57edb162d0be")> _ Public Class MyTaskProvider Inherits TaskProvider Public Sub New(ByVal sp As IServiceProvider) MyBase.New(sp) End Sub End Class Private _taskProvider As MyTaskProvider Private Sub CreateProvider() If _taskProvider Is Nothing Then _taskProvider = New MyTaskProvider(_parent) _taskProvider.ProviderName = "To Do" End If End Sub Private Sub ClearError() CreateProvider() _taskProvider.Tasks.Clear() End Sub Private Sub ReportError(ByVal p As String) CreateProvider() Dim errorTask = New Task() errorTask.CanDelete = False errorTask.Category = TaskCategory.Misc errorTask.Text = p _taskProvider.Tasks.Add(errorTask) _taskProvider.Show() Dim taskList = TryCast(GetService(GetType(SVsTaskList)), IVsTaskList2) If taskList Is Nothing Then Exit Sub End If Dim guidProvider = GetType(MyTaskProvider).GUID taskList.SetActiveProvider(guidProvider) End Sub
[Guid("72de1eAD-a00c-4f57-bff7-57edb162d0be")] public class MyTaskProvider : TaskProvider { public MyTaskProvider(IServiceProvider sp) : base(sp) { } } private MyTaskProvider _taskProvider; private void CreateProvider() { if (_taskProvider == null) { _taskProvider = new MyTaskProvider(_parent); _taskProvider.ProviderName = "To Do"; } } private void ClearError() { CreateProvider(); _taskProvider.Tasks.Clear(); } private void ReportError(string p) { CreateProvider(); var errorTask = new Task(); errorTask.CanDelete = false; errorTask.Category = TaskCategory.Misc; errorTask.Text = p; _taskProvider.Tasks.Add(errorTask); _taskProvider.Show(); var taskList = GetService(typeof(SVsTaskList)) as IVsTaskList2; if (taskList == null) { return; } var guidProvider = typeof(MyTaskProvider).GUID; taskList.SetActiveProvider(ref guidProvider); }
在這段程式碼開始一特定的 TaskProvider 類別稱為 MyTaskProvider,其中包含 GUID。 接下來是這種新類別,後面跟著一種方法,必要時,會建立新的執行個體成員變數。
接下來是兩個重要方法、 ClearError,可清除現有的工作項目和 ReportError,將項目來新增工作清單。
ReportError 方法會建立新的執行個體的工作、 初始化執行個體,然後加入執行個體與工作清單。 新工作清單 項目才看得見,當使用者選取頂端的下拉式清單中的 ToDo 的項目 工作清單。 最後兩行程式碼中的自動從下拉式清單中選取 [ToDo 的項目,並將新的工作項目帶入檢視。 TaskProvider 類別會繼承,是因為 SetActiveProvider 方法所要求的 GUID,以做為參數時,需要的 GUID。
試用一下
若要測試擴充功能
按 CTRL + F5,若要開啟的實驗建置Visual Studio。
在實驗性質的組建中,在工具 ] 功能表中,按一下 ToDo 管理員。
開啟您所設計的工具視窗。
在文字方塊中輸入一些文字,然後按一下 [ 新增。
您應該會看到此項目加入清單方塊。
輸入其他名稱,然後按一下新增一次。
當加入項目時,起始日期設定為目前的日期和時間。 發生錯誤,也是中的項目,這樣會觸發工作清單。
在檢視 ] 功能表中,按一下 輸出 開啟 輸出視窗。
請注意每次您新增一個項目,會顯示一則訊息,在工作清單窗格。
按一下其中一個清單方塊中的項目。
屬性 ] 視窗會顯示兩個項目的屬性。
變更其中一個屬性,然後按 ENTER 鍵。
項目會更新清單方塊中。
下一步
在這個逐步解說中,您建立工具視窗中的另一個工具視窗與Visual Studio。 Visual Studio有數個工具視窗,您可以使用,而且可以在中找到這些 Guid ToolWindowGuids類別。 您也可以建立包含內容的類別, 屬性可以存取視窗。 您提供存取子函式屬性 ] 視窗使用。 在set存取子函式,呼叫您自己的程式碼來處理中所做的變更成屬性視窗。 此舉可以提供雙向通訊機制。 最後,您學到如何將項目來新增工作清單、 如何帶入檢視中的項目,以及如何新增文字至 輸出視窗。