The Amadeus.NET Blog

Development, Projects, Plans and Ideas on .NET, Visual Studio, Windows XP & Vista

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.

Leave a Comment

(required) 

(required) 

(optional)

(required) 


Please add 3 and 8 and type the answer here: