2

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

我现在想做的是“打开添加新项目对话框并选择我使用此 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);
}

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

例如,当您尝试在解决方案资源管理器中右键单击文件夹创建 Class 或 UserControl 右键单击文件夹,然后添加 -> 用户控件

你会得到类似这样的东西: 结果

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

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

4

2 回答 2

3

最后我解决了我的问题。

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

我找到了挖掘网络的解决方案,就在这里,特别感谢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.");
    }
}

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

希望这可以帮助某人,

真挚地

于 2017-01-09T12:04:56.833 回答
1

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

至于选择所需的模板,请参见命令 File.AddNewItem 的参数。幸运的是,Project.AddNewItem 命令是相同的。

于 2017-01-03T19:42:14.013 回答