共用方式為


工作區

工作區是 Visual Studio 在 Open Folder中代表任何檔案集合的方式,並以 IWorkspace 類型表示。 工作區本身並不瞭解資料夾內檔案的相關內容或功能。 相反地,它會提供一組一般 API,讓功能和延伸模塊產生及取用其他人可以採取行動的數據。 生產者是透過 Managed Extensibility Framework (MEF),使用各種導出屬性所組成。

工作區提供者和服務

工作區提供者和服務提供數據與功能,以回應工作區的內容。 它們可能會提供內容相關檔案資訊、來源檔案中的符號,或建置功能。

這兩個概念都會使用 工廠模式,並由工作區透過 MEF 匯入。 所有匯出屬性都會執行 IProviderMetadataBaseIWorkspaceServiceFactoryMetadata,但擴展應該使用具體類型來處理匯出型別。

提供者和服務之間的其中一個差異是其與工作區的關聯。 工作區可以有許多特定類型的提供者,但每個工作區只會建立一個特定類型的服務。 例如,工作區有許多檔案掃描器提供者,但工作區每個工作區只有一個索引服務。

另一個主要差異是取用來自提供者和服務的數據。 工作區是從提供者取得數據的進入點,原因有幾個。 首先,提供者通常會有一些他們建立的窄組數據。 數據可能是 C# 原始程式檔的符號,或是 CMakeLists.txt 檔案的建置檔案內容。 工作區會將消費者的要求匹配到與其要求一致的元數據的提供者。 其次,某些案例可讓許多提供者參與要求,而其他案例則使用優先順序最高的提供者。

相比之下,擴充功能可以取得工作區服務的實例,並直接與其互動。 IWorkspace 上的擴充方法適用於 Visual Studio 所提供的服務,例如 GetFileWatcherService。 您的延伸模組可能會為延伸模組內的元件或其他延伸模組提供工作區服務。 消費者應該使用 GetServiceAsync 或您在 IWorkspace 類型上提供的擴充函式。

警告

請勿撰寫與 Visual Studio 衝突的服務。 這可能會導致非預期的問題。

工作區關閉後的處置

在關閉工作區時,擴充器可能需要處置並呼叫非同步程式碼。 IAsyncDisposable 介面可讓您輕鬆撰寫此程序代碼。

工作區設定

工作區具有 IWorkspaceSettingsManager 服務,對工作區具有簡單但功能強大的控制。 如需設定的基本概觀,請參閱 自定義建置和偵錯工作

大部分 SettingsType 類型的設定都是 .json 檔案,例如 VSWorkspaceSettings.jsontasks.vs.json

工作區設定的威力集中在「範圍」周圍,這隻是工作區內的路徑。 當取用者呼叫 GetAggregatedSettings時,會匯總包含所要求路徑和設定類型的所有範圍。 範圍匯總優先順序如下所示:

  1. 「本機設定」,通常是工作區根目錄 .vs 目錄。
  2. 所請求的路徑本身。
  3. 所要求路徑的父目錄。
  4. 包含工作區根目錄在內的所有向上的父目錄。
  5. 位於用戶目錄中的 「全域設定」。

這個結果是 IWorkspaceSettings的一個實例。 此物件保存特定類型的設定,並且可以查詢儲存為 string的設定鍵名稱。 GetProperty 方法和 WorkspaceSettingsExtensions 擴充方法預期呼叫端知道所要求的設定值類型。 由於大部分的配置檔會保存為 .json 檔案,因此許多調用都會使用 stringboolint這些類型和它們的陣列。 也支援物件類型。 在這些情況下,您可以使用 IWorkspaceSettings 本身作為類型自變數。 例如:

{
  "intValue": 1,
  "stringValue": "s",
  "boolValue": true,
  "stringArray": [
    "s1",
    "s2"
  ],
  "nestedIWorkspaceSettings": {
    "nestedString": "ns"
  }
}

假設這些設定位於使用者的 VSWorkspaceSettings.json中,數據可以存取為:

using System.Collections.Generic;
using Microsoft.VisualStudio.Workspace;
using Microsoft.VisualStudio.Workspace.Settings;

private static void ReadSettings(IWorkspace workspace)
{
    IWorkspaceSettingsManager settingsManager = workspace.GetSettingsManager();
    IWorkspaceSettings settings = settingsManager.GetAggregatedSettings(SettingsTypes.Generic);

    // result == WorkspaceSettingsResult.Success
    WorkspaceSettingsResult result = settings.GetProperty("intValue", out int intValue);
    result = settings.GetProperty("stringValue", out string stringValue);
    result = settings.GetProperty("boolValue", out bool boolValue);
    result = settings.GetProperty("stringArray", out string[] stringArray);
    result = settings.GetProperty("nestedIWorkspaceSettings", out IWorkspaceSettings nestedIWorkspaceSettings);
    result = nestedIWorkspaceSettings.GetProperty("nestedString", out string nestedString);

    // Extension method alternative using default values.
    int intValueOrDefault = settings.Property("intValue", /* default */ 42);

    // Missing key. result == WorkspaceSettingsResult.Undefined
    result = settings.GetProperty("missing", out string missing);

    // Wrong type for a key. result == WorkspaceSettingsResult.Error
    result = settings.GetProperty("intValue", out IWorkspaceSettings notSettings);

    // Special ability to union "stringArray" across all scopes.
    IEnumerable<string> allStringArray = settings.UnionPropertyArray<string>("stringArray");
}

注意

這些設定 API 與 Microsoft.VisualStudio.Settings 命名空間中可用的 API 無關。 工作區設定與主機無關,並使用工作區特定的配置檔或動態設定提供者。

提供動態設定

延伸模組可以提供 IWorkspaceSettingsProviders。 這些記憶體中提供者允許擴充功能新增設定或覆蓋其他設定。

IWorkspaceSettingsProvider 匯出方式與其他工作區提供者不同。 工廠不是 IWorkspaceProviderFactory,且沒有特殊的屬性類型。 請改為實作 IWorkspaceSettingsProviderFactory,並使用 [Export(typeof(IWorkspaceSettingsProviderFactory))]

// Common workspace provider factory pattern
[ExportFeatureProvider(some, args, to, export)]
internal class MyProviderFactory : IWorkspaceProviderFactory<IFeatureProvider>
{
     IFeatureProvider CreateProvider(IWorkspace workspace) => new Provider(workspace);
}

// IWorkspaceSettingsProvider pattern
[Export(typeof(IWorkspaceSettingsProviderFactory))]
internal class MySettingsProviderFactory : IWorkspaceSettingsProviderFactory
{
    // 100 is typically the value used by built-in settings providers. Lower value is higher priority.
    int Priority => 100;

    IWorkspaceSettingsProvider CreateSettingsProvider(IWorkspace workspace) => new MySettingsProvider(workspace);
}

提示

實作傳回 IWorkspaceSettingsSource 的方法時(例如 IWorkspaceSettingsProvider.GetSingleSettings),會傳回 IWorkspaceSettings 的實例,而不是 IWorkspaceSettingsSourceIWorkspaceSettings 提供在某些設定聚合期間可能有用的更多資訊。

工作區建議的做法

  • IWorkspaceProviderFactory.CreateProvider 或類似 API 傳回物件,這些 API 會在建立時記住其 Workspace 內容。 提供者介面被設計,預期在物件建立時會被保留。
  • 在工作區的[本機設定] 路徑內儲存工作區特定的快取或設定。 在 Visual Studio 2017 15.6 版或更新版本中,使用 Microsoft.VisualStudio.Workspace.WorkspaceHelper.MakeRootedUnderWorkingFolder 建立檔案的路徑。 針對 15.6 版之前的版本,請使用下列代碼段:
using System.IO;
using Microsoft.VisualStudio.Workspace;
using Microsoft.VisualStudio.Workspace.Settings;

private static string MakeRootedUnderWorkingFolder(IWorkspace workspace, string relativePath)
{
    string workingFolder = workspace.GetSettingsManager().GetAggregatedSettings(SettingsTypes.WorkspaceControlSettings).Property<string>("WorkingFolder");
    return Path.Combine(workingFolder, relativePath);
}

解決方案事件和封裝自動載入

載入的套件可以實作 IVsSolutionEvents7 並叫用 IVsSolution.AdviseSolutionEvents。 其中包含在 Visual Studio 中開啟和關閉資料夾的事件。

UI 上下文可用於自動載入您的套件。 該值為 4646B819-1AE0-4E79-97F4-8A8176FDD664

故障排除

SourceExplorerPackage 套件未正確載入

工作區擴充性大量以MEF為基礎,且組合錯誤會導致裝載Open Folder的套件無法載入。 例如,如果延伸模組匯出具有 ExportFileContextProviderAttribute的類型,但此類型只會實作 IWorkspaceProviderFactory<IFileContextActionProvider>,則嘗試在 Visual Studio 中開啟資料夾時會發生錯誤。

您可以在 %LOCALAPPDATA%\Microsoft\VisualStudio\16.0_id\ComponentModelCache\Microsoft.VisualStudio.Default.err中找到錯誤詳細數據。 解決擴充功能所實作類型的任何錯誤。

  • 檔案語境 - 檔案語境提供者為 [開啟資料夾] 工作區帶來程式碼智慧。
  • 索引編製 - 工作區索引會收集並保存工作區的相關信息。