Skip to content

Commit 054b9dd

Browse files
committed
Visual Studio Facade is now distributed using Dependency Injection
1 parent a755c79 commit 054b9dd

22 files changed

+286
-148
lines changed

src/ExtensionManager.UI/Attached/VSTheme.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1+
using System.Threading;
12
using System.Windows;
23

3-
using ExtensionManager.VisualStudio;
4+
using ExtensionManager.VisualStudio.Themes;
45

56
namespace ExtensionManager.UI.Attached;
67

78
internal static class VSTheme
89
{
10+
private static IVSThemes? _themes;
11+
912
public static readonly DependencyProperty UseProperty;
1013

1114
static VSTheme()
@@ -20,19 +23,22 @@ static VSTheme()
2023
});
2124
}
2225

26+
public static void Initialize(IVSThemes themes)
27+
=> Interlocked.Exchange(ref _themes, themes);
28+
2329
public static void SetUse(UIElement element, bool value) => element.SetValue(UseProperty, value);
2430
public static bool GetUse(UIElement element) => (bool)element.GetValue(UseProperty);
2531

2632
private static void OnUsePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
2733
{
28-
if (!VSFacade.IsInitialized)
34+
if (_themes is not { } themes)
2935
return;
3036

3137
if (d is not UIElement element)
3238
return;
3339
if (e.NewValue is not bool value)
3440
return;
3541

36-
VSFacade.Themes.Use(element, value);
42+
themes.Use(element, value);
3743
}
3844
}

src/ExtensionManager.UI/DialogService.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using ExtensionManager.UI.Worker;
1111
using ExtensionManager.VisualStudio;
1212
using ExtensionManager.VisualStudio.Extensions;
13+
using ExtensionManager.VisualStudio.Threads;
1314

1415
using Microsoft.Win32;
1516

@@ -19,15 +20,22 @@ namespace ExtensionManager.UI;
1920

2021
internal sealed class DialogService : IDialogService
2122
{
23+
private readonly IVSThreads _threads;
24+
25+
public DialogService(IVSThreads threads)
26+
{
27+
_threads = threads;
28+
}
29+
2230
public Task<string?> ShowSaveVsextFileDialogAsync() => ShowVsextFileDialogAsync<SaveFileDialog>();
2331
public Task<string?> ShowOpenVsextFileDialogAsync() => ShowVsextFileDialogAsync<OpenFileDialog>();
2432
private Task<string?> ShowVsextFileDialogAsync<TFileDialog>()
2533
where TFileDialog : FileDialog, new()
2634
{
27-
if (VSFacade.Threads.CheckUIThreadAccess())
35+
if (_threads.CheckUIThreadAccess())
2836
return Task.FromResult(OnUIThread());
2937

30-
return VSFacade.Threads.RunOnUIThreadAsync(OnUIThread);
38+
return _threads.RunOnUIThreadAsync(OnUIThread);
3139

3240
static string? OnUIThread()
3341
{
@@ -79,14 +87,14 @@ private async Task ShowInstallForSolutionDialogAsync(IInstallWorker worker, IMan
7987

8088
private Task ShowInstallExportDialogAsync(object viewModel)
8189
{
82-
if (VSFacade.Threads.CheckUIThreadAccess())
90+
if (_threads.CheckUIThreadAccess())
8391
{
8492
OnUIThread(viewModel);
8593

8694
return Task.CompletedTask;
8795
}
8896

89-
return VSFacade.Threads.RunOnUIThreadAsync(() => OnUIThread(viewModel));
97+
return _threads.RunOnUIThreadAsync(() => OnUIThread(viewModel));
9098

9199
static void OnUIThread(object viewModel)
92100
{

src/ExtensionManager.VisualStudio.Abstractions/ExtensionManager.VisualStudio.Abstractions.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
<Compile Remove="IVisualStudioUIThread.cs" />
1515
<Compile Remove="IVisualStudioViewColors.cs" />
1616
<Compile Remove="IVisualStudioViewResourceKeys.cs" />
17-
<Compile Remove="ServiceCollectionExtensions.cs" />
1817
</ItemGroup>
1918

2019
<ItemGroup>
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using ExtensionManager.VisualStudio.Documents;
2+
using ExtensionManager.VisualStudio.Extensions;
3+
using ExtensionManager.VisualStudio.MessageBox;
4+
using ExtensionManager.VisualStudio.Solution;
5+
using ExtensionManager.VisualStudio.StatusBar;
6+
using ExtensionManager.VisualStudio.Themes;
7+
using ExtensionManager.VisualStudio.Threads;
8+
9+
namespace ExtensionManager.VisualStudio;
10+
11+
/// <summary>
12+
/// This class is an abstraction around the Visual Studio API and should have the same look and feel as the Community.VisualStudio.Toolkit.VS class.
13+
/// </summary>
14+
public interface IVSFacade
15+
{
16+
/// <summary>Contains methods for WPF to deal with Visual Studio Themes.</summary>
17+
IVSThemes Themes { get; }
18+
19+
/// <summary> Contains methods for dealing with threads. </summary>
20+
IVSThreads Threads { get; }
21+
22+
/// <summary> A collection of services related to solutions. </summary>
23+
IVSSolutions Solutions { get; }
24+
25+
/// <summary> An API wrapper that makes it easy to work with the status bar. </summary>
26+
IVSStatusBar StatusBar { get; }
27+
28+
/// <summary> Contains helper methods for dealing with documents. </summary>
29+
IVSDocuments Documents { get; }
30+
31+
/// <summary> Shows message boxes. </summary>
32+
IVSMessageBox MessageBox { get; }
33+
34+
/// <summary> Contains methods for dealing with Visual Studio Extensions. </summary>
35+
IVSExtensions Extensions { get; }
36+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using ExtensionManager.VisualStudio.Documents;
2+
using ExtensionManager.VisualStudio.Extensions;
3+
using ExtensionManager.VisualStudio.MessageBox;
4+
using ExtensionManager.VisualStudio.Solution;
5+
using ExtensionManager.VisualStudio.StatusBar;
6+
using ExtensionManager.VisualStudio.Themes;
7+
using ExtensionManager.VisualStudio.Threads;
8+
9+
namespace ExtensionManager.VisualStudio;
10+
11+
public interface IVSServiceFactory
12+
{
13+
IVSThemes CreateThemes();
14+
IVSThreads CreateThreads();
15+
IVSSolutions CreateSolutions();
16+
IVSStatusBar CreateStatusBar();
17+
IVSDocuments CreateDocuments();
18+
IVSMessageBox CreateMessageBox();
19+
IVSExtensions CreateExtensions();
20+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using Microsoft.Extensions.DependencyInjection;
2+
3+
namespace ExtensionManager.VisualStudio;
4+
5+
public static class ServiceCollectionExtensions
6+
{
7+
public static IServiceCollection ConfigureVSFacade(this IServiceCollection services, IVSServiceFactory serviceFactory)
8+
{
9+
services.AddSingleton<IVSFacade>(new VSFacade(serviceFactory));
10+
11+
services.AddTransient(s => s.GetRequiredService<IVSFacade>().Themes);
12+
services.AddTransient(s => s.GetRequiredService<IVSFacade>().Threads);
13+
services.AddTransient(s => s.GetRequiredService<IVSFacade>().Solutions);
14+
services.AddTransient(s => s.GetRequiredService<IVSFacade>().StatusBar);
15+
services.AddTransient(s => s.GetRequiredService<IVSFacade>().Documents);
16+
services.AddTransient(s => s.GetRequiredService<IVSFacade>().MessageBox);
17+
services.AddTransient(s => s.GetRequiredService<IVSFacade>().Extensions);
18+
19+
return services;
20+
}
21+
}
Lines changed: 18 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
using System;
2-
using System.Threading;
3-
41
using ExtensionManager.VisualStudio.Documents;
52
using ExtensionManager.VisualStudio.Extensions;
63
using ExtensionManager.VisualStudio.MessageBox;
@@ -14,64 +11,40 @@ namespace ExtensionManager.VisualStudio;
1411
/// <summary>
1512
/// This class is an abstraction around the Visual Studio API and should have the same look and feel as the Community.VisualStudio.Toolkit.VS class.
1613
/// </summary>
17-
public abstract class VSFacade
14+
public sealed class VSFacade : IVSFacade
1815
{
19-
private static VSFacade? _instance;
20-
private static IVSThemes? _themes;
21-
private static IVSThreads? _threads;
22-
private static IVSSolutions? _solutions;
23-
private static IVSStatusBar? _statusBar;
24-
private static IVSDocuments? _documents;
25-
private static IVSMessageBox? _messageBox;
26-
private static IVSExtensions? _extensions;
27-
28-
/// <summary>
29-
/// Indicates whether this <see cref="VSFacade"/> is initialised or not. <br/>
30-
/// This should always be <see langword="true"/> at runtime and <see langword="false"/> at design time.
31-
/// </summary>
32-
public static bool IsInitialized => _instance is not null;
16+
private readonly IVSServiceFactory _factory;
17+
private IVSThemes? _themes;
18+
private IVSThreads? _threads;
19+
private IVSSolutions? _solutions;
20+
private IVSStatusBar? _statusBar;
21+
private IVSDocuments? _documents;
22+
private IVSMessageBox? _messageBox;
23+
private IVSExtensions? _extensions;
3324

3425
/// <summary>Contains methods for WPF to deal with Visual Studio Themes.</summary>
35-
public static IVSThemes Themes => _themes ??= Instance.CreateThemes();
26+
public IVSThemes Themes => _themes ??= _factory.CreateThemes();
3627

3728
/// <summary> Contains methods for dealing with threads. </summary>
38-
public static IVSThreads Threads => _threads ??= Instance.CreateThreads();
29+
public IVSThreads Threads => _threads ??= _factory.CreateThreads();
3930

4031
/// <summary> A collection of services related to solutions. </summary>
41-
public static IVSSolutions Solutions => _solutions ??= Instance.CreateSolutions();
32+
public IVSSolutions Solutions => _solutions ??= _factory.CreateSolutions();
4233

4334
/// <summary> An API wrapper that makes it easy to work with the status bar. </summary>
44-
public static IVSStatusBar StatusBar => _statusBar ??= Instance.CreateStatusBar();
35+
public IVSStatusBar StatusBar => _statusBar ??= _factory.CreateStatusBar();
4536

4637
/// <summary> Contains helper methods for dealing with documents. </summary>
47-
public static IVSDocuments Documents => _documents ??= Instance.CreateDocuments();
38+
public IVSDocuments Documents => _documents ??= _factory.CreateDocuments();
4839

4940
/// <summary> Shows message boxes. </summary>
50-
public static IVSMessageBox MessageBox => _messageBox ??= Instance.CreateMessageBox();
41+
public IVSMessageBox MessageBox => _messageBox ??= _factory.CreateMessageBox();
5142

5243
/// <summary> Contains methods for dealing with Visual Studio Extensions. </summary>
53-
public static IVSExtensions Extensions => _extensions ??= Instance.CreateExtensions();
54-
55-
private static VSFacade Instance
56-
{
57-
get => _instance ?? throw new InvalidOperationException("VS facade was not already initialized");
58-
}
44+
public IVSExtensions Extensions => _extensions ??= _factory.CreateExtensions();
5945

60-
protected static void Initialize(VSFacade instance)
46+
public VSFacade(IVSServiceFactory factory)
6147
{
62-
var oldInstance = Interlocked.CompareExchange(ref _instance, instance, null);
63-
64-
if (oldInstance is not null)
65-
throw new InvalidOperationException("VS facade was already initialized");
48+
_factory = factory;
6649
}
67-
68-
protected VSFacade() { }
69-
70-
protected abstract IVSThemes CreateThemes();
71-
protected abstract IVSThreads CreateThreads();
72-
protected abstract IVSSolutions CreateSolutions();
73-
protected abstract IVSStatusBar CreateStatusBar();
74-
protected abstract IVSDocuments CreateDocuments();
75-
protected abstract IVSMessageBox CreateMessageBox();
76-
protected abstract IVSExtensions CreateExtensions();
7750
}

src/ExtensionManager.VisualStudio.Shared/ExtensionManager.VisualStudio.Shared.projitems

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,6 @@
1919
<Compile Include="$(MSBuildThisFileDirectory)StatusBar\VSStatusBar.cs" />
2020
<Compile Include="$(MSBuildThisFileDirectory)Themes\VSThemes.cs" />
2121
<Compile Include="$(MSBuildThisFileDirectory)Threads\VSThreads.cs" />
22-
<Compile Include="$(MSBuildThisFileDirectory)VSFacadeImplementation.cs" />
22+
<Compile Include="$(MSBuildThisFileDirectory)VSServiceFactory.cs" />
2323
</ItemGroup>
2424
</Project>

src/ExtensionManager.VisualStudio.Shared/VSFacadeImplementation.cs

Lines changed: 0 additions & 30 deletions
This file was deleted.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using ExtensionManager.VisualStudio.Documents;
2+
using ExtensionManager.VisualStudio.Extensions;
3+
using ExtensionManager.VisualStudio.MessageBox;
4+
using ExtensionManager.VisualStudio.Solution;
5+
using ExtensionManager.VisualStudio.StatusBar;
6+
using ExtensionManager.VisualStudio.Themes;
7+
using ExtensionManager.VisualStudio.Threads;
8+
9+
#if V15
10+
namespace ExtensionManager.VisualStudio.V15;
11+
#elif V16
12+
namespace ExtensionManager.VisualStudio.V16;
13+
#elif V17_5
14+
namespace ExtensionManager.VisualStudio.V17_5;
15+
#elif V17_7
16+
namespace ExtensionManager.VisualStudio.V17_7;
17+
#endif
18+
19+
public sealed class VSServiceFactory : IVSServiceFactory
20+
{
21+
public IVSThemes CreateThemes() => new VSThemes();
22+
public IVSThreads CreateThreads() => new VSThreads();
23+
public IVSSolutions CreateSolutions() => new VSSolutions();
24+
public IVSStatusBar CreateStatusBar() => new VSStatusBar();
25+
public IVSDocuments CreateDocuments() => new VSDocuments();
26+
public IVSMessageBox CreateMessageBox() => new VSMessageBox();
27+
public IVSExtensions CreateExtensions() => new VSExtensions();
28+
}

0 commit comments

Comments
 (0)