@@ -21,21 +21,28 @@ namespace GitHub.VisualStudio.Base
2121 public class TeamExplorerServiceHolder : ITeamExplorerServiceHolder
2222 {
2323 static readonly ILogger log = LogManager . ForContext < TeamExplorerServiceHolder > ( ) ;
24- readonly IVSUIContextFactory uiContextFactory ;
2524 readonly Dictionary < object , Action < ILocalRepositoryModel > > activeRepoHandlers = new Dictionary < object , Action < ILocalRepositoryModel > > ( ) ;
2625 ILocalRepositoryModel activeRepo ;
2726 bool activeRepoNotified = false ;
2827
2928 IServiceProvider serviceProvider ;
3029 IVSGitExt gitService ;
3130 IVSUIContext gitUIContext ;
31+ IVSUIContextFactory uiContextFactory ;
3232
3333 // ActiveRepositories PropertyChanged event comes in on a non-main thread
3434 readonly SynchronizationContext syncContext ;
3535
36- public TeamExplorerServiceHolder ( IVSUIContextFactory uiContextFactory , IVSGitExt gitService )
36+ /// <summary>
37+ /// This class relies on IVSUIContextFactory to get the UIContext object that provides information
38+ /// when VS switches repositories. Unfortunately, for some reason MEF fails to create the instance
39+ /// when imported from the constructor, so it's imported manually when first accessed via the
40+ /// ServiceProvider instance (when mocking, make sure that the ServiceProvider includes this factory)
41+ /// </summary>
42+ /// <param name="gitService"></param>
43+ [ ImportingConstructor ]
44+ public TeamExplorerServiceHolder ( IVSGitExt gitService )
3745 {
38- this . uiContextFactory = uiContextFactory ;
3946 this . GitService = gitService ;
4047 syncContext = SynchronizationContext . Current ;
4148 }
@@ -52,7 +59,7 @@ public IServiceProvider ServiceProvider
5259 serviceProvider = value ;
5360 if ( serviceProvider == null )
5461 return ;
55- GitUIContext = GitUIContext ?? uiContextFactory . GetUIContext ( new Guid ( Guids . GitSccProviderId ) ) ;
62+ GitUIContext = GitUIContext ?? UIContextFactory . GetUIContext ( new Guid ( Guids . GitSccProviderId ) ) ;
5663 UIContextChanged ( GitUIContext ? . IsActive ?? false , false ) ;
5764 }
5865 }
@@ -80,7 +87,7 @@ public void Subscribe(object who, Action<ILocalRepositoryModel> handler)
8087
8188 bool notificationsExist ;
8289 ILocalRepositoryModel repo ;
83- lock ( activeRepoHandlers )
90+ lock ( activeRepoHandlers )
8491 {
8592 repo = ActiveRepo ;
8693 notificationsExist = activeRepoNotified ;
@@ -128,7 +135,7 @@ public void ClearServiceProvider(IServiceProvider provider)
128135
129136 public void Refresh ( )
130137 {
131- GitUIContext = GitUIContext ?? uiContextFactory . GetUIContext ( new Guid ( Guids . GitSccProviderId ) ) ;
138+ GitUIContext = GitUIContext ?? UIContextFactory . GetUIContext ( new Guid ( Guids . GitSccProviderId ) ) ;
132139 UIContextChanged ( GitUIContext ? . IsActive ?? false , true ) ;
133140 }
134141
@@ -142,14 +149,19 @@ void NotifyActiveRepo()
142149 }
143150 }
144151
145- void UIContextChanged ( object sender , UIContextChangedEventArgs e )
152+ void UIContextChanged ( object sender , IVSUIContextChangedEventArgs e )
146153 {
147154 Guard . ArgumentNotNull ( e , nameof ( e ) ) ;
148155
149156 ActiveRepo = null ;
150157 UIContextChanged ( e . Activated , false ) ;
151158 }
152159
160+ /// <summary>
161+ /// This is called on a background thread. Do not do synchronous GetService calls here.
162+ /// </summary>
163+ /// <param name="active"></param>
164+ /// <param name="refresh"></param>
153165 async void UIContextChanged ( bool active , bool refresh )
154166 {
155167 Debug . Assert ( ServiceProvider != null , "UIContextChanged called before service provider is set" ) ;
@@ -170,7 +182,7 @@ async void UIContextChanged(bool active, bool refresh)
170182 {
171183 log . Error ( "Error 2001: ActiveRepositories is null. GitService: '{GitService}'" , GitService ) ;
172184 GitService . Refresh ( ServiceProvider ) ;
173- repos = GitService ? . ActiveRepositories ;
185+ repos = GitService . ActiveRepositories ;
174186 if ( repos == null )
175187 log . Error ( "Error 2002: ActiveRepositories is null. GitService: '{GitService}'" , GitService ) ;
176188 }
@@ -245,6 +257,74 @@ IVSGitExt GitService
245257 gitService . ActiveRepositoriesChanged += UpdateActiveRepo ;
246258 }
247259 }
260+
261+ IVSUIContextFactory UIContextFactory
262+ {
263+ get
264+ {
265+ if ( uiContextFactory == null )
266+ {
267+ uiContextFactory = ServiceProvider . GetServiceSafe < IVSUIContextFactory > ( ) ;
268+ }
269+ return uiContextFactory ;
270+ }
271+ }
272+ }
273+
274+ [ Export ( typeof ( IVSUIContextFactory ) ) ]
275+ [ PartCreationPolicy ( CreationPolicy . Shared ) ]
276+ class VSUIContextFactory : IVSUIContextFactory
277+ {
278+ public IVSUIContext GetUIContext ( Guid contextGuid )
279+ {
280+ return new VSUIContext ( UIContext . FromUIContextGuid ( contextGuid ) ) ;
281+ }
282+ }
283+
284+ class VSUIContextChangedEventArgs : IVSUIContextChangedEventArgs
285+ {
286+ public bool Activated { get ; }
287+
288+ public VSUIContextChangedEventArgs ( bool activated )
289+ {
290+ Activated = activated ;
291+ }
292+ }
293+
294+ class VSUIContext : IVSUIContext
295+ {
296+ readonly UIContext context ;
297+ readonly Dictionary < EventHandler < IVSUIContextChangedEventArgs > , EventHandler < UIContextChangedEventArgs > > handlers =
298+ new Dictionary < EventHandler < IVSUIContextChangedEventArgs > , EventHandler < UIContextChangedEventArgs > > ( ) ;
299+ public VSUIContext ( UIContext context )
300+ {
301+ this . context = context ;
302+ }
303+
304+ public bool IsActive { get { return context . IsActive ; } }
305+
306+ public event EventHandler < IVSUIContextChangedEventArgs > UIContextChanged
307+ {
308+ add
309+ {
310+ EventHandler < UIContextChangedEventArgs > handler = null ;
311+ if ( ! handlers . TryGetValue ( value , out handler ) )
312+ {
313+ handler = ( s , e ) => value . Invoke ( s , new VSUIContextChangedEventArgs ( e . Activated ) ) ;
314+ handlers . Add ( value , handler ) ;
315+ }
316+ context . UIContextChanged += handler ;
317+ }
318+ remove
319+ {
320+ EventHandler < UIContextChangedEventArgs > handler = null ;
321+ if ( handlers . TryGetValue ( value , out handler ) )
322+ {
323+ handlers . Remove ( value ) ;
324+ context . UIContextChanged -= handler ;
325+ }
326+ }
327+ }
248328 }
249329
250330 static class IGitRepositoryInfoExtensions
0 commit comments