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();
}