Catching Rename Events

"How do I trap rename file events in Solution Explorer and cancel the event if it happens?"

Great question! As with many things in Visual Studio Extensibility, there is a way to accomplish this with both Macros/Add-ins and with VSIP. First let’s take a look at the DTE way. To catch the rename events for files and other project items, you need to do something slightly different than you would with solution item events. Since the project item types are language-specific, you need to do late-binding. Let’s consider catching file rename events in Visual Basic. In the macros editor, add the following code to the EnvironmentEvents module:

 

    <System.ContextStaticAttribute()> _

    Public WithEvents vbProjectItemsEvents As EnvDTE.ProjectItemsEvents

At this point, you are not yet catching VB project items. We need to assign vbProjectItemsEvents to an instance of a new EnvDTE.ProjectItemsEvents object. The most opportune place for this to occur is when Visual Studio starts up. We can catch this in the DTEEvents.OnStartupComplete event:

Public Sub DTEEvents_OnStartupComplete() _

Handles DTEEvents.OnStartupComplete

vbProjectItemsEvents = _
DTE.Events.GetObject("VBProjectItemsEvents")

End Sub

The next step is to write the event handler. This is actually kind of tricky do to a bug in Visual Studio 2003. The following code will NOT work correctly:

Public Sub vbProjectItemsEvents_ItemRenamed(ByVal ProjectItem As_

EnvDTE.ProjectItem, ByVal OldName As String) Handles_ vbProjectItemsEvents.ItemRenamed

     

ProjectItem.Name = OldName

End Sub

When you execute the command above, Visual Studio will throw a new ItemRenamed event, which will be caught by your event handler. As you can see, this will cause your event handler to recurse and eventually crash Visual Studio. One way to get around this problem in Visual Studio 2003 is the following:

Private InRename As Boolean

Public Sub vbProjectItemsEvents_ItemRenamed(ByVal ProjectItem As_ EnvDTE.ProjectItem, ByVal OldName As String) Handles_ vbProjectItemsEvents.ItemRenamed

  If InRename Then

          Return

      Else

          InRename = True

          ProjectItem.Name = OldName

          InRename = False

      End If

End Sub

You can perform similar actions to the above to catch other VS languages. A good reference is Inside Visual Studio .NET 2003, Pgs 241-243. You can also check out this article on MSDN.

In VSIP land, things are a little different. Instead of working with event handlers, you can use the SVsTrackProjectDocuments service to inform the shell that you are listening for certain document events. You have to create a class that implements the IVsTrackProjectDocumentsEvents2 interface, and pass an instance of it into the IVsTrackProjectDocuments2. AdviseTrackProjectDocumentsEvents() method you get from the service. In your class that implements IVsTrackProjectDocumentsEvents2, you can write an implementation for OnQueryRenameFiles(). Unlike the DTE method above, the VSIP way will allow you to actually examine every rename and potentially cancel the operation. This could come in handy for something like implementing your own custom source control system where you might want to prevent certain items from being renamed. Make sure when you're done monitoring the rename events that you call UnadviseTrackProjectDocumentsEvents().

Thanks

Dr. eX