VisualStudio VSPackage自定义命令

时间:2016-12-22 15:59:19

标签: c# visual-studio visual-studio-2015 vspackage vsct

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

我现在要做的是“打开添加新项对话框,然后选择我使用此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回调代码是这样的:(目前我只是创建一个messageBox,只是为了确保它有效)

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);
}

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

例如,当您尝试创建一个Class或UserControl时右键单击解决方案资源管理器中的文件夹 RightClick on Folder, then Add -> UserControl

您获得类似于此的内容: Result

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

如果您需要任何澄清,请随时提出。 提前感谢您的任何建议

2 个答案:

答案 0 :(得分:0)

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

关于选择所需模板,请参阅parameters for the command File.AddNewItem。幸运的是,Project.AddNewItem命令是相同的。

答案 1 :(得分:0)

最后我解决了我的问题。

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

我找到了解决网络问题的解决方案here,特别感谢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.");
    }
}

非常感谢那些经过尝试(或者甚至想过)帮助的人!

希望这有助于某人,

此致