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
Comments
- Anonymous
April 15, 2004
Could you add a ItemMoved event to the next version of Visual Studio to catch when the user moves a file of folder inside the Solution Explorer? Currently it seems that we must use VSIP to do that, but it would be handy to provide that event in the extensibility model for addins... - Anonymous
April 16, 2004
Wow. My question ;-) - Anonymous
May 07, 2004
Some users of my add-in report that the code that retrieves late-bound CSharpProjectItemsEvents throws InvalidCastException:
[code]
EnvDTE.ProjectItemsEvents myProjectItemsEvents;
myProjectItemsEvents = (ProjectItemsEvents)
applicationObject.Events.GetObject ("CSharpProjectItemsEvents"); // throws InvalidCastException
[/code]
Any ideas how this could happen?