如何在 Visual Studio 2019 中异步加载 ModelingPackage(DSL-Tools)?
How to load a ModelingPackage (DSL-Tools) asynchronously in Visual Studio 2019?
我有一个使用 [ProvideAutoLoad]
的 DSL 工具项目,因为它向 Visual Studio 添加了一组菜单命令以允许用户转换代码(我们有很多文本模板),和其他一些东西。
由于 VS2019 not allow to autoload sync packages anymore,即使启用了允许自动加载的选项,我也会收到烦人的警告。
显然,Microsoft 没有计划提供 ModelingPackage
的异步版本(事实上,我开始怀疑他们是否会完全停止使用 DSL 工具)。
有人找到解决这个问题的方法吗?
我尝试使用另一个包 - 构建为 AsyncPackage
- 这样就可以在 InitializeAsync()
上加载我的 DSL-tools 包,但我最终使用 IVsShell
服务。
protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress<VSShell.ServiceProgressData> progress)
{
// Default behavior
await base.InitializeAsync(cancellationToken, progress).ConfigureAwait(false);
// Load the service designer package
this.EnsureDesignerPackage();
// Switche to the UI thread
await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
// Menu commands
this.InitializeMenuCommands();
}
private void EnsureDesignerPackage()
{
// Package already loaded?
if (!this.IsDesignerPackageLoaded())
{
this.LoadDesignerPackage();
}
}
private bool IsDesignerPackageLoaded()
{
// Package identifier
Guid packageId = new Guid(GlobalConstants.ServiceDesignerPackageId);
// Is loaded?
IVsShell service = this.VsShellService;
int hr = this.VsShellService.IsPackageLoaded(ref packageId, out IVsPackage package);
if (ErrorHandler.Succeeded(hr) && package != null)
{
return true;
}
// Default result
return false;
}
private void LoadDesignerPackage()
{
// Package identifier
Guid packageId = new Guid(GlobalConstants.ServiceDesignerPackageId);
// Not loaded?
int hr = this.VsShellService.IsPackageLoaded(ref packageId, out IVsPackage package);
if (hr != VSConstants.S_OK || package == null)
{
// Load
hr = this.VsShellService.LoadPackage(ref packageId, out package);
if (ErrorHandler.Failed(hr))
{
string message = "Service designer loading failed: {0}.".Format().With(hr);
this.ShowException(message);
}
}
}
今天早些时候,我刚好让一位客户经历了同样的场景。不幸的是,上次我问到目前没有更新底层 DSL 框架以利用 AsyncPackage 或类似框架的计划。我看到你已经在 中记录了一个建议,并且刚刚投票并添加了我自己的 $.02。我会鼓励任何点击此链接的人对上面链接的建议进行投票。
要为您的 DSL 包对象添加对异步加载的支持,您需要添加对 Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime.dll 程序集的引用,然后编辑您的 Package.tt 文件,添加 AllowsBackgroundLoading 设置为 true 的 VSShell.PackageRegistration 属性,并在同一个 class 上实现 IAsyncLoadablePackageInitialize 接口。例如:
namespace <#= CodeGenerationUtilities.GetPackageNamespace(this.Dsl) #>
{
/// <summary>
/// Double-derived class to allow easier code customization.
/// </summary>
[VSShell::ProvideMenuResource("1000.ctmenu", 1)]
[VSShell::ProvideToolboxItems(1)]
[VSShell::PackageRegistration(AllowsBackgroundLoading = true)]
[global::Microsoft.VisualStudio.TextTemplating.VSHost.ProvideDirectiveProcessor(typeof(global::<#= this.Dsl.Namespace #>.<#= directiveName #>DirectiveProcessor), global::<#= this.Dsl.Namespace #>.<#= directiveName #>DirectiveProcessor.<#= directiveName #>DirectiveProcessorName, "A directive processor that provides access to <#= directiveName #> files")]
[global::System.Runtime.InteropServices.Guid(Constants.<#= dslName #>PackageId)]
internal sealed partial class <#= dslName #>Package : <#= dslName #>PackageBase, VSShellInterop.IAsyncLoadablePackageInitialize
{
public VSShellInterop.IVsTask Initialize(VSShellInterop.IAsyncServiceProvider pServiceProvider, VSShellInterop.IProfferAsyncService pProfferService, VSShellInterop.IAsyncProgressCallback pProgressCallback)
{
// do async initialization here
return null;
}
}
}
此致,
我有一个使用 [ProvideAutoLoad]
的 DSL 工具项目,因为它向 Visual Studio 添加了一组菜单命令以允许用户转换代码(我们有很多文本模板),和其他一些东西。
由于 VS2019 not allow to autoload sync packages anymore,即使启用了允许自动加载的选项,我也会收到烦人的警告。
显然,Microsoft 没有计划提供 ModelingPackage
的异步版本(事实上,我开始怀疑他们是否会完全停止使用 DSL 工具)。
有人找到解决这个问题的方法吗?
我尝试使用另一个包 - 构建为 AsyncPackage
- 这样就可以在 InitializeAsync()
上加载我的 DSL-tools 包,但我最终使用 IVsShell
服务。
protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress<VSShell.ServiceProgressData> progress)
{
// Default behavior
await base.InitializeAsync(cancellationToken, progress).ConfigureAwait(false);
// Load the service designer package
this.EnsureDesignerPackage();
// Switche to the UI thread
await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
// Menu commands
this.InitializeMenuCommands();
}
private void EnsureDesignerPackage()
{
// Package already loaded?
if (!this.IsDesignerPackageLoaded())
{
this.LoadDesignerPackage();
}
}
private bool IsDesignerPackageLoaded()
{
// Package identifier
Guid packageId = new Guid(GlobalConstants.ServiceDesignerPackageId);
// Is loaded?
IVsShell service = this.VsShellService;
int hr = this.VsShellService.IsPackageLoaded(ref packageId, out IVsPackage package);
if (ErrorHandler.Succeeded(hr) && package != null)
{
return true;
}
// Default result
return false;
}
private void LoadDesignerPackage()
{
// Package identifier
Guid packageId = new Guid(GlobalConstants.ServiceDesignerPackageId);
// Not loaded?
int hr = this.VsShellService.IsPackageLoaded(ref packageId, out IVsPackage package);
if (hr != VSConstants.S_OK || package == null)
{
// Load
hr = this.VsShellService.LoadPackage(ref packageId, out package);
if (ErrorHandler.Failed(hr))
{
string message = "Service designer loading failed: {0}.".Format().With(hr);
this.ShowException(message);
}
}
}
今天早些时候,我刚好让一位客户经历了同样的场景。不幸的是,上次我问到目前没有更新底层 DSL 框架以利用 AsyncPackage 或类似框架的计划。我看到你已经在
要为您的 DSL 包对象添加对异步加载的支持,您需要添加对 Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime.dll 程序集的引用,然后编辑您的 Package.tt 文件,添加 AllowsBackgroundLoading 设置为 true 的 VSShell.PackageRegistration 属性,并在同一个 class 上实现 IAsyncLoadablePackageInitialize 接口。例如:
namespace <#= CodeGenerationUtilities.GetPackageNamespace(this.Dsl) #>
{
/// <summary>
/// Double-derived class to allow easier code customization.
/// </summary>
[VSShell::ProvideMenuResource("1000.ctmenu", 1)]
[VSShell::ProvideToolboxItems(1)]
[VSShell::PackageRegistration(AllowsBackgroundLoading = true)]
[global::Microsoft.VisualStudio.TextTemplating.VSHost.ProvideDirectiveProcessor(typeof(global::<#= this.Dsl.Namespace #>.<#= directiveName #>DirectiveProcessor), global::<#= this.Dsl.Namespace #>.<#= directiveName #>DirectiveProcessor.<#= directiveName #>DirectiveProcessorName, "A directive processor that provides access to <#= directiveName #> files")]
[global::System.Runtime.InteropServices.Guid(Constants.<#= dslName #>PackageId)]
internal sealed partial class <#= dslName #>Package : <#= dslName #>PackageBase, VSShellInterop.IAsyncLoadablePackageInitialize
{
public VSShellInterop.IVsTask Initialize(VSShellInterop.IAsyncServiceProvider pServiceProvider, VSShellInterop.IProfferAsyncService pProfferService, VSShellInterop.IAsyncProgressCallback pProgressCallback)
{
// do async initialization here
return null;
}
}
}
此致,