主に一部のテンプレートですでにウィザードが必要だったため、プロジェクト テンプレートでウィザードを使用するソリューションを選択しました。
他のすべてのウィザードが拡張することになっている、または基本的な機能のために単独で使用できる基本クラスを作成しました。
public class AddTargetsWizard : IWizard
{
private const string RELATIVE_PATH_TO_TARGETS = @"..\..\..\..\PATH\TO\Custom.Tasks.Targets";
private const string TASK_NOT_FOUND_MESSAGE = @"A project of this type should be created under a specific path in order for the custom build task to be properly executed.
The build task could not be found at the following location:
{0}
Including the build task would result in unexpected behavior in Visual Studio.
The project was created, but the build task WILL NOT BE INCLUDED.
This project's builds WILL NOT benefit from the custom build task.";
private string _newProjectFileName;
private bool _addTaskToProject;
private Window _mainWindow;
public AddTargetsWizard()
{
this._addTaskToProject = true;
}
protected Window MainWindow
{
get
{
return this._mainWindow;
}
}
public virtual void BeforeOpeningFile(EnvDTE.ProjectItem projectItem)
{
}
public virtual void ProjectFinishedGenerating(EnvDTE.Project project)
{
this._newProjectFileName = project.FullName;
var projectDirectory = Path.GetDirectoryName(this._newProjectFileName);
var taskPath = Path.GetFullPath(Path.Combine(projectDirectory, RELATIVE_PATH_TO_TARGETS));
if (!File.Exists(taskPath))
{
MessageBox.Show(
this.MainWindow,
string.Format(TASK_NOT_FOUND_MESSAGE, taskPath),
"Project Creation Error",
MessageBoxButton.OK,
MessageBoxImage.Error,
MessageBoxResult.OK,
MessageBoxOptions.None);
this._addTaskToProject = false;
}
}
public virtual void ProjectItemFinishedGenerating(EnvDTE.ProjectItem projectItem)
{
}
public virtual void RunFinished()
{
if (this._addTaskToProject)
{
var project = new Microsoft.Build.Evaluation.Project(this._newProjectFileName);
project.Xml.AddImport(RELATIVE_PATH_TO_TARGETS);
project.Save();
}
}
public void RunStarted(object automationObject, Dictionary<string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams)
{
var dte = (EnvDTE80.DTE2)automationObject;
var mainWindow = dte.MainWindow;
foreach (var proc in System.Diagnostics.Process.GetProcesses())
{
if (proc.MainWindowTitle.Equals(mainWindow.Caption))
{
var source = HwndSource.FromHwnd(proc.MainWindowHandle);
this._mainWindow = source.RootVisual as System.Windows.Window;
break;
}
}
this.OnRunStarted(automationObject, replacementsDictionary, runKind, customParams);
}
protected virtual void OnRunStarted(object automationObject, Dictionary<string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams)
{
}
public virtual bool ShouldAddProjectItem(string filePath)
{
return true;
}
}
このウォークスルーは、ウィザードをプロジェクト (または項目) テンプレートに関連付ける方法について非常によく説明しています。
OnRunStarted
ウィザード ウィンドウの表示、置換ディクショナリの入力など、追加機能を提供する必要がある子ウィザードに仮想メソッドを提供していることに気付くでしょう。
このアプローチおよび/または実装について私が気に入らない点:
- 単純なプロジェクト テンプレートよりもはるかに複雑です。
- ウィザード ウィンドウ (すべて WPF) を Visual Studio を所有者とする実際のモーダル ウィンドウにするために、現在のインスタンスのタイトルを使用して HWND と関連付けられて
Window
いる .
- プロジェクトが予想されるフォルダー階層に作成されている場合はすべて問題ありませんが、それ以外の場合、Visual Studio は奇妙な動作をします (つまり、役に立たないダイアログがポップアップします)。
Import
そのため、現在のプロジェクトの場所が相対パスで機能しない場合はエラー メッセージを表示し、挿入を避けることにしました。
誰かが他のアイデアを持っている場合、私はまだすべて耳を傾けています.