VisualStudio VSPackage 自定义命令

VisualStudio VSPackage Custom Command

我正在为 Visual Studio 2015 年写一个小扩展。 我添加了一个 VSPackage 以将一些 CustomCommands 嵌入到快捷菜单中,当您右键单击解决方案资源管理器中的项目或文件夹时,您会看到这些快捷菜单。

我现在想做的是"open the Add New Item dialog and select the one of the templates I've installed with this VSPackage"。

这是我用来初始化命令的代码:

private TemplateCommand(Package package)
{
    if (package == null)
        throw new ArgumentNullException(nameof(package));

    _package = package;

    var commandService = ServiceProvider.GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
    if (commandService == null)
        return;

    AddCommand(commandService, CommandId, CreateCustomTemplate);
}

CreateCustomTemplate 回调代码是这样的:(目前我只是创建一个消息框,只是为了确保它能正常工作)

private void CreateCustomTemplate(object sender, EventArgs eventArgs)
{
    //TODO: code to replace!
    var message = string.Format(CultureInfo.CurrentCulture, "Inside {0}.CreateCustomTemplate()", GetType().FullName);

    // Show a message box to prove we were here
    VsShellUtilities.ShowMessageBox(
        ServiceProvider,
        message,
        "CREATE CustomTemplate",
        OLEMSGICON.OLEMSGICON_INFO,
        OLEMSGBUTTON.OLEMSGBUTTON_OK,
        OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST);
}

那么,回顾一下,如何打开“添加新项目”对话框和select特定项目模板

例如,当您尝试创建 Class 或 UserControl 时右键单击解决方案资源管理器中的文件夹

你得到了类似这样的东西:

这正是我想要实现的目标。显然我想创建自己的模板而不是 UserControl。

如果您需要任何说明,请随时询问。 预先感谢您的任何建议

您可以执行命令"Project.AddNewItem" 或"File.AddNewItem" 来显示对话框。有几种方法可以通过编程方式执行命令,最简单的方法是获取 EnvDTE.DTE 实例并调用 dte.ExecuteCommand(commandName).

至于选择所需的模板,请参见parameters for the command File.AddNewItem。幸运的是 Project.AddNewItem 命令也是一样的。

最后我解决了我的问题。

不幸的是,命令 File.AddNewItem(或 Project.AddNewItem)不适合我的情况,因为我想查看 AddNewFile 对话框(这些命令只是将项目添加到指定的项目)。

我在网上找到了解决方案,完全here, specifically thanks to the answer of Vladimir.Ilic

这是我用来实现目标的代码:

internal sealed class TemplateCommand
{
    private const int CustomCommandId = 0x1023;

    private static readonly Guid CommandSet = COMMANDSET_GUID;
    private readonly Package _package;


    // ReSharper disable MemberCanBePrivate.Global
    // ReSharper disable UnusedAutoPropertyAccessor.Global
    public IServiceProvider ServiceProvider => _package;

    public static TemplateCommand Instance { get; set; }
    // ReSharper restore UnusedAutoPropertyAccessor.Global
    // ReSharper restore MemberCanBePrivate.Global

    public static void Initialize(Package package)
    {
        Instance = new TemplateCommand(package);
    }

    private TemplateCommand(Package package)
    {
        if (package == null)
            throw new ArgumentNullException(nameof(package));

        _package = package;

        var commandService = ServiceProvider.GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
        if (commandService == null)
            return;

        AddCommand(commandService, CustomCommandId, CreateCustomCommand);
    }

    private static void AddCommand(IMenuCommandService commandService, int commandId, EventHandler callback)
    {
        var command = new CommandID(CommandSet, commandId);
        var menuItem = new MenuCommand(callback, command);
        commandService.AddCommand(menuItem);
    }

    private void CreateCustomCommand(object sender, EventArgs eventArgs)
    {
        AddNewItem("MyCustomCommand");
    }

    private void AddNewItem(string itemName)
    {
        var dte = ServiceProvider.GetService(typeof(DTE)) as DTE;
        if (dte == null)
            return;

        int iDontShowAgain;
        uint projectItemId;
        var strFilter = string.Empty;

        var hierarchy = GetCurrentVsHierarchySelection(out projectItemId);
        if (hierarchy == null)
            return;

        var project = ToDteProject(hierarchy);
        if (project == null)
            return;

        var vsProject = ToVsProject(project);
        if (vsProject == null)
            return;

        var addItemDialog = ServiceProvider.GetService(typeof(IVsAddProjectItemDlg)) as IVsAddProjectItemDlg;
        if (addItemDialog == null)
            return;

        const uint uiFlags = (uint)(__VSADDITEMFLAGS.VSADDITEM_AddNewItems | __VSADDITEMFLAGS.VSADDITEM_SuggestTemplateName | __VSADDITEMFLAGS.VSADDITEM_AllowHiddenTreeView);
        const string categoryNameInNewFileDialog = "MyCustomTemplates";

        // ProjectGuid for C# projects
        var projGuid = new Guid("FAE04EC0-301F-11D3-BF4B-00C04F79EFBC");

        string projectDirectoryPath;
        hierarchy.GetCanonicalName(projectItemId, out projectDirectoryPath);
        var itemNameInNewFileDialog = itemName;
        addItemDialog.AddProjectItemDlg(projectItemId,
                                        ref projGuid,
                                        vsProject,
                                        uiFlags,
                                        categoryNameInNewFileDialog,
                                        itemNameInNewFileDialog,
                                        ref projectDirectoryPath,
                                        ref strFilter,
                                        out iDontShowAgain);
    }

    private static IVsHierarchy GetCurrentVsHierarchySelection(out uint projectItemId)
    {
        IntPtr hierarchyPtr, selectionContainerPtr;
        IVsMultiItemSelect mis;
        var monitorSelection = (IVsMonitorSelection)Package.GetGlobalService(typeof(SVsShellMonitorSelection));
        monitorSelection.GetCurrentSelection(out hierarchyPtr, out projectItemId, out mis, out selectionContainerPtr);

        var hierarchy = Marshal.GetTypedObjectForIUnknown(hierarchyPtr, typeof(IVsHierarchy)) as IVsHierarchy;
        return hierarchy;
    }

    private static Project ToDteProject(IVsHierarchy hierarchy)
    {
        if (hierarchy == null)
            throw new ArgumentNullException(nameof(hierarchy));

        object prjObject;
        if (hierarchy.GetProperty(0xfffffffe, (int)__VSHPROPID.VSHPROPID_ExtObject, out prjObject) == VSConstants.S_OK)
            return (Project)prjObject;

        throw new ArgumentException("Hierarchy is not a project.");
    }

    private IVsProject ToVsProject(Project project)
    {
        if (project == null)
            throw new ArgumentNullException(nameof(project));

        var vsSln = ServiceProvider.GetService(typeof(IVsSolution)) as IVsSolution;
        if (vsSln == null)
            throw new ArgumentException("Project is not a VS project.");

        IVsHierarchy vsHierarchy;
        vsSln.GetProjectOfUniqueName(project.UniqueName, out vsHierarchy);
        // ReSharper disable SuspiciousTypeConversion.Global
        var vsProject = vsHierarchy as IVsProject;
        // ReSharper restore SuspiciousTypeConversion.Global
        if (vsProject != null)
            return vsProject;

        throw new ArgumentException("Project is not a VS project.");
    }
}

非常感谢那些路过并尝试(甚至想)提供帮助的人!

希望这对某人有所帮助,

此致