-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathCommandWrapper.cs
70 lines (57 loc) · 3.17 KB
/
CommandWrapper.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
using System;
using System.ComponentModel.Design;
using System.Linq;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.VisualStudio.Shell;
using Task = System.Threading.Tasks.Task;
namespace Community.VisualStudio.Toolkit.DependencyInjection.Core
{
internal class CommandWrapper<T>
where T : BaseDICommand
{
private static readonly MethodInfo _beforeQueryStatusMethod = typeof(BaseDICommand).GetMethods(BindingFlags.Instance | BindingFlags.NonPublic).First(x => x.Name == "BeforeQueryStatus" && x.GetParameters().Count() == 2);
private static readonly MethodInfo _executeMethod = typeof(BaseDICommand).GetMethod("Execute", BindingFlags.Instance | BindingFlags.NonPublic);
private static readonly MethodInfo _executeAsyncMethod = typeof(BaseDICommand).GetMethod("ExecuteAsync", BindingFlags.Instance | BindingFlags.NonPublic);
private readonly IServiceProvider _serviceProvider;
public CommandWrapper(IServiceProvider serviceProvider, AsyncPackage package)
{
this._serviceProvider = serviceProvider;
CommandAttribute? attr = (CommandAttribute)typeof(T).GetCustomAttributes(typeof(CommandAttribute), true).FirstOrDefault();
if (attr is null)
{
throw new InvalidOperationException($"No [Command(GUID, ID)] attribute was added to {typeof(T).Name}");
}
// Use package GUID if no command set GUID has been specified
Guid cmdGuid = attr.Guid == Guid.Empty ? package.GetType().GUID : attr.Guid;
CommandID cmd = new(cmdGuid, attr.Id);
this.Command = new OleMenuCommand(this.Execute, changeHandler: null, this.BeforeQueryStatus, cmd);
ThreadHelper.ThrowIfNotOnUIThread();
IMenuCommandService commandService = serviceProvider.GetRequiredService<IMenuCommandService>();
commandService.AddCommand(this.Command); // Requires main/UI thread
}
/// <summary>
/// The command object associated with the command ID (GUID/ID).
/// </summary>
public OleMenuCommand Command { get; }
protected void BeforeQueryStatus(object sender, EventArgs e)
{
using var scope = this._serviceProvider.CreateScope();
BaseDICommand instance = (BaseDICommand)scope.ServiceProvider.GetRequiredService(typeof(T));
_beforeQueryStatusMethod.Invoke(instance, new object[] { sender, e });
}
protected void Execute(object sender, EventArgs e)
{
using var scope = this._serviceProvider.CreateScope();
BaseDICommand instance = (BaseDICommand)scope.ServiceProvider.GetRequiredService(typeof(T));
_executeMethod.Invoke(instance, new object[] { sender, e });
}
protected async Task ExecuteAsync(OleMenuCmdEventArgs e)
{
using var scope = this._serviceProvider.CreateScope();
BaseDICommand instance = (BaseDICommand)scope.ServiceProvider.GetRequiredService(typeof(T));
Task executeAsyncTask = (Task)_executeAsyncMethod.Invoke(instance, new object[] { e });
await executeAsyncTask;
}
}
}