Made the TPageEnumeration a value type so the multi page view model can start out with 'null' and switch to the initial page after the main window loads

This commit is contained in:
Markus Ewald 2026-04-28 09:31:04 +02:00 committed by Markus Ewald
commit 7d98ba1e0d
3 changed files with 17 additions and 10 deletions

View file

@ -24,8 +24,11 @@ using Nuclex.Avalonia.Commands;
namespace Nuclex.Avalonia.ViewModels {
/// <summary>Interface for view models that can switch between different pages</summary>
/// <typeparam name="TPageEnumeration">Enum type by which pages can be indicated</typeparam>
public interface IMultiPageViewModel<TPageEnumeration> {
/// <typeparam name="TPageEnumeration">
/// Type by which pages can be indicated (typically an enum)
/// </typeparam>
public interface IMultiPageViewModel<TPageEnumeration>
where TPageEnumeration : struct {
/// <summary>Command to switch the active tool page</summary>
IAsyncCommand<TPageEnumeration> SwitchPageCommand { get; }

View file

@ -18,6 +18,7 @@ limitations under the License.
#endregion // Apache License 2.0
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Threading.Tasks;
@ -27,9 +28,12 @@ using Nuclex.Support;
namespace Nuclex.Avalonia.ViewModels {
/// <summary>Base class for view models that have multiple child view models</summary>
/// <typeparam name="TPageEnumeration">Enum type by which pages can be indicated</typeparam>
/// <typeparam name="TPageEnumeration">
/// Type by which pages can be indicated (typically an enum)
/// </typeparam>
public abstract class MultiPageViewModel<TPageEnumeration> :
Observable, IMultiPageViewModel<TPageEnumeration>, IDisposable {
Observable, IMultiPageViewModel<TPageEnumeration>, IDisposable
where TPageEnumeration : struct {
/// <summary>Initializes a new multi-page view model</summary>
/// <param name="windowManager">
@ -98,8 +102,8 @@ namespace Nuclex.Avalonia.ViewModels {
/// <summary>Switches to another page</summary>
/// <param name="newPage">New page to switch to</param>
/// <returns>A task that will finish when the new page has been switched to</returns>
private Task switchPageAsync(TPageEnumeration? newPage) {
if(newPage.Equals(this.activePage)) {
private Task switchPageAsync(TPageEnumeration newPage) {
if(Comparer.Default.Compare(this.activePage, newPage) == 0) {
return Task.CompletedTask;
}
@ -116,7 +120,7 @@ namespace Nuclex.Avalonia.ViewModels {
// Double-checked locking to avoid creating a view model for the same page
// multiple times if the construction takes time
object newPageViewModel;
object? newPageViewModel;
if(!this.cachedViewModels.TryGetValue(newPage, out newPageViewModel)) {
lock(this.cachedViewModels) {
if(!this.cachedViewModels.TryGetValue(newPage, out newPageViewModel)) {
@ -155,7 +159,7 @@ namespace Nuclex.Avalonia.ViewModels {
private readonly ConcurrentDictionary<TPageEnumeration, object>? cachedViewModels;
/// <summary>Page that is currently active in the multi-page view model</summary>
private TPageEnumeration activePage;
private TPageEnumeration? activePage;
/// <summary>View model for the active page</summary>
private object? activePageViewModel;