【问题标题】:In C#, what and how to pass IServiceProvider in ErrorListProvider(IServiceProvider isp)?在 C# 中,什么以及如何在 ErrorListProvider(IServiceProvider isp) 中传递 IServiceProvider?
【发布时间】:2020-04-21 21:58:42
【问题描述】:

我正在创建一个 vsix 项目,我需要在错误列表窗口中添加一些自定义错误。现在我被困在IServiceProvider。它包含什么以及我为什么需要它以及如何获得它?在我的代码中,我需要使用服务提供商进行初始化。我怎样才能做到这一点?以下是代码:

internal class ErrorListManager
{
    public static ErrorListProvider errorListProvider;

    public static void Initialize(IServiceProvider serviceProvider) 
    {
        errorListProvider = new ErrorListProvider(serviceProvider);

    }

    public static void AddError(string errorMsg) {
        AddTask(errorMsg, TaskErrorCategory.Error);
    }

    private static void AddTask(string errorMsg, TaskErrorCategory category)
    {
        errorListProvider.Tasks.Add(new ErrorTask
        {
            Category = TaskCategory.User,
            ErrorCategory = category,
            Text = errorMsg
        });
    }
}

请帮忙。我是 C# 和 VSIX 的初学者。谢谢!

【问题讨论】:

    标签: c# asynchronous vsix service-provider error-list


    【解决方案1】:

    要在 VS 错误列表 中写入内容,您需要使用 ErrorListProvider。在我的实现中,我从 ErrorListProvider 继承并为“ErrorWindowController”实现我自己的行为。代码如下所示(阅读代码 cmets 了解更多信息):

    public class ErrorWindowController : ErrorListProvider
    {
    
    #region Constructor
    
    /// <summary>
    /// Instance Constructor
    /// </summary>
    /// <param name="aServiceProvider"></param>
    public ErrorWindowController(IServiceProvider aIServiceProvider) : base(aIServiceProvider)
    {
    }
    
    #endregion
    
    
    #region Public Methods
    
    // Use this to add a collection of custom errors in VS Error List
    public void AddErrors(IEnumerable<ErrorModel> aErrors)
    {
        SuspendRefresh();
    
        foreach (ErrorModel error in aErrors)
        {
          ErrorTask errorTask = new ErrorTask
          {
            ErrorCategory = error.Category,
            Document = error.FilePath,
            Text = error.Description,
            Line = error.Line - 1,
            Column = error.Column,
            Category = TaskCategory.BuildCompile,
            Priority = TaskPriority.High,
            HierarchyItem = error.HierarchyItem
          };
          errorTask.Navigate += ErrorTaskNavigate;
          Tasks.Add(errorTask);
        }
    
        BringToFront();
        ResumeRefresh();
    }
    
    // Remove all the errors from Error List which are depending of a project and this specific project is closed
    // Or remove all the errors from Error List when the VS solution is closed
    public void RemoveErrors(IVsHierarchy aHierarchy)
    {
        SuspendRefresh();
    
        for (int i = Tasks.Count - 1; i >= 0; --i)
        {
          var errorTask = Tasks[i] as ErrorTask;
          aHierarchy.GetCanonicalName(Microsoft.VisualStudio.VSConstants.VSITEMID_ROOT, out string nameInHierarchy);
          errorTask.HierarchyItem.GetCanonicalName(Microsoft.VisualStudio.VSConstants.VSITEMID_ROOT, out string nameErrorTaskHierarchy);
          if (nameInHierarchy == nameErrorTaskHierarchy)
          {
            errorTask.Navigate -= ErrorTaskNavigate;
            Tasks.Remove(errorTask);
          }
        }
    
        ResumeRefresh();
    }
    
    // Remove all the errors from the Error List
    public void Clear()
    {
        Tasks.Clear();
    }
    
    
    #endregion
    
    
    #region Private Methods
    
    // This is optional
    // Add navigation for your errors. 
    private void ErrorTaskNavigate(object sender, EventArgs e)
    {
      ErrorTask objErrorTask = (ErrorTask)sender;
      objErrorTask.Line += 1;
      bool bResult = Navigate(objErrorTask, new Guid(EnvDTE.Constants.vsViewKindCode));
      objErrorTask.Line -= 1;
    }
    
    
    #endregion
    }
    

    ErrorModel非常简单:

    public class ErrorModel
    {
      #region Properties
    
      public string FilePath { get; set; }
    
      public int Line { get; set; }
    
      public int Column { get; set; }
    
      public TaskErrorCategory Category { get; set; }
    
      public string Description { get; set; }
    
      public IVsHierarchy HierarchyItem { get; set; }
    
      #endregion
    
    }
    

    编码愉快!

    【讨论】:

    • 我可以知道你在调用构造函数时传递了什么以及如何传递IServiceProvider aIServiceProvider 吗?我使用菜单命令模板创建了我的 VSIX 项目。在这里,我添加了许多其他项目,例如Windows 窗体,TextAdornment。所以现在,每当我点击我的菜单按钮时,只有我得到所有必要的东西的服务提供商。但是当我尝试从其他任何地方初始化时,我没有得到服务提供者。
    • 抱歉回复晚了。我发现管理 VS 服务的最佳方法是在包异步加载时缓存我需要的所有服务。这样,服务就在你需要的时候随时可用,而且只是一次性操作。在上面的示例中,我将IServiceProvider 接口作为参数发送,因为我只需要基础对象的接口ErrorListProvider。
    • 仅当我单击菜单命令时才会调用包异步加载。但我希望在创建编辑器 TextView 时加载它。我可以添加新的异步包来初始化我的 ErrorListManager Initialize 方法吗?
    • 我之前忘了提,我使用以下属性在 Visual Studio 启动时强制加载 VSIX 包:[ProvideAutoLoad(VSConstants.UICONTEXT.NoSolution_string, PackageAutoLoadFlags.BackgroundLoad)]。让我知道它是否适合您
    • 我很乐意提供帮助。关于初始化时间,如果您正在做繁重的工作,最好考虑组件或操作的延迟初始化。在打开 Visual Studio 时,实际上不需要的组件可以稍后在打开 Visual Studio 解决方案时或在考虑到您的需要的另一个 VS 事件上进行初始化。祝你好运!
    【解决方案2】:

    您的包裹是服务提供商。它的基类 AsyncPackage 派生自实现 OLE.Interop.IServiceProvider 和 System.IServiceProvider 的 Package 类(是的,VSX 令人困惑,并且有两个 IServiceProvider 接口)。因此,从您的包类中,您将调用 ErrorListManager.Initialize(this)。

    也就是说,您可能希望将 VS 2015 及更高版本的新 API 用于 ErrorList。您使用的旧方法不允许您向“代码”等列添加值。请参阅此处的示例:

    VSSDK-Extensibility-Samples/ErrorList:https://github.com/microsoft/VSSDK-Extensibility-Samples/tree/master/ErrorList

    madskristensen/WebAccessibilityChecker:https://github.com/madskristensen/WebAccessibilityChecker/tree/master/src/ErrorList

    madskristensen/TaskOutputListener:https://github.com/madskristensen/TaskOutputListener/blob/master/src/ErrorListProvider/ErrorListProvider.cs

    【讨论】:

    • 包类究竟是什么?这是我整个项目开始的课程吗?还是别的什么?
    • @TanmayBairagi 整个 VSIX 项目开始的类。它派生自 Package 或 AsyncPackage,并具有 Initialize 或 InitializeAsync 覆盖方法
    • 好吧。我使用菜单命令模板创建了我的 VSIX 项目。在这里,我添加了许多其他项目,例如Windows 窗体,TextAdornment。所以现在,每当我点击我的菜单按钮时,只有我得到我需要的一切,初始化方法正常工作。但是当我尝试从其他任何地方初始化时,我没有得到服务提供商。感谢您理解我的问题先生!有没有什么解决方案我不需要点击菜单按钮来初始化我的 ErrorListManager 类?
    • @TanmayBairagi 好吧,如果您的 ErrorListManager 有 Initialize 方法,那么您的代码中的某些内容必须调用该方法。调用它的人必须将 IServiceProvider 作为参数传递。除了带有 InitializeAsync 方法的包之外,您还有哪些其他入口点(“来自其他任何地方”?)?
    • 实际上(“从其他任何地方”)不是入口点(包类)。除了包类之外,我没有任何InitializeAsync 方法。尽管我尝试从 ("project"->Add->New Item->Extensibility->Async Package) 添加一个 Async Package ,它会自动创建 InitializeAsync 。但问题是,我无论如何都无法加载这个包。希望你能解决问题。
    猜你喜欢
    • 1970-01-01
    • 2015-03-21
    • 1970-01-01
    • 2015-07-11
    • 2015-01-10
    • 1970-01-01
    • 2017-07-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多