Search code examples
wpfvisual-studio-2017visual-studio-extensions

How to handle Solutions, Projects and their contents in a VisualStudio extension


In short: I'm new to VisualStudio Extensibility and my goal is to create an extension with a ToolWindow (which already works) showing different views for each context of a VisualStudio solution, i. e. a view for the solution, a view for a project etc.. The window should be opened by clicking on a context menu entry in the context menus of the Solution Explorer, Class View, Object Browser and (ideally) any other window showing contents like projects, namespaces, classes etc..

After searching I found a lot of information, but for some points I couldn't find very helpful information. How do I ...

  • ... create a context menu item for the VisualStudio views?
  • ... get the currently open solution as an instance in code?
  • ... get the projects of the solution and their contens as instances in code?
  • ... add/remove items to/from a solution/project/class/... in code?
  • ... react to selection changes in the Solution Explorer?

What I've done, so far: I read the docs for Starting to Develop Visual Studio Extensions and downloaded the VSSDK-Extensibility-Samples. Especially the WPF_Toolwindow example was interesting for my purposes, so I built and ran it, which was successful, so far. Another interesting sample would have been the WPFDesigner_XML, but it always throws a NullReferenceException, so I decided to stick with the former ToolWindow, which is completely fine, for now.

Furtermore, I tried to understand the example by having a close look at each file in the project, running it in the debugger and analyzing what happened. I'm confident I understood it, but am also open for corrections of my possibly misguided thoughts following.

Now, I have created a new project, based on the WPF_Toolwindow sample, renamed and adapted to my needs (basically, I created new GUIDs, renamed the namespaces and removed things I won't use). This extension still works in the debugger. I even uninstalled everything from the experimental instance and debugged the extension from scratch.

What I try to achieve:

  • Have the ToolWindow load a specific view/viewmodel, when the selection changes in the Solution Explorer (or any other VisualStudio view). Alternatively, there should be a context menu item for every node's context menu in the Solution Explorer tree (or any other VisualStudio view).
  • Get the currently open solution, the containing projects and basically everything from the Solution Explorer's content as instances processable in my viewmodel. I need to properly add/remove
    • classes/structs/enums to/from
      1. a folder in a project
      2. a namespace
    • properties/fields to/from a class/struct
  • Generate code based on information of the solution and add the file properly to a project.

Does anyone know of examples for something like this or can anyone give me some hints, where I can find further information? Any help would be appreciated. Thanks in advance.


Solution

  • (1) The items already have a context menu and I want to add a new command to this menu.

    if you want to add a sub menu to the context menu, the following link provide a complete sample enter image description here

    https://github.com/visualstudioextensibility/VSX-Samples/tree/master/CommandSubmenu

    (3) Yes, basically adding a file to a project without manually manipulating the project file would be nice.

    You can add the file to project via Project.ProjectItems.AddFromFile, and the following provide a sample for your reference.

    https://www.mztools.com/Articles/2014/MZ2014009.aspx

    Update:

    I select a project and a similar event is fired. Are there such events I can subscribe to?

    You could use IVsMonitorSelection to implement. here is the code which retrieve related project path for your reference.

    IntPtr hierarchyPointer, selectionContainerPointer;
                Object selectedObject = null;
                IVsMultiItemSelect multiItemSelect;
                uint projectItemId;
    
                IVsMonitorSelection monitorSelection =
                        (IVsMonitorSelection)Package.GetGlobalService(
                        typeof(SVsShellMonitorSelection));
    
                monitorSelection.GetCurrentSelection(out hierarchyPointer,
                                                     out projectItemId,
                                                     out multiItemSelect,
                                                     out selectionContainerPointer);
    
                IVsHierarchy selectedHierarchy = Marshal.GetTypedObjectForIUnknown(
                                                     hierarchyPointer,
                                                     typeof(IVsHierarchy)) as IVsHierarchy;
    
                if (selectedHierarchy != null)
                {
                    ErrorHandler.ThrowOnFailure(selectedHierarchy.GetProperty(
                                                      projectItemId,
                                                      (int)__VSHPROPID.VSHPROPID_ExtObject,
                                                      out selectedObject));
                }
    
                Project selectedProject = selectedObject as Project;
    
                string projectPath = selectedProject.FullName;
    

    For more information about the usage, please refer to:

    https://www.mztools.com/articles/2007/mz2007024.aspx