3
3
using System . ComponentModel . Design ;
4
4
using System . Diagnostics . CodeAnalysis ;
5
5
using System . Linq ;
6
+ using System . Management . Instrumentation ;
7
+ using System . Threading . Tasks ;
6
8
using Microsoft . VisualStudio . Shell ;
7
9
using Uno . UI . RemoteControl . Messaging . IdeChannel ;
8
10
using Uno . UI . RemoteControl . VS . Commands ;
11
13
12
14
namespace Uno . UI . RemoteControl . VS ;
13
15
14
- internal sealed class UnoMenuCommand
16
+ internal sealed class UnoMenuCommand : IDisposable
15
17
{
16
18
private readonly AsyncPackage _package ;
17
19
private OleMenuCommandService CommandService { get ; set ; }
18
20
private IdeChannelClient IdeChannelClient ;
19
-
21
+ private DynamicItemMenuCommand ? _dynamicMenuCommand ;
22
+ private OleMenuCommand ? _unoMainMenuItem ;
20
23
private static readonly Guid UnoStudioPackageCmdSet = new Guid ( "6c532d75-ee35-4726-a1cd-338c5243e38f" ) ;
21
24
private static readonly int UnoMainMenu = 0x4100 ;
22
25
private static readonly int DynamicMenuCommandId = 0x4103 ;
23
26
24
27
public List < AddMenuItemRequestIdeMessage > CommandList { get ; set ; } = [ ] ;
25
- public static UnoMenuCommand ? Instance { get ; private set ; }
26
28
27
- private UnoMenuCommand ( AsyncPackage package , IdeChannelClient ideChannelClient , OleMenuCommandService commandService , AddMenuItemRequestIdeMessage cr )
29
+ private UnoMenuCommand (
30
+ AsyncPackage package
31
+ , IdeChannelClient ideChannelClient
32
+ , OleMenuCommandService commandService
33
+ , AddMenuItemRequestIdeMessage cr )
28
34
{
29
35
_package = package ?? throw new ArgumentNullException ( nameof ( _package ) ) ;
30
36
CommandService = commandService = commandService ?? throw new ArgumentNullException ( nameof ( commandService ) ) ;
31
37
IdeChannelClient = ideChannelClient ?? throw new ArgumentNullException ( nameof ( ideChannelClient ) ) ;
32
38
CommandList . Add ( cr ) ;
33
39
34
- CommandID dynamicItemRootId = new CommandID ( UnoStudioPackageCmdSet , DynamicMenuCommandId ) ;
40
+ var dynamicItemRootId = new CommandID ( UnoStudioPackageCmdSet , DynamicMenuCommandId ) ;
35
41
if ( commandService . FindCommand ( dynamicItemRootId ) is not DynamicItemMenuCommand )
36
42
{
37
- DynamicItemMenuCommand dynamicMenuCommand = new DynamicItemMenuCommand (
43
+ _dynamicMenuCommand = new DynamicItemMenuCommand (
38
44
dynamicItemRootId ,
39
45
IsValidDynamicItem ,
40
46
OnInvokedDynamicItem ,
41
47
OnBeforeQueryStatusDynamicItem ) ;
42
- commandService . AddCommand ( dynamicMenuCommand ) ;
48
+ commandService . AddCommand ( _dynamicMenuCommand ) ;
49
+ }
50
+
51
+ var unoMainMenuId = new CommandID ( UnoStudioPackageCmdSet , UnoMainMenu ) ;
52
+ if ( commandService . FindCommand ( unoMainMenuId ) is not OleMenuCommand )
53
+ {
54
+ _unoMainMenuItem = new OleMenuCommand ( null , unoMainMenuId ) ;
55
+ _unoMainMenuItem . BeforeQueryStatus += OnBeforeQueryStatus ;
56
+ commandService . AddCommand ( _unoMainMenuItem ) ;
57
+ }
58
+
59
+ var dynamicMenuCommandIdId = new CommandID ( UnoStudioPackageCmdSet , DynamicMenuCommandId ) ;
60
+ if ( commandService . FindCommand ( dynamicMenuCommandIdId ) is DynamicItemMenuCommand dynamicMenuItem )
61
+ {
62
+ dynamicMenuItem . BeforeQueryStatus += OnBeforeQueryStatus ;
43
63
}
44
64
}
45
65
46
- public static async Task InitializeAsync ( AsyncPackage package , IdeChannelClient ideChannelClient , AddMenuItemRequestIdeMessage cr )
66
+ public static async Task < UnoMenuCommand > InitializeAsync (
67
+ AsyncPackage package
68
+ , IdeChannelClient ideChannelClient
69
+ , AddMenuItemRequestIdeMessage cr )
47
70
{
48
71
// Switch to the main thread - the call to AddCommand in DynamicMenu's constructor requires the UI thread.
49
72
await ThreadHelper . JoinableTaskFactory . SwitchToMainThreadAsync ( package . DisposalToken ) ;
50
73
51
- if ( Instance is null
52
- && await package . GetServiceAsync ( typeof ( IMenuCommandService ) ) is OleMenuCommandService commandService )
74
+ if ( await package . GetServiceAsync ( typeof ( IMenuCommandService ) ) is OleMenuCommandService commandService )
53
75
{
54
- Instance = new UnoMenuCommand ( package , ideChannelClient , commandService , cr ) ;
55
-
56
- CommandID unoMainMenuId = new CommandID ( UnoStudioPackageCmdSet , UnoMainMenu ) ;
57
- if ( Instance . CommandService . FindCommand ( unoMainMenuId ) is not OleMenuCommand )
58
- {
59
- var unoMenuItem = new OleMenuCommand ( null , unoMainMenuId ) ;
60
- unoMenuItem . BeforeQueryStatus += Instance . OnBeforeQueryStatus ;
61
- commandService . AddCommand ( unoMenuItem ) ;
62
- }
63
-
64
- CommandID dynamicMenuCommandIdId = new CommandID ( UnoStudioPackageCmdSet , DynamicMenuCommandId ) ;
65
- if ( Instance . CommandService . FindCommand ( dynamicMenuCommandIdId ) is DynamicItemMenuCommand dynamicMenuItem )
66
- {
67
- dynamicMenuItem . BeforeQueryStatus += Instance . OnBeforeQueryStatus ;
68
- }
76
+ return new UnoMenuCommand ( package , ideChannelClient , commandService , cr ) ;
69
77
}
78
+
79
+ throw new InvalidOperationException ( "IMenuCommandService is not availabe" ) ;
70
80
}
71
81
72
82
private void OnBeforeQueryStatus ( object sender , EventArgs e )
@@ -108,10 +118,12 @@ sender is DynamicItemMenuCommand matchedCommand &&
108
118
private void OnBeforeQueryStatusDynamicItem ( object sender , EventArgs args )
109
119
{
110
120
ThreadHelper . ThrowIfNotOnUIThread ( ) ;
121
+
111
122
if ( ! CommandList . Any ( ) )
112
123
{
113
124
return ;
114
125
}
126
+
115
127
DynamicItemMenuCommand matchedCommand = ( DynamicItemMenuCommand ) sender ;
116
128
matchedCommand . Enabled = true ;
117
129
matchedCommand . Visible = true ;
@@ -124,10 +136,24 @@ private void OnBeforeQueryStatusDynamicItem(object sender, EventArgs args)
124
136
matchedCommand . MatchedCommandId = 0 ;
125
137
}
126
138
127
- private static int GetCurrentPosition ( DynamicItemMenuCommand matchedCommand ) =>
128
- // The position of the command is the command ID minus the ID of the root dynamic start item.
129
- matchedCommand . MatchedCommandId == 0 ? 0 : matchedCommand . MatchedCommandId - ( int ) DynamicMenuCommandId ;
139
+ private static int GetCurrentPosition ( DynamicItemMenuCommand matchedCommand )
140
+ // The position of the command is the command ID minus the ID of the root dynamic start item.
141
+ => matchedCommand . MatchedCommandId == 0 ? 0 : matchedCommand . MatchedCommandId - ( int ) DynamicMenuCommandId ;
130
142
131
143
private bool TryGetCommandRequestIdeMessage ( DynamicItemMenuCommand matchedCommand , [ NotNullWhen ( true ) ] out AddMenuItemRequestIdeMessage result )
132
144
=> ( result = CommandList . Skip ( GetCurrentPosition ( matchedCommand ) ) . FirstOrDefault ( ) ) != null ;
145
+
146
+ public void Dispose ( )
147
+ {
148
+ if ( _dynamicMenuCommand is not null )
149
+ {
150
+ CommandService . RemoveCommand ( _dynamicMenuCommand ) ;
151
+ }
152
+
153
+ if ( _unoMainMenuItem is not null )
154
+ {
155
+ _unoMainMenuItem . Enabled = false ;
156
+ _unoMainMenuItem . Visible = false ;
157
+ }
158
+ }
133
159
}
0 commit comments