程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> Team System: 工作項目和撤消支持

Team System: 工作項目和撤消支持

編輯:關於.NET

在本專欄 2007 年 1 月期中 (msdn.microsoft.com/msdnmag/issues/07/01/TeamSystem),我介紹了 如何創建 Microsoft® Word 2003 加載項來與 Team Foundation Server 版本控制子系統協同工作。 在 2007 年 4 月期的專欄中 (msdn.microsoft.com/msdnmag/issues/07/04/TeamSystem),我深入探討了 工作項目跟蹤子系統。在本月的專欄中,我將介紹如何向加載項添加工作項目支持。此外,您還將了解如 何添加原本應出現在第一版本加載項中的功能 — 撤消支持。

更改

在介紹加載項的第一期專欄中,我使用了 Microsoft Visual Studio® 2005 Tools for the 2007 Microsoft Office system 的測試版本(Visual Studio 2005 Tools for Office Second Edition,或簡稱為 VSTO 2005 SE)。從那之後,Microsoft 已經發布了最終版本,該版本支持為 Office 2003 和 2007 Office system 創建應用程序加載項。所以,如果您打算按照該專欄文章中的說明 操作,則需將該加載項的第一個“版本”升級到 RTM 版本。為此,只需在安裝了 VSTO 2005 SE 的計算機上打開該解決方案並重新編譯即可。一旦確認新版本可正常運行,下一步要做的就是添加撤 消掛起的更改支持。該功能要求您修改 tfsvcUtil 類和 ThisAddin 類。

在 tfsvcUtil 中,添加 一個新的共享方法 UndoPendingChanges(該方法可接受目前正在修改的文檔的完整路徑),並讓其返回 布爾值。事實證明,該新方法的核心功能很像現有的 CheckInDocument 方法。該方法會進行檢查,以確 保已與 Team Foundation Server 建立有效連接,並確認加載了有效工作區。這一步完成後,它將為傳入 的文檔獲取一個 PendingChanges 對象數組。假設返回了一項掛起的更改,然後調用用戶工作區的 Undo 方法,傳入 PendingChanges 數組。這一方法應返回整數值 1。如果確實如此,該方法返回 True,否則 便使用新定義的 MSG_UNDO_NOT_ZERO 常量引發 tfsUtilException。圖 1 提供了完整的方法列表。

Figure 1 tfsvcUtil 中的 UndoPendingChanges 方法

Public Shared Function UndoPendingChanges( _
 ByVal docPath As String) As Boolean
 If serverValidated Then
  If m_userWorkspace Is Nothing Then
   Dim userWorkstation As Workstation = Workstation.Current
   Dim docWSInfo As WorkspaceInfo = _
    userWorkstation.GetLocalWorkspaceInfo(docPath)
   m_userWorkspace = m_tfsVCS.GetWorkspace(docWSInfo)
  End If
  Dim pc As PendingChange() = _
   m_userWorkspace.GetPendingChanges(docPath)
  If pc IsNot Nothing AndAlso pc.Length > 0 Then
   Dim retval As Integer = m_userWorkspace.Undo(pc)
   ' Retval should equal the number of items 'undone'
   If retval = 1 Then
    Return True
   Else
    Throw New tfsUtilException(String.Format( _
     MSG_UNDO_NOT_ZERO, docPath, retval))
   End If
  Else
   Return False
  End If
 Else
  Throw New tfsUtilException(MSG_SERVER_NOT_VALIDATED)
 End If
End Function

您需要對 ThisAddIn 類進行的更改非常簡單。像以前一樣,由於篇幅所限,我不 再對 Word 加載項特殊代碼進行更多詳述(您可以將本期專欄的下載內容和以前的版本做比較,看看有些 什麼變化)。毫無疑問,您必須修改該類,為工具欄添加新的“撤消掛起的更改”按鈕,為新 按鈕添加單擊處理程序,並添加其他代碼來處理狀態變化以控制該按鈕是否啟用。基本上,“撤消 掛起的更改”按鈕的啟用狀態應反映現有“簽入”按鈕的狀態。

工作項目支持

為將工作項目與簽入進行關聯添加支持需要進行三組重要更改。首先,需要修改 tfsvcUtil 類, 以支持與工作項目存儲區的連接。其次,需要修改 CheckInDocument 方法,以執行工作項目的實際關聯 。最後,需要修改現有的 frmCheckIn 對話框,以支持列出工作項目,以便用戶選擇其作為簽入的一部分 。

要對工作項目進行編程,可以從 TFSUtil 項目添加對 Microsoft.TeamFoundation.WorkItemTracking.Client.dll 程序集的引用。我在前幾期專欄文章中提到 過,Team Explorer 默認情況下會在全局程序集緩存 (GAC) 中安裝其支持程序集。然而,該安裝程序並 不注冊這些程序集,所以它們在 Visual Studio 2005“添加引用”對話框中不會顯示。您需 要修改注冊表以便讓“添加引用”對話框看到這些程序集,或者手動浏覽這些程序集。您可以 在 %Program Files%\Microsoft Visual Studio 8\Common7\IDE\PrivateAssemblies\ 中找到這些程序集 。

添加引用後,需要修改 tfsvcUtil 類,並在源文件的頂部添加一個 imports 語句,如下所示:

Imports Microsoft.TeamFoundation.WorkItemTracking.Client

目前,當加載項連接 到 Team Foundation Server 框時,它只連接版本控制服務。您可以修改現有的連接方法,以便也連接到 工作項目存儲區。但是,有時也會出現加載項用戶不打算關聯工作項目的情形,這樣就會為連接方法增加 不必要的系統開銷。您可以改為添加單獨調用的新方法來連接到工作項目存儲區。您可以公開該方法;但 是,在多數情況下,現有方法將在開始任何與工作項目相關的操作之前調用此方法。如果與工作項目存儲 區的連接已經到位,那麼該方法實際上成了 no-op。

需要向 tfsvcUtil 類添加一個新的共享方法 ConnectWIS。此方法不接受任何參數,也不返回任何內容。該方法的主體很簡單。首先,它會進行檢查以 確保存在有效的 Team Foundation Server 實例。如果沒有,它會引發異常,因為用戶需要在調用該方法 之前啟動連接。不過,您可以修改加載項的體系結構,以支持嘗試登錄到用戶的默認 Team Foundation Server 安裝。如果服務器可用,可以使用 m_tfs 實例的 GetServiceMethod 與工作項目存儲區建立連接 ,類型化為 TeamFoundationServer 對象:

Public Shared Sub ConnectWIS()
 If Not m_tfs Is Nothing Then
  If tfsvcUtil.m_tfsWIS Is Nothing Then
   tfsvcUtil.m_tfsWIS = CType( _
    m_tfs.GetService(GetType(WorkItemStore)), WorkItemStore)
  End If
 Else
  Throw New tfsUtilException(MSG_SERVER_NOT_VALIDATED)
 End If
End Sub

您會注意到工作項目存儲區引用緩存在類級別變量 m_tfsWIS 中,類型化為 WorkItemStore 對象。需要將此變量添加到類中,如下所示:

Private Shared m_tfsWIS As 

WorkItemStore = Nothing

添加完畢後,需要創建一個重載版本的 CheckInDocument 方法,以 便它通過一個額外的輸入參數匹配現有版本,該參數接受 WorkItemCheckinInfo 實例的數組。接下來, 剪切現有方法的主體,然後將其粘貼到新方法中。修改原始方法,以使它調用新版本,為 WorkItemCheckinInfo 數組傳遞 Nothing。修改過的版本現在僅為一行代碼:

Return 

tfsvcUtil.CheckInDocument(docPath, comment, Nothing)

現在您需要修改 CheckInDocument 中的代碼,檢查是否有任何 WorkItemCheckinInfo 對象傳遞給該方法。如果有,該代碼會調用 ConnectWIS 方法,以確保已經建立與工作項目存儲區的連接。完成後,您可調用 CheckIn 的重載版本( 它可接受 WorkItemCheckinInfo 實例的數組),為簽入說明和策略覆蓋傳遞 Nothing。圖 2 提供了完整 列表。

Figure 2 帶有工作項目支持功能的簽入

Public Shared Function CheckInDocument( _
 ByVal docPath As String, ByVal comment As String, _
 ByVal SelectedWorkItems() As WorkItemCheckinInfo) _
 As Integer
 If serverValidated Then
  If m_userWorkspace Is Nothing Then
   Dim userWorkstation As Workstation = Workstation.Current
   Dim docWSInfo As WorkspaceInfo = _
    userWorkstation.GetLocalWorkspaceInfo(docPath)
   m_userWorkspace = m_tfsVCS.GetWorkspace(docWSInfo)
  End If
  Dim pc As PendingChange() = _
   m_userWorkspace.GetPendingChanges(docPath)
  If pc IsNot Nothing AndAlso pc.Length > 0 Then
   If SelectedWorkItems IsNot Nothing _
    AndAlso SelectedWorkItems.Length > 0 Then
    tfsvcUtil.ConnectWIS()
    Return m_userWorkspace.CheckIn( _
      pc, comment, Nothing, SelectedWorkItems, Nothing)
    Else
     Return m_userWorkspace.CheckIn(pc, comment)
   End If
  Else
   Return -1
  End If
 Else
  Throw New tfsUtilException(MSG_SERVER_NOT_VALIDATED)
 End If
End Function

返回工作項目查詢

此時,您已經為簽入過程添加了工作項目關聯支持。但 是您需要提升 tfsvcUtil 類,以支持返回針對當前“團隊項目”的工作項目查詢列表。此外 ,您還需要一個能運行查詢並向調用方返回工作項目的方法,這樣工作項目可以作為完整簽入體驗的一部 分向用戶顯示。

添加兩個方法便可以實現這一點。方法一:GetWIQ。它能返回 StoredQueriesCollection。方法二: RunWIQ。它接受查詢名稱作為字符串參數,返回一個 WorkItemsCollection 對象。我在本專欄 2007 年 4 月一期 (msdn.microsoft.com/msdnmag/issues/07/04/TeamSystem) 中詳細說明了操作方法。圖 3 提 供了所需的代碼。

Figure 3 GetStoredQueries 和 RunWIQ 方法

Public Shared Function GetStoredQueries(ByVal docPath As String) _
 As StoredQueryCollection
 If IsServerReady Then
  tfsvcUtil.ConnectWIS()
  If m_userWorkspace Is Nothing Then
   Dim userWorkstation As Workstation = Workstation.Current
   Dim docWSInfo As WorkspaceInfo = _
    userWorkstation.GetLocalWorkspaceInfo(docPath)
   m_userWorkspace = m_tfsVCS.GetWorkspace(docWSInfo)
  End If
  Dim vcTeamProject As TeamProject = _
   m_userWorkspace.GetTeamProjectForLocalPath(docPath)
  m_wisProject = m_tfsWIS.Projects(vcTeamProject.Name)
  Return m_wisProject.StoredQueries()
 Else
  Throw New tfsUtilException(MSG_SERVER_NOT_VALIDATED)
 End If
End Function
Public Shared Function RunWIQ(ByVal docPath As String, _
 ByVal WIQ As StoredQuery) As WorkItemCollection
 Dim wiqlToExecute As String = WIQ.QueryText.ToLower()
 Dim params As Hashtable = Nothing
 Dim wic As WorkItemCollection = Nothing
 If wiqlToExecute.Contains(MACRO_PROJECT) Then
  If params Is Nothing Then
   params = New Hashtable
  End If
  params.Add(MACRO_PROJECT.Substring(1), WIQ.Project.Name)
 End If
 If wiqlToExecute.Contains(MACRO_ME) Then
  If params Is Nothing Then params = New Hashtable
  params.Add(MACRO_ME.Substring(1), _
   m_tfsVCS.AuthenticatedUser.Substring( _
   m_tfsVCS.AuthenticatedUser.IndexOf("\"c) + 1))
 End If
 If params IsNot Nothing Then
  wic = m_tfsWIS.Query(wiqlToExecute, params)
 Else
  wic = m_tfsWIS.Query(wiqlToExecute)
 End If
 If wic.Count = 0 Then
  Return Nothing
 Else
  Return wic
 End If
End Function

更新簽入對話框

既然您已編寫好主要代碼,可以在簽入中處理關聯工作項目了,您需要修改現 有簽入對話框來支持工作項目關聯。首先,擴大現有窗體,將大小屬性調整到 640×480 的樣子, 這樣您就有余地調整布局。接下來,向此窗體添加面板控件並將其命名為 pnlComments。然後,從該窗體 中剪切現有文本框 txtComment,將其粘貼到新的面板中,將 Dock 屬性設置為 Fill。需要向 txtComment_TextChanged 事件處理程序重新添加一個 handles 子句,因為現有子句在您剪切文本框時被 刪除了。

需要將名為 grpOptions 的 GroupBox 控件添加到左側的窗體。向分組框添加兩個 RadioButton 控件,分別命名為 rdoComments 和 rdoWorkItems。將它們的 AutoSize 屬性更改為 False ,將 Appearance 屬性改為 Button。將 rdoComments 單選按鈕的 Checked 屬性設置為 True。最後,重 新安排窗體,使其看起來就像圖 4 所示。

圖 4帶有注釋頁的 修改過的簽入對話框

在基本 UI 更改就緒後,您需要添加支持以在單擊“工作項目” 切換按鈕時能在網格中顯示工作項目。向稱為 pnlWorkItems 的窗體添加一個面板控件。在該面板內部添 加兩個面板:pnlSQCombo 和 pnlGridHolder。將 pnlSQCombo 的 Dock 屬性設置為 Top,將 pnlGridHolder 的屬性設為 Fill。然後,您需要向 pnlSQCombo 添加一個標簽和一個組合框控件,向 pnlGridHolder 添加一個 DataGridView 控件。將組合框命名為 cboStoredQueries,將網格命名為 dgvWorkItems。使用智能標記將網格停靠在面板控件中。調整 pnlWorkItems 的大小和位置,讓它們和 pnlComments 相匹配,並將其 Visible 屬性設置為 False。

當用戶單擊“工作項目” 切換按鈕時,單擊事件處理程序將執行必要的操作,使工作項目可用。除非您知道自己始終希望將工作項 目和文檔簽入相關聯,否則為窗體加載時間添加額外系統開銷毫無意義。有一些代碼能實現此目的,其中 大部分都是正確設置 UI 所需的通用 Windows® 窗體代碼。

當單擊“工作項目” 切換按鈕時,操作順序如下所示:加載簽入操作組合框數據源,定義網格列,加載存儲查詢,然後運行 My Work Items 查詢,將查詢結果綁定到網格控件。圖 5 列出了用戶單擊“工作項目”切換 按鈕時被調用的代碼。

Figure 5 rdoWorkItems_Click 事件處理程序

Private Sub rdoWorkItems_Click(ByVal sender As Object, _
 ByVal e As System.EventArgs) Handles rdoWorkItems.Click
 ' Load ComboBox Data Sources
 LoadCheckInActionComboBox()
 ' Define Grid Layout
 DefineWorkItemGrid()
 ' Load WIQs
 LoadStoredQueries()
 For Each sq As StoredQuery In msq
  If sq.Name = "My Work Items" Then
   Me.cboStoredQueries.SelectedItem = sq
   Exit For
  End If
 Next
 ' Run WIQ
 LoadGridData()
 Me.pnlComments.Visible = False
 Me.pnlWorkItems.Visible = True
End Sub

rdoWorkItems_Click 事件處理程序會調用許多支持程序來完成它的工作。 LoadCheckInActionComboBox 為將顯示在網格中的簽入操作組合框初始化數據源。如果檢查 Microsoft 簽入對話框,您將發現,根據選中的工作項目的類型,簽入操作組合框要麼只顯示 Associate 一個字眼 ,要麼顯示 Associate 和 Resolve。模仿這種行為需要在窗體中做一點幕後工作。

為了操作順利 ,您第一步要做的是定義兩個類級別數組:

Private listAssociate(0) As String
Private listAssociateResolve(1) As String

接下來要做的是根據選擇的工作項目的類型,在 這兩個數組間交換簽入操作組合框的數據源。LoadCheckInActionComboBox 會將字符串值加載到數組中。

然後,事件處理程序會運行 DefineWorkItemGrid 將網格控件初始化。此方法會為簽入操作添加 一個未綁定的復選框控件、四個數據綁定文本列(工作項目類型、工作項目 ID、標題和狀態),以及一 個未綁定的組合框控件。接著,rdoWorkItems_Click 會調用 LoadStoredQueries。該方法會調用您先前 創建的 GetStoredQueries 方法。然後,它會將結果數據綁定到 cboStoredQueries 組合框控件。

而在 rdoWorkItems_Click 方法中,代碼會遍歷存儲查詢列表,直到找到 My Work Items 查詢。 一旦找到,該代碼就在 cboStoredQueries 組合框控件中將它設為當前選擇的查詢。然後,該方法會執行 LoadGridData,檢索由 My Work Items 查詢返回的工作項目,並將結果綁定到網格。最後, rdoWorkItems_Click 隱藏注釋面板,顯示工作項目面板。

為了讓網格以類似於 Microsoft 版本 的方式工作,您需要為兩個與網格相關的事件編寫事件處理程序。第一個事件是 CellFormatting。網格 顯示的其中一個列是來自 WorkItem 對象的 Type 屬性。該屬性被類型化為 WorkItemType 對象。您希望 在網格中顯示此對象的 Name 屬性。但遺憾的是,在執行 ToString 方法時,此對象返回的是其完全限定 的類型名稱,而不是其 Name 屬性。要顯示 Name 屬性,需要在 CellFormatting 事件處理程序中更改單 元格的值。本代碼會進行檢查,以確定待格式化的列是否為“工作項目類型”列:

Private Sub dgvWorkItems_CellFormatting(ByVal sender As Object, _
 ByVal e As DataGridViewCellFormattingEventArgs) _
 Handles dgvWorkItems.CellFormatting
 If e.ColumnIndex = typeColumnIndex Then
  If e.Value IsNot Nothing Then
   Dim wit As WorkItemType = CType(e.Value, WorkItemType)
   e.Value = wit.Name
   e.FormattingApplied = True
  End If
 End If
End Sub

如果的確是,而且單元格的值不為空,那麼該代碼就會從單元格中檢索 WorkItemType 實例,將單元格的值更改為 Name 屬性的值。

接下來,需要為 Current-CellDirtyStateChanged 事件實現一個事件處理程序。在此處理程序中,您要根據所選的工作項目的類型來更改簽入操作組合框的 數據源。編寫代碼以使它僅在復選框列的狀態更改時才執行。

要了解數據源應該是什麼,您需要 訪問綁定到當前行的 WorkItem 對象。獲得數據源以後,您可以調用它的 GetNextState 方法,傳入 Microsoft.VSTS.Actions.Checkin 的一個字符串值。該代碼將進行檢查,以核實是否存在來自簽入的有 效狀態轉換。如果存在,該代碼會收到一個有效字符串,指示組合框應顯示 Associate 和 Resolve 兩者 。如果沒有檢索到有效字符串,則只能顯示 Associate。這樣,該代碼就會設置正確的數據源,然後提交 當前編輯,更改復選框的狀態。

然後,該代碼會檢查復選框的值,如果已經被設置為選中 (True) ,簽入操作組合框就會被啟用,成為激活控件,編輯即開始。如果復選框返回到未選中狀態,該代碼會重 置組合框。圖 6 提供了相關的詳細信息。

Figure 6 完整的 CurrentCellDirtyStateChanged 事件處理程序

Private Sub 

dgvWorkItems_CurrentCellDirtyStateChanged( _
  ByVal sender As Object, ByVal e As System.EventArgs) _
  Handles dgvWorkItems.CurrentCellDirtyStateChanged
  Dim c As DataGridViewCell = dgvWorkItems.CurrentCell
  If c.ColumnIndex = checkedColumnIndex Then
    Dim dcb As DataGridViewComboBoxCell = _
      CType(dgvWorkItems(comboBoxColumnIndex, _
      c.RowIndex), DataGridViewComboBoxCell)
    Dim currentRow As DataGridViewRow = dgvWorkItems.Rows(c.RowIndex)
    Dim wi As WorkItem = CType(currentRow.DataBoundItem, WorkItem)
    Dim nextState As String = _
      wi.GetNextState("Microsoft.VSTS.Actions.Checkin")
    If String.IsNullOrEmpty(nextState) Then
      dcb.DataSource = listAssociate
    Else
      dcb.DataSource = listAssociateResolve
    End If
    dgvWorkItems.CommitEdit( _
      DataGridViewDataErrorContexts.CurrentCellChange)
    If CBool(c.Value) Then
      dcb.ReadOnly = False
      dcb.Value = dcb.Items.Item(0)
      dgvWorkItems.CurrentCell = dcb
      dgvWorkItems.BeginEdit(True)
    Else
      dcb.Value = Nothing
      dcb.ReadOnly = True
    End If
  End If
End Sub

您為了處理工作項目而需要添加的最後一部分代碼是通過在 FormClosing 事件中創建 WorkItemCheckinInfo 對象數組而開發的(參見圖 7)。創建此數組的方法是遍歷網格行,創建 WorkItemCheckinInfo 實例(如果已選中復選框列)。創建 WorkItemCheckinInfo 實例時,指定簽入操 作。除此方法以外,您還需要將一個公共屬性 WorkItems 添加到窗體,以便在對話框關閉時可以檢索到 該數組。該屬性應在 FormClosing 方法的末尾設置。

Figure 7 frmCheckIn 對話框中的 FormClosing 事件處理程序

Private Sub 

frmCheckIn_FormClosing( _
  ByVal sender As Object, ByVal e As FormClosingEventArgs) _
  Handles Me.FormClosing
  Dim chkCol As DataGridViewCell
  Dim cboCol As DataGridViewCell
  Dim wiciList As New List(Of WorkItemCheckinInfo)
  Dim cia As WorkItemCheckinAction = WorkItemCheckinAction.None
  For Each row As DataGridViewRow In Me.dgvWorkItems.Rows
    chkCol = row.Cells(checkedColumnIndex)
    If CBool(chkCol.Value) Then
      ' Item is selected
      cboCol = row.Cells(comboBoxColumnIndex)
      Select Case cboCol.Value.ToString()
        Case "Associate"
          cia = WorkItemCheckinAction.Associate
        Case "Resolve"
          cia = WorkItemCheckinAction.Resolve
        Case Else
          cia = WorkItemCheckinAction.None
      End Select
      wiciList.Add(New WorkItemCheckinInfo( _
        CType(row.DataBoundItem, WorkItem), cia))
    End If
  Next
  If wiciList.Count > 0 Then
    Me.WorkItems = wiciList.ToArray()
  Else
    Me.WorkItems = Nothing
  End If
End Sub

最後細節

您會在窗體中找到一些其他代碼,用來處理存儲查詢組合框的 SelectedValueChanged 事件。為支持 工作項目而為加載項所做的最後一步是在 Word 加載項中修改 ThisAddIn 類的 cbbCheckInDoc_Click 方 法。修改過的版本僅進行簡單檢查,確定對話框的新 WorkItems 屬性是否有數據。如果有,說明已經調 用新版本的 CheckInDocument 方法。否則,說明還在執行舊版本。圖 8 顯示了使用工作項目的已完成簽 入體驗。

圖 8 帶有工作項目支持功能的完成的簽入對話框

此時,如果您運行加載項,可以向源控件添加一個文檔、通過注釋和關聯工作項目將其簽入和簽出, 甚至撤消掛起的更改。到這一步,很多工作都已經完成,但仍有很多工作可做。在本專欄的下一期中,我 將介紹添加簽入說明和策略支持,也許還會談到其他有趣的功能。

請將您想詢問的問題和提出的意見發送至 [email protected].

本文配套源碼:http://www.bianceng.net/dotnet/201212/829.htm

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved