Implementing 'Show All Files' in a Visual Studio project.
This article shows how a project implementer in Visual Studio 2005 can handle the "Show All Files" command to show/hide nodes (that may or may not represent files on disk). Before I proceed, it's important to mention that, in my projects, I don't use the MPF classes. I've developed my own classes that wrap the interop interfaces and I've added my own logic to them. Therefore, some of the examples in this article, may need to be modified before they are used in a different project system.
This article supposes that you are familiar with:
-Developing a project system and managing the contents of the project hierarchy.
-Handling commands through an IOleCommandTarget interface. (The IVsUIHierarchy interface, handles commands almost the same way)
Prerequisites:
1) A collection that holds all hierarchy events clients that request to be advised about your hierarchy events through
Microsoft.VisualStudio.Shell.Interop.IVsHierarchy.AdviseHierarchyEvents().
2) One or more specific classes (or base classes like FileNode of the MPF), that will be used to represent your extra nodes in the project
hierarchy.
3) A method that iterates through the members of the hierarchy events clients and advises them of any changes.
4) A variable that holds a project specific value that indicates the current view mode (Normal/ViewAll).
The Implementation:
Clients that wish to be advised of project hierarchy events, request to be added to our list of clients through IVsHierarchy.AdviseHierarchyEvents. The very first such client calls this method is the solution (IVsSolution) itself. By ignoring this call, we simply cannot inform the solution of any changes in out project hierarchy structure. The MPF classes handle this method internally and, as far as I know, inheritors don't have access to the private hierarchyEventSinks list, created and used in the HierarchyNode class. Those using the MPF classes will have to override AdviseHierarchyEvents and add extra code after calling the base class or, go change the access of the hierarchyEventSinks field to public (easy since if you are using the MPF classes, you have to include the actual source code of the project model in your project).
Private m_HierarchyEventsClient As New Dictionary(Of UInt32, IVsHierarchyEvents)
...
#Region " AdviseHierarchyEvents "
Protected Overridable Function AdviseHierarchyEvents(ByVal pEventSink As IVsHierarchyEvents, ByRef pdwCookie As UInteger) As Integer Implements IVsHierarchy.AdviseHierarchyEvents, IVsUIHierarchy.AdviseHierarchyEvents
If m_IsDisposed Then
Return VSConstants.E_UNEXPECTED
End If
If m_ReleasedCookies.Count = 0 Then
pdwCookie = CUInt(m_HierarchyEventsClient.Count + 1)
m_HierarchyEventsClient.Add(pdwCookie, pEventSink)
Else
pdwCookie = m_ReleasedCookies(0)
m_HierarchyEventsClient(pdwCookie) = pEventSink
m_ReleasedCookies.Remove(pdwCookie)
End If
Return VSConstants.S_OK
End Function
#End Region
(Example of implementing the AdviseHierarchyEvents() method)
Friend Overloads Sub AdviseClients(ByVal propid As Int32)
If Me.Project.HierarchyEventsClients.Count > 0 Then
Dim clientID As UInt32
For Each clientID In Me.Project.HierarchyEventsClients.Keys
Dim client As IVsHierarchyEvents = Me.Project.HierarchyEventsClients(clientID)
If client IsNot Nothing Then
Try
client.OnPropertyChanged(m_ItemID, propid, 0)
Catch ex As Exception
Me.Project.UnadviseHierarchyEvents(clientID)
End Try
End If
Next
End If
End Sub
' This accepts an array that allows us to fire multiple events
' using a single call.
Friend Overloads Sub AdviseClients(ByVal propid() As Int32)
If (propid IsNot Nothing) AndAlso _
(propid.Length > 0) Then
Dim p As Int32
For Each p In propid
Me.AdviseClients(p)
Next
End If
End Sub
(Example of a method that iterates through the hierarchy events clients collection and informs them of any changes. m_ItemID is the item id of the item in the project hierarchy that fires the event. In our case this will most possibly be the project node.)
Handling the "Show All Files" command:
Next thing we do is handle the VSStd2KCmdID.SHOWALLFILES command through our implementation of IVsUIHierarchy.QueryStatusCommand and IVsUIHierarchy.ExecCommand(). In MPF we will have to override the QueryStatus() and ExecCommand() of the base HierarchyNode.
Private Overloads Function QueryStatusCommand(ByVal itemid As UInteger, ByRef pguidCmdGroup As System.Guid, ByVal cCmds As UInteger, ByVal prgCmds() As Microsoft.VisualStudio.OLE.Interop.OLECMD, ByVal pCmdText As System.IntPtr) As Integer Implements IVsUIHierarchy.QueryStatusCommand
If m_IsDisposed Then
Return VSConstants.E_UNEXPECTED
End If
If pguidCmdGroup = VSConstants.VSStd2K Then
Select Case prgCmds(0).cmdID
...
Case VSConstants.VSStd2KCmdID.SHOWALLFILES
If m_ViewMode = EProjectMode.Normal Then
prgCmds(0).cmdf = CUInt(OLECMDF.OLECMDF_SUPPORTED Or OLECMDF.OLECMDF_ENABLED)
Else
prgCmds(0).cmdf = CUInt(OLECMDF.OLECMDF_SUPPORTED Or OLECMDF.OLECMDF_ENABLED Or OLECMDF.OLECMDF_LATCHED)
End If
Return VSConstants.S_OK
...
End Select
...
End If
End Function
(Example of implementing IVsUIHierarchy.ExecCommand())
Private Overloads Function ExecCommand(ByVal itemid As UInteger, ByRef pguidCmdGroup As System.Guid, ByVal nCmdID As UInteger, ByVal nCmdexecopt As UInteger, ByVal pvaIn As System.IntPtr, ByVal pvaOut As System.IntPtr) As Integer Implements IVsUIHierarchy.ExecCommand
If m_IsDisposed Then
Return VSConstants.E_UNEXPECTED
End If
...
If pguidCmdGroup = VSConstants.VSStd2K Then
Select Case nCmdID
Case VSConstants.VSStd2KCmdID.SHOWALLFILES
If m_ViewMode = EProjectMode.Normal Then
m_ViewMode = EProjectMode.ViewAll
' In MPF we would simple create the new FileNode objects
' here and add the to the project before calling AdviseClients()
Else
m_ViewMode = EProjectMode.Normal
' In MPF we would remove any nodes from the project here
' before calling AdviseClients()
End If
m_ProjectFolder.AdviseClients(New __VSHPROPID() _
{__VSHPROPID.VSHPROPID_Expandable, _
__VSHPROPID.VSHPROPID_FirstChild, _
__VSHPROPID.VSHPROPID_ExpandByDefault, _
__VSHPROPID.VSHPROPID_Expanded})
Return VSConstants.S_OK
...
End Select
...
Else
Return OLEInterop.Constants.OLECMDERR_E_UNKNOWNGROUP
End If
End Function
(Example of implementing IVsUIHierarchy.ExecCommand())
In the last example above, m_ViewMode represents our internal variable that holds a project specific value indicating the current view mode. When the event is fired, the solution (IVsSolution), that is also added in our list of hierarchy events clients, will immediately call IVsHierarchy.GetProperty() to obtain the new structure of the project hierarchy. In MPF, we can simply instantiate all the new nodes that we need to appear, or remove them depending on the current view mode and before calling AdviseClients(). The MPF base classes would then take care of populating the hierarchy.
For implementers of a project that uses the MPF classes, this article has ended here!
Private Overloads Function GetProperty(ByVal itemid As UInteger, ByVal propid As Integer, ByRef pVar As Object) As Integer Implements IVsHierarchy.GetProperty, IVsUIHierarchy.GetProperty
Select Case propid
Case __VSHPROPID.VSHPROPID_FirstChild, __VSHPROPID.VSHPROPID_FirstVisibleChild
Select Case m_ViewMode
Case EProjectMode.Normal
' Return the first item id depending on view mode.
...
Case EProjectMode.ViewAll
' Return the first item id depending on view mode.
...
End Select
...
Return New UIntPtr(VSConstants.VSITEMID_NIL)
...
End Select
End Function
(Example of implementing the IVsHierarchy.GetProperty() method on the project node or any file or folder node that has children we want to appear only when Show All Files is selected.)
Private Overloads Function GetProperty(ByVal itemid As UInteger, ByVal propid As Integer, ByRef pVar As Object) As Integer Implements IVsHierarchy.GetProperty, IVsUIHierarchy.GetProperty
Select Case propid
Case __VSHPROPID.VSHPROPID_NextSibling, __VSHPROPID.VSHPROPID_NextVisibleSibling
Select Case m_ViewMode
Case EProjectMode.Normal
' Return the next item id depending on view mode.
...
Case EProjectMode.ViewAll
' Return the next item id depending on view mode.
...
End Select
...
Return New UIntPtr(VSConstants.VSITEMID_NIL)
...
End Select
End Function
(Example of implementing the IVsHierarchy.GetProperty() method on the any file or folder node.)
This concludes this brief article describing how to implement the "Show All Files" feature in Visual Studio 2005.