Пользовательская команда VisualStudio VSPackage
Я пишу небольшое расширение для 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">
Вы получаете что-то похожее на это:
И это именно то, чего я пытаюсь достичь. Очевидно, я хотел бы создать свой собственный шаблон, а не UserControl.
Если вам нужны какие-либо разъяснения, не стесняйтесь спрашивать. Заранее спасибо за любое предложение
2 ответа
В конце концов я решил свою проблему.
К сожалению, команда 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.");
}
}
Большое спасибо тем, кто прошел мимо и которые пытались (или даже думали) помочь!
Надеюсь, это кому-то поможет,
Искренне
Вы можете выполнить команды "Project.AddNewItem" или "File.AddNewItem", чтобы показать диалоговое окно. Есть несколько способов выполнить команду программно, самый простой - получить экземпляр EnvDTE.DTE и вызвать dte.ExecuteCommand(commandName).
Что касается выбора нужного шаблона, см. Параметры для команды File.AddNewItem. Если повезет, то для команды Project.AddNewItem то же самое.