Extending Visual Studio properties

We’ve been doing a bit of work with Visual Studio Extensibility recently through the LightSpeed designer and the VS File Explorer add-in, so I thought I’d start jotting down some of the stuff we’ve come across. We’ll start with a nice obscure one…

One of the features we’ve always had in mind for the LightSpeed designer is the ability to use your own custom templates. An example of why you might want to do this is if you want to have the property setters always call logging code. But how would you tell LightSpeed which custom template to use? Well, of course, it could be a model-level thing, but then if you’ve got multiple models in a project, you have to specify it on each one individually. More likely, you’ll want to choose the custom template at project or solution level because the reasons for needing custom code are likely to be at the project or solution level, e.g. design policy or coding standards. To support this, we would need to add a property to the Visual Studio project object, to be displayed in the Properties window when the user selected the project. But that object is defined by Visual Studio, not by us!

If you’re familiar with Windows Forms, you probably know that some controls (such as ToolTip and HelpProvider) have exactly the same problem — they want to add a pseudo-property to other controls on the form. Windows Forms solves this using an interface called IExtenderProvider. Visual Studio provides an analogous interface, also called IExtenderProvider though with slightly different methods.

So to add properties to a Visual Studio object, you implement IExtenderProvider and register your implementation using DTE.ObjectExtenders.RegisterExtenderProvider. For add-ins, do this in your connection method. For DSL Tools packages, you can do it in your package’s Initialize override. As part of registration, you have to say what kind of object you’re interested in extending (expressed as a CATID string for your old-skool COM nostalgia-inducing pleasure), so you may need to register multiple times (for example to extend both C# and Visual Basic projects). You may need to do a bit of poking around to find out what CATID to register with for any given selection, though the EnvDTE.Constants class and the VSLangProj namespace are good places to start.

When the user makes a selection, Visual Studio asks all suitably registered extender providers whether they are interested in this selection by calling IExtenderProvider.CanExtend. At this point you have access to the extendee object so you can make a more specific decision if required. For example we’d only want to display our custom property against projects that contain LightSpeed models.

If you return true from CanExtend, Visual Studio calls your GetExtender implementation. All you need to do from here is return an object with the properties you want added to the property grid. (Well, you need to do some bookkeeping as well, but this is described in the VS SDK documentation.) One thing we found is that the returned object needs to be COM-visible; otherwise, it’s just a plain old CLR object. Your returned object can use WinForms design-time attributes like CategoryAttribute, DisplayNameAttribute, DescriptionAttribute and EditorAttribute to customise the display.

Be aware that all this does is display the extension properties in the Properties window. Sometimes this is all you need: for example, the AnkhSVN add-in for Subversion displays read-only source control information using this technique. But in our case we would also need to save whatever the user enters into the “template file” extension property. How you do this depends on what you’re extending, but if you’re extending a project or solution, one simple solution is to have Visual Studio save the values as part of the project or solution file by using the Globals property of the Project or Solution interface, and setting VariablePersists to true.

As so often with Visual Studio, much of the battle is knowing what to do. You can see from the above that there’s not a lot of code to write to extend a Visual Studio object, but the documentation is ropey and the samples are often out of date. Hopefully this will provide a few pointers for the two other people on the planet who need to extend the VS properties window…

Tagged as Visual Studio

4 Responses to “Extending Visual Studio properties”

  • Can you point me in the direction or send some examples of registering a automation extender in a package?
    That would be great!

  • Hello Jaime,

    To register an extender, call:

    dte.ObjectExtenders.RegisterExtenderProvider

    where dte is the running instance of Visual Studio, which you can get from Package.GetGlobalService(typeof(DTE)). The CATID would normally be one of the PrjBrowseObjectCATID values. You should be able to call this from your package’s Initialise override.

  • Thanks, I figured that out. I also figured out how to persist the properties with the IVsBuildPropertyStorage. I use that to embed a guid that acts as a key for project global properties in my ProjectItem within the .proj file using the SetItemAttribute and GetItemAttribute methods. The problem I am having now is that I can’t persist the information when a cross project paste or drag and drop operation takes place. Unfortunately, this isn’t trivial. It becomes problematic because the items are deleted and added. You can track solution changes but there is a bug in the dte object events and the IVsTrackProjectDocumentsEvents2 doesn’t really offer all that must as a strategy.

  • Ah, sorry. That’s not something I’ve had to do, so I don’t have any bright ideas. Sorry I can’t help, and good luck!

  • Leave a Reply

Archives

Join our mailer

You should join our newsletter! Sent monthly:

Back to Top