diff --git a/src/modules/cmdpal/Microsoft.CmdPal.Common/Services/IRootPageService.cs b/src/modules/cmdpal/Microsoft.CmdPal.Common/Services/IRootPageService.cs index da56775eec..24e509b8a4 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.Common/Services/IRootPageService.cs +++ b/src/modules/cmdpal/Microsoft.CmdPal.Common/Services/IRootPageService.cs @@ -16,13 +16,13 @@ public interface IRootPageService /// /// Pre-loads any necessary data or state before the root page is loaded. - /// This will be awaited before the root page and the user can do anything, + /// This will be awaited before the root page and the user can do anything, /// so ideally it should be quick and not block the UI thread for long. /// Task PreLoadAsync(); /// - /// Do any loading work that can be done after the root page is loaded and + /// Do any loading work that can be done after the root page is loaded and /// displayed to the user. /// This is run asynchronously, on a background thread. /// diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/PageViewModel.cs b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/PageViewModel.cs index 126efa83ca..681f7bc7f1 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/PageViewModel.cs +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/PageViewModel.cs @@ -249,7 +249,19 @@ public partial class PageViewModel : ExtensionObjectViewModel, IPageContext public interface IPageContext { - public void ShowException(Exception ex, string? extensionHint = null); + void ShowException(Exception ex, string? extensionHint = null); - public TaskScheduler Scheduler { get; } + TaskScheduler Scheduler { get; } +} + +public interface IPageViewModelFactoryService +{ + /// + /// Creates a new instance of the page view model for the given page type. + /// + /// The page for which to create the view model. + /// Indicates whether the page is not the top-level page. + /// The command palette host that will host the page (for status messages) + /// A new instance of the page view model. + PageViewModel? TryCreatePageViewModel(IPage page, bool nested, CommandPaletteHost host); } diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/PageViewModelFactory.cs b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/PageViewModelFactory.cs new file mode 100644 index 0000000000..83dbe51624 --- /dev/null +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/PageViewModelFactory.cs @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation +// The Microsoft Corporation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CommandPalette.Extensions; + +namespace Microsoft.CmdPal.UI.ViewModels; + +public class PageViewModelFactory : IPageViewModelFactoryService +{ + private readonly TaskScheduler _scheduler; + + public PageViewModelFactory(TaskScheduler scheduler) + { + _scheduler = scheduler; + } + + public PageViewModel? TryCreatePageViewModel(IPage page, bool nested, CommandPaletteHost host) + { + return page switch + { + IListPage listPage => new ListViewModel(listPage, _scheduler, host) { IsNested = nested }, + IContentPage contentPage => new ContentPageViewModel(contentPage, _scheduler, host), + _ => null, + }; + } +} diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/ShellViewModel.cs b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/ShellViewModel.cs index 43f1508906..294b0021c7 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/ShellViewModel.cs +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/ShellViewModel.cs @@ -21,6 +21,7 @@ public partial class ShellViewModel : ObservableObject, { private readonly IRootPageService _rootPageService; private readonly TaskScheduler _scheduler; + private readonly IPageViewModelFactoryService _pageViewModelFactory; private readonly Lock _invokeLock = new(); private Task? _handleInvokeTask; @@ -65,8 +66,9 @@ public partial class ShellViewModel : ObservableObject, public bool IsNested { get => _isNested; } - public ShellViewModel(TaskScheduler scheduler, IRootPageService rootPageService) + public ShellViewModel(TaskScheduler scheduler, IRootPageService rootPageService, IPageViewModelFactoryService pageViewModelFactory) { + _pageViewModelFactory = pageViewModelFactory; _scheduler = scheduler; _rootPageService = rootPageService; _currentPage = new LoadingPageViewModel(null, _scheduler); @@ -87,6 +89,7 @@ public partial class ShellViewModel : ObservableObject, // Now that the basics are set up, we can load the root page. _rootPage = _rootPageService.GetRootPage(); + // This sends a message to us to load the root page view model. WeakReferenceMessenger.Default.Send(new(new ExtensionObject(_rootPage))); @@ -251,7 +254,7 @@ public partial class ShellViewModel : ObservableObject, _isNested = !isMainPage; // Construct our ViewModel of the appropriate type and pass it the UI Thread context. - var pageViewModel = GetViewModelForPage(page, _isNested, host); + var pageViewModel = _pageViewModelFactory.TryCreatePageViewModel(page, _isNested, host); if (pageViewModel == null) { Logger.LogError($"Failed to create ViewModel for page {page.GetType().Name}"); @@ -396,19 +399,6 @@ public partial class ShellViewModel : ObservableObject, } } - private PageViewModel? GetViewModelForPage(IPage page, bool nested, CommandPaletteHost host) - { - return page switch - { - IListPage listPage => new ListViewModel(listPage, _scheduler, host) - { - IsNested = nested, - }, - IContentPage contentPage => new ContentPageViewModel(contentPage, _scheduler, host), - _ => null, - }; - } - public void SetActiveExtension(IExtensionWrapper? extension) { if (extension != _activeExtension) diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI/App.xaml.cs b/src/modules/cmdpal/Microsoft.CmdPal.UI/App.xaml.cs index d34bd667fe..2c7d0afc15 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.UI/App.xaml.cs +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI/App.xaml.cs @@ -148,6 +148,7 @@ public partial class App : Application // ViewModels services.AddSingleton(); + services.AddSingleton(); return services.BuildServiceProvider(); }