7. VSTO Bug Tracker : Using Document-Level Features in Add-Ins
Prior to Visual Studio 2008 SP1, you couldn’t use common VSTO features like controls in the document and databinding to list objects at the add-in level. But with SP1 we introduced a way for you to use these features at the add-in level. In this section some of the wierd ways Idid things in section 4 will start to make more sense—I designed the code in Section 4 to be easily portable to an add-in.
One thing that won’t port to the add-in level is cached data—that feature only works when code is at the document level.
Choose File > Add > New Project.. and create a new Excel add-in project. I’ll be using VB in this example.
Add a web reference to the BugService as described in Article 4. Be sure to name the reference BugService.
Now, double click on your ThisAddIn file. In the ThisAddIn class, add this as a member variable. We won’t be adding any our dataset as a member variable because we can’t cache it at the add-in level, so there is no reason to make it a class member variable.
Public buttonDictionary As New Dictionary(Of Excel.Worksheet, Microsoft.Office.Tools.Excel.Controls.Button)
Next, we will put some calls to our AddListObjectAndButton function. Add an event handler for the NewWorkbook, WorkbookBeforeClose, and WorkbookOpen events. You will also put some code in ThisAddIn_Startup. Also, handle the SheetBeforeRightClick event temporarily until we add a ribbon in the next article—this will make it so that if you right click on a worksheet, the bug data will be added to the workbook.
Private Sub ThisAddIn_Startup(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Startup
If Application.ActiveWorkbook IsNot Nothing Then
PopulateSpreadsheet(False)
End If
End Sub
Private Sub ThisAddIn_Shutdown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shutdown
End Sub
Private Sub Application_NewWorkbook(ByVal Wb As Excel.Workbook) Handles Application.NewWorkbook
PopulateSpreadsheet(False)
End Sub
Private Sub Application_SheetBeforeRightClick(ByVal Sh As Object, ByVal Target As Microsoft.Office.Interop.Excel.Range, ByRef Cancel As Boolean) Handles Application.SheetBeforeRightClick
PopulateSpreadsheet(True)
End Sub
Private Sub Application_WorkbookBeforeClose(ByVal Wb As Excel.Workbook, ByRef Cancel As Boolean) Handles Application.WorkbookBeforeClose
CleanUpDynamicButton()
End Sub
Private Sub Application_WorkbookOpen(ByVal Wb As Excel.Workbook) Handles Application.WorkbookOpen
PopulateSpreadsheet(False)
End Sub
The rest of the code is almost identical to the code we wrote in Article 4. PopulateSpreadsheet has these changes from the document to the add-in level.
1) Instead of the line “vstoSheet = GetVstoObject(s)” it changes to “vstoSheet = s.GetVstoObject()”. At the add-in level, GetVstoObject is an extension method to the Microsoft.Office.Interop.Excel.Worksheet type.
2) We don’t have the “If NeedsFill(“bugDataSet”)” if clause—cached data isn’t supported at the add-in level.
3) Since bugDataset isn’t needed to be declared at the class member level due to no cached data, we declare it local in PopulateSpreadsheet. Also you might need to add an “Imports System.Data" to the top of the file.
4) We’ll also add a line at the top of PopulateSpreadsheet to detect if the name of the active workbook is “BugWorkbook”—the wokrbook we created in Section 4. If it is, we’ll immediately return so as not to have our add-in conflict with our document level solution.
Other than these four changes, the remaining code should look very familiar:
Public Sub PopulateSpreadsheet(ByVal alwaysAdd As Boolean)
If Application.ActiveWorkbook.Name = "BugWorkbook" Then Exit Sub
Dim foundList As Excel.ListObject = Nothing
Dim s As Excel.Worksheet = Nothing
Dim bugDataset As DataSet
foundList = FindList()
' If not there create it if always add is true
If foundList Is Nothing Then
If alwaysAdd = True Then
s = Application.ActiveSheet
foundList = s.ListObjects.AddEx(Excel.XlListObjectSourceType.xlSrcRange, s.Range("A1", "D2"))
foundList.Name = "BugListObject"
Else
Exit Sub
End If
Else
s = TryCast(foundList.Parent, Excel.Worksheet)
End If
' Dynamically create the list object
Dim vstoSheet As Microsoft.Office.Tools.Excel.Worksheet
vstoSheet = s.GetVstoObject()
' Do we already have a listobject, if so exit.
If vstoSheet.Controls.Contains("BugListObject") Then
Exit Sub
End If
Dim list As Microsoft.Office.Tools.Excel.ListObject = vstoSheet.Controls.AddListObject(foundList)
'If NeedsFill("bugDataset") Then
Application.StatusBar = "Updating data from bug web service..."
Dim bugService As BugService.BugService = New BugService.BugService()
bugDataset = bugService.BulkDataExport("", "")
'End If
list.AutoSetDataBoundColumnHeaders = True
list.DataSource = bugDataset.Tables(0)
list.Range.Columns.AutoFit()
list.Disconnect()
Dim buttonRange As Excel.Range = s.Range("E1")
Dim pivotButton As Microsoft.Office.Tools.Excel.Controls.Button
pivotButton = vstoSheet.Controls.AddButton(buttonRange, "CreatePivotTable")
buttonDictionary.Add(s, pivotButton)
AddHandler pivotButton.Click, AddressOf pivotButton_Click
pivotButton.Text = "Pivot"
Application.StatusBar = ""
s.Name = "Bug Data"
s.Activate()
End Sub
Private Function FindList() As Excel.ListObject
' Do we already have a created list object?
Dim l As Excel.ListObject = Nothing
Dim s As Excel.Worksheet = Nothing
For Each s In Application.ActiveWorkbook.Worksheets
For Each l In s.ListObjects
If l.Name = "BugListObject" Then
Return l
End If
Next
Next
Return Nothing
End Function
Private Sub pivotButton_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Dim s As Excel.Worksheet = Nothing
Dim pivotCache As Excel.PivotCache
Dim pivotTables As Excel.PivotTables
Dim pivotTable As Excel.PivotTable
Dim pivotField As Excel.PivotField
s = Application.ActiveWorkbook.Worksheets.Add()
pivotCache = s.Parent.PivotCaches.Create(Excel.XlPivotTableSourceType.xlDatabase, FindList().Range, Excel.XlPivotTableVersionList.xlPivotTableVersion12)
pivotTables = s.PivotTables()
pivotTable = pivotTables.Add(pivotCache, s.Range("A1"))
pivotTable.AddDataField(pivotTable.PivotFields(4))
pivotTable.AddFields("Date")
pivotField = pivotTable.PivotFields("Column")
pivotField.Orientation = Excel.XlPivotFieldOrientation.xlPageField
pivotField.CurrentPage = "Active"
pivotField = pivotTable.PivotFields("Team")
pivotField.Orientation = Excel.XlPivotFieldOrientation.xlPageField
Dim project As String = InputBox("Enter the team", "Team name", "Project - Office Client")
pivotField.CurrentPage = project
s.Name = project
End Sub
Private Sub CleanUpDynamicButton()
Try
Dim l As Excel.ListObject = FindList()
If (l Is Nothing) Then
Exit Sub
End If
Dim vstoButton As Microsoft.Office.Tools.Excel.Controls.Button
vstoButton = buttonDictionary(l.Parent)
RemoveHandler vstoButton.Click, AddressOf pivotButton_Click
buttonDictionary.Remove(l.Parent)
Catch ex As Exception
End Try
End Sub
Now, when you run this add-in and right click on the worksheet, the bugs dataset will be added to the workbook along with the “Pivot” button.
Next up, we’ll enhance our solution with a custom ribbon.
Comments
- Anonymous
May 14, 2009
PingBack from http://microsoft-sharepoint.simplynetdev.com/7-vsto-bug-tracker-using-document-level-features-in-add-ins/