Workshop - Added filtering, sorting and changable entries per page

This commit is contained in:
Robert committed 2023-09-23 23:08:28 +02:00
1 parent aa8519b33c
commit 4994b3fb44
18 files changed
+396 -159

No files matched your search

@@ -0,0 +1,42 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:entries="clr-namespace:Artemis.UI.Screens.Workshop.Entries"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.Workshop.Entries.EntryListInputView"
x:DataType="entries:EntryListInputViewModel">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" MaxWidth="500" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Name="SearchBox" Classes="search-box" Watermark="{CompiledBinding SearchWatermark}" Text="{CompiledBinding Search}"/>
<StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right" Spacing="5" Margin="5 0">
<TextBlock VerticalAlignment="Center">Sort by</TextBlock>
<ComboBox Width="165" SelectedIndex="{CompiledBinding SortBy}">
<ComboBoxItem>Recently updated</ComboBoxItem>
<ComboBoxItem>Recently added</ComboBoxItem>
<ComboBoxItem>Download count</ComboBoxItem>
</ComboBox>
</StackPanel>
<StackPanel Grid.Column="2" Orientation="Horizontal" Spacing="5">
<TextBlock VerticalAlignment="Center">Show per page</TextBlock>
<ComboBox Width="65" SelectedItem="{CompiledBinding EntriesPerPage}">
<system:Int32>10</system:Int32>
<system:Int32>20</system:Int32>
<system:Int32>50</system:Int32>
<system:Int32>100</system:Int32>
</ComboBox>
</StackPanel>
<TextBlock Grid.Column="3" VerticalAlignment="Center" Margin="5 0 0 0" MinWidth="75" TextAlignment="Right">
<Run Text="{CompiledBinding TotalCount}"/>
<Run Text="total"/>
</TextBlock>
</Grid>
</UserControl>
@@ -0,0 +1,13 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace Artemis.UI.Screens.Workshop.Entries;
public partial class EntryListInputView : UserControl
{
public EntryListInputView()
{
InitializeComponent();
}
}
@@ -0,0 +1,73 @@
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.Shared;
using ReactiveUI;
namespace Artemis.UI.Screens.Workshop.Entries;
public class EntryListInputViewModel : ViewModelBase
{
private static string? _lastSearch;
private readonly PluginSetting<int> _entriesPerPage;
private readonly PluginSetting<int> _sortBy;
private string? _search;
private string _searchWatermark = "Search";
private int _totalCount;
public EntryListInputViewModel(ISettingsService settingsService)
{
_search = _lastSearch;
_entriesPerPage = settingsService.GetSetting("Workshop.EntriesPerPage", 10);
_sortBy = settingsService.GetSetting("Workshop.SortBy", 10);
_entriesPerPage.AutoSave = true;
_sortBy.AutoSave = true;
}
public string SearchWatermark
{
get => _searchWatermark;
set => RaiseAndSetIfChanged(ref _searchWatermark, value);
}
public string? Search
{
get => _search;
set
{
RaiseAndSetIfChanged(ref _search, value);
_lastSearch = value;
}
}
public int EntriesPerPage
{
get => _entriesPerPage.Value;
set
{
_entriesPerPage.Value = value;
this.RaisePropertyChanged();
}
}
public int SortBy
{
get => _sortBy.Value;
set
{
_sortBy.Value = value;
this.RaisePropertyChanged();
}
}
public int TotalCount
{
get => _totalCount;
set => RaiseAndSetIfChanged(ref _totalCount, value);
}
public void ClearLastSearch()
{
_lastSearch = null;
}
}
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Reactive.Disposables;
using System.Reactive.Linq;
@@ -6,7 +7,6 @@ using System.Threading;
using System.Threading.Tasks;
using Artemis.UI.Screens.Workshop.Categories;
using Artemis.UI.Screens.Workshop.Parameters;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Routing;
using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.Builders;
@@ -20,26 +20,33 @@ namespace Artemis.UI.Screens.Workshop.Entries;
public abstract class EntryListViewModel : RoutableScreen<WorkshopListParameters>
{
private readonly INotificationService _notificationService;
private readonly IWorkshopClient _workshopClient;
private readonly ObservableAsPropertyHelper<bool> _showPagination;
private readonly ObservableAsPropertyHelper<bool> _isLoading;
private readonly SourceList<IGetEntries_Entries_Items> _entries = new();
private int _page;
private readonly ObservableAsPropertyHelper<bool> _isLoading;
private readonly INotificationService _notificationService;
private readonly string _route;
private readonly ObservableAsPropertyHelper<bool> _showPagination;
private readonly IWorkshopClient _workshopClient;
private int _loadedPage = -1;
private int _totalPages = 1;
private int _entriesPerPage = 10;
protected EntryListViewModel(IWorkshopClient workshopClient, IRouter router, CategoriesViewModel categoriesViewModel, INotificationService notificationService,
private int _page;
private int _totalPages = 1;
protected EntryListViewModel(string route,
IWorkshopClient workshopClient,
IRouter router,
CategoriesViewModel categoriesViewModel,
EntryListInputViewModel entryListInputViewModel,
INotificationService notificationService,
Func<IGetEntries_Entries_Items, EntryListItemViewModel> getEntryListViewModel)
{
_route = route;
_workshopClient = workshopClient;
_notificationService = notificationService;
_showPagination = this.WhenAnyValue(vm => vm.TotalPages).Select(t => t > 1).ToProperty(this, vm => vm.ShowPagination);
_isLoading = this.WhenAnyValue(vm => vm.Page, vm => vm.LoadedPage, (p, c) => p != c).ToProperty(this, vm => vm.IsLoading);
CategoriesViewModel = categoriesViewModel;
InputViewModel = entryListInputViewModel;
_entries.Connect()
.ObserveOn(new AvaloniaSynchronizationContext(DispatcherPriority.SystemIdle))
@@ -49,26 +56,22 @@ public abstract class EntryListViewModel : RoutableScreen<WorkshopListParameters
Entries = entries;
// Respond to page changes
this.WhenAnyValue(vm => vm.Page).Skip(1).Subscribe(p => Task.Run(() => router.Navigate(GetPagePath(p))));
this.WhenAnyValue(vm => vm.Page).Skip(1).Subscribe(p => Task.Run(() => router.Navigate($"{_route}/{p}")));
// Respond to filter changes
this.WhenActivated(d => CategoriesViewModel.WhenAnyValue(vm => vm.CategoryFilters).Skip(1).Subscribe(_ =>
this.WhenActivated(d =>
{
// Reset to page one, will trigger a query
if (Page != 1)
Page = 1;
// If already at page one, force a query
else
Task.Run(() => Query(CancellationToken.None));
}).DisposeWith(d));
// Respond to filter query input changes
InputViewModel.WhenAnyValue(vm => vm.Search).Skip(1).Throttle(TimeSpan.FromMilliseconds(200)).Subscribe(_ => RefreshToStart()).DisposeWith(d);
InputViewModel.WhenAnyValue(vm => vm.SortBy, vm => vm.EntriesPerPage).Skip(1).Subscribe(_ => RefreshToStart()).DisposeWith(d);
CategoriesViewModel.WhenAnyValue(vm => vm.CategoryFilters).Skip(1).Subscribe(_ => RefreshToStart()).DisposeWith(d);
});
}
protected abstract string GetPagePath(int page);
public bool ShowPagination => _showPagination.Value;
public bool IsLoading => _isLoading.Value;
public CategoriesViewModel CategoriesViewModel { get; }
public EntryListInputViewModel InputViewModel { get; }
public ReadOnlyObservableCollection<EntryListItemViewModel> Entries { get; }
@@ -84,18 +87,13 @@ public abstract class EntryListViewModel : RoutableScreen<WorkshopListParameters
set => RaiseAndSetIfChanged(ref _loadedPage, value);
}
public int TotalPages
{
get => _totalPages;
set => RaiseAndSetIfChanged(ref _totalPages, value);
}
public int EntriesPerPage
{
get => _entriesPerPage;
set => RaiseAndSetIfChanged(ref _entriesPerPage, value);
}
public override async Task OnNavigating(WorkshopListParameters parameters, NavigationArguments args, CancellationToken cancellationToken)
{
Page = Math.Max(1, parameters.Page);
@@ -105,17 +103,70 @@ public abstract class EntryListViewModel : RoutableScreen<WorkshopListParameters
await Query(cancellationToken);
}
public override Task OnClosing(NavigationArguments args)
{
// Clear search if not navigating to a child
if (!args.Path.StartsWith(_route))
InputViewModel.ClearLastSearch();
return base.OnClosing(args);
}
protected virtual EntryFilterInput GetFilter()
{
return new EntryFilterInput {And = CategoriesViewModel.CategoryFilters};
}
protected virtual IReadOnlyList<EntrySortInput> GetSort()
{
// Sort by created at
if (InputViewModel.SortBy == 1)
return new[] {new EntrySortInput {CreatedAt = SortEnumType.Desc}};
// Sort by downloads
if (InputViewModel.SortBy == 2)
return new[] {new EntrySortInput {Downloads = SortEnumType.Desc}};
// Sort by latest release, then by created at
return new[]
{
new EntrySortInput {LatestRelease = new ReleaseSortInput {CreatedAt = SortEnumType.Desc}},
new EntrySortInput {CreatedAt = SortEnumType.Desc}
};
}
private void RefreshToStart()
{
// Reset to page one, will trigger a query
if (Page != 1)
Page = 1;
// If already at page one, force a query
else
Task.Run(() => Query(CancellationToken.None));
}
private async Task Query(CancellationToken cancellationToken)
{
try
{
string? search = string.IsNullOrWhiteSpace(InputViewModel.Search) ? null : InputViewModel.Search;
EntryFilterInput filter = GetFilter();
IOperationResult<IGetEntriesResult> entries = await _workshopClient.GetEntries.ExecuteAsync(filter, EntriesPerPage * (Page - 1), EntriesPerPage, cancellationToken);
IReadOnlyList<EntrySortInput> sort = GetSort();
IOperationResult<IGetEntriesResult> entries = await _workshopClient.GetEntries.ExecuteAsync(
search,
filter,
InputViewModel.EntriesPerPage * (Page - 1),
InputViewModel.EntriesPerPage,
sort,
cancellationToken
);
entries.EnsureNoErrors();
if (entries.Data?.Entries?.Items != null)
{
TotalPages = (int) Math.Ceiling(entries.Data.Entries.TotalCount / (double) EntriesPerPage);
TotalPages = (int) Math.Ceiling(entries.Data.Entries.TotalCount / (double) InputViewModel.EntriesPerPage);
InputViewModel.TotalCount = entries.Data.Entries.TotalCount;
_entries.Edit(e =>
{
e.Clear();
@@ -123,7 +174,9 @@ public abstract class EntryListViewModel : RoutableScreen<WorkshopListParameters
});
}
else
{
TotalPages = 1;
}
}
catch (Exception e)
{
@@ -138,9 +191,4 @@ public abstract class EntryListViewModel : RoutableScreen<WorkshopListParameters
LoadedPage = Page;
}
}
protected virtual EntryFilterInput GetFilter()
{
return new EntryFilterInput {And = CategoriesViewModel.CategoryFilters};
}
}
@@ -2,14 +2,21 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:layout="clr-namespace:Artemis.UI.Screens.Workshop.Layout"
xmlns:pagination="clr-namespace:Artemis.UI.Shared.Pagination;assembly=Artemis.UI.Shared"
xmlns:tabs="clr-namespace:Artemis.UI.Screens.Workshop.Entries.Tabs"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.Workshop.Entries.Tabs.LayoutListView"
x:DataType="tabs:LayoutListViewModel">
<Grid ColumnDefinitions="300,*" RowDefinitions="*,Auto">
<StackPanel Grid.Column="0" Grid.RowSpan="2" Margin="0 0 10 0" VerticalAlignment="Top">
<UserControl.Styles>
<Styles>
<Style Selector="StackPanel.empty-state > TextBlock">
<Setter Property="TextAlignment" Value="Center"></Setter>
<Setter Property="TextWrapping" Value="Wrap"></Setter>
</Style>
</Styles>
</UserControl.Styles>
<Grid ColumnDefinitions="300,*" RowDefinitions="Auto,*,Auto">
<StackPanel Grid.Column="0" Grid.RowSpan="3" Margin="0 0 10 0" VerticalAlignment="Top">
<Border Classes="card" VerticalAlignment="Stretch">
<StackPanel>
<TextBlock Theme="{StaticResource SubtitleTextBlockStyle}">Categories</TextBlock>
@@ -20,18 +27,35 @@
</StackPanel>
<ProgressBar Grid.Column="1" Grid.Row="0" VerticalAlignment="Top" Margin="0 0 20 0" IsVisible="{CompiledBinding IsLoading}" IsIndeterminate="True" />
<ScrollViewer Grid.Column="1" Grid.Row="0">
<ItemsRepeater ItemsSource="{CompiledBinding Entries}" Margin="0 0 20 0">
<ItemsRepeater.ItemTemplate>
<ContentControl Grid.Column="1" Grid.Row="0" Margin="0 0 20 8" Content="{CompiledBinding InputViewModel}"/>
<ScrollViewer Grid.Column="1" Grid.Row="1">
<ItemsControl ItemsSource="{CompiledBinding Entries}" Margin="0 0 20 0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentControl Content="{CompiledBinding}" Margin="0 0 0 5"></ContentControl>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
<Panel Grid.Column="1" Grid.Row="1" IsVisible="{CompiledBinding !IsLoading}">
<StackPanel IsVisible="{CompiledBinding !Entries.Count}" Margin="0 50 0 0" Classes="empty-state">
<TextBlock Theme="{StaticResource TitleTextBlockStyle}">Looks like your current filters gave no results</TextBlock>
<TextBlock>
<Run>Modify or clear your filters to view other device layouts</Run>
</TextBlock>
<Lottie Path="/Assets/Animations/empty.json" RepeatCount="1" Width="350" Height="350"></Lottie>
</StackPanel>
</Panel>
<pagination:Pagination Grid.Column="1"
Grid.Row="1"
Grid.Row="2"
Margin="0 20 0 10"
IsVisible="{CompiledBinding ShowPagination}"
Value="{CompiledBinding Page}"
@@ -8,36 +8,26 @@ namespace Artemis.UI.Screens.Workshop.Entries.Tabs;
public class LayoutListViewModel : EntryListViewModel
{
/// <inheritdoc />
public LayoutListViewModel(IWorkshopClient workshopClient,
IRouter router,
CategoriesViewModel categoriesViewModel,
EntryListInputViewModel entryListInputViewModel,
INotificationService notificationService,
Func<IGetEntries_Entries_Items, EntryListItemViewModel> getEntryListViewModel)
: base(workshopClient, router, categoriesViewModel, notificationService, getEntryListViewModel)
: base("workshop/entries/layout", workshopClient, router, categoriesViewModel, entryListInputViewModel, notificationService, getEntryListViewModel)
{
entryListInputViewModel.SearchWatermark = "Search layouts";
}
#region Overrides of EntryListBaseViewModel
/// <inheritdoc />
protected override string GetPagePath(int page)
{
return $"workshop/entries/layouts/{page}";
}
/// <inheritdoc />
protected override EntryFilterInput GetFilter()
{
return new EntryFilterInput
{
And = new[]
{
new EntryFilterInput {EntryType = new EntryTypeOperationFilterInput {Eq = WebClient.Workshop.EntryType.Layout}},
new EntryFilterInput {EntryType = new EntryTypeOperationFilterInput {Eq = EntryType.Layout}},
base.GetFilter()
}
};
}
#endregion
}
@@ -2,14 +2,21 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:profile="clr-namespace:Artemis.UI.Screens.Workshop.Profile"
xmlns:pagination="clr-namespace:Artemis.UI.Shared.Pagination;assembly=Artemis.UI.Shared"
xmlns:tabs="clr-namespace:Artemis.UI.Screens.Workshop.Entries.Tabs"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
mc:Ignorable="d" d:DesignWidth="1200" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.Workshop.Entries.Tabs.ProfileListView"
x:DataType="tabs:ProfileListViewModel">
<Grid ColumnDefinitions="300,*" RowDefinitions="*,Auto">
<StackPanel Grid.Column="0" Grid.RowSpan="2" Margin="0 0 10 0" VerticalAlignment="Top">
<UserControl.Styles>
<Styles>
<Style Selector="StackPanel.empty-state > TextBlock">
<Setter Property="TextAlignment" Value="Center"></Setter>
<Setter Property="TextWrapping" Value="Wrap"></Setter>
</Style>
</Styles>
</UserControl.Styles>
<Grid ColumnDefinitions="300,*" RowDefinitions="Auto,*,Auto">
<StackPanel Grid.Column="0" Grid.RowSpan="3" Margin="0 0 10 0" VerticalAlignment="Top">
<Border Classes="card" VerticalAlignment="Stretch">
<StackPanel>
<TextBlock Theme="{StaticResource SubtitleTextBlockStyle}">Categories</TextBlock>
@@ -20,19 +27,35 @@
</StackPanel>
<ProgressBar Grid.Column="1" Grid.Row="0" VerticalAlignment="Top" Margin="0 0 20 0" IsVisible="{CompiledBinding IsLoading}" IsIndeterminate="True" />
<ScrollViewer Grid.Column="1" Grid.Row="0">
<ItemsRepeater ItemsSource="{CompiledBinding Entries}" Margin="0 0 20 0">
<ItemsRepeater.ItemTemplate>
<ContentControl Grid.Column="1" Grid.Row="0" Margin="0 0 20 8" Content="{CompiledBinding InputViewModel}"/>
<ScrollViewer Grid.Column="1" Grid.Row="1">
<ItemsControl ItemsSource="{CompiledBinding Entries}" Margin="0 0 20 0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentControl Content="{CompiledBinding}" Margin="0 0 0 5"></ContentControl>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
<Panel Grid.Column="1" Grid.Row="1" IsVisible="{CompiledBinding !IsLoading}">
<StackPanel IsVisible="{CompiledBinding !Entries.Count}" Margin="0 50 0 0" Classes="empty-state">
<TextBlock Theme="{StaticResource TitleTextBlockStyle}">Looks like your current filters gave no results</TextBlock>
<TextBlock>
<Run>Modify or clear your filters to view some awesome profiles</Run>
</TextBlock>
<Lottie Path="/Assets/Animations/empty.json" RepeatCount="1" Width="350" Height="350"></Lottie>
</StackPanel>
</Panel>
<pagination:Pagination Grid.Column="1"
Grid.Row="1"
Grid.Row="2"
Margin="0 20 0 10"
IsVisible="{CompiledBinding ShowPagination}"
Value="{CompiledBinding Page}"
@@ -8,36 +8,26 @@ namespace Artemis.UI.Screens.Workshop.Entries.Tabs;
public class ProfileListViewModel : EntryListViewModel
{
/// <inheritdoc />
public ProfileListViewModel(IWorkshopClient workshopClient,
IRouter router,
CategoriesViewModel categoriesViewModel,
EntryListInputViewModel entryListInputViewModel,
INotificationService notificationService,
Func<IGetEntries_Entries_Items, EntryListItemViewModel> getEntryListViewModel)
: base(workshopClient, router, categoriesViewModel, notificationService, getEntryListViewModel)
: base("workshop/entries/profiles", workshopClient, router, categoriesViewModel, entryListInputViewModel, notificationService, getEntryListViewModel)
{
entryListInputViewModel.SearchWatermark = "Search profiles";
}
#region Overrides of EntryListBaseViewModel
/// <inheritdoc />
protected override string GetPagePath(int page)
{
return $"workshop/entries/profiles/{page}";
}
/// <inheritdoc />
protected override EntryFilterInput GetFilter()
{
return new EntryFilterInput
{
And = new[]
{
new EntryFilterInput {EntryType = new EntryTypeOperationFilterInput {Eq = WebClient.Workshop.EntryType.Profile}},
new EntryFilterInput {EntryType = new EntryTypeOperationFilterInput {Eq = EntryType.Profile}},
base.GetFilter()
}
};
}
#endregion
}
@@ -3,7 +3,6 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:search="clr-namespace:Artemis.UI.Screens.Workshop.Search"
xmlns:workshop="clr-namespace:Artemis.WebClient.Workshop;assembly=Artemis.WebClient.Workshop"
xmlns:windowing="clr-namespace:FluentAvalonia.UI.Windowing;assembly=FluentAvalonia"
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
@@ -1,4 +1,6 @@
using Artemis.UI.Screens.Workshop.Home;
using System.Threading;
using System.Threading.Tasks;
using Artemis.UI.Screens.Workshop.Home;
using Artemis.UI.Screens.Workshop.Search;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Routing;
@@ -7,12 +9,27 @@ namespace Artemis.UI.Screens.Workshop;
public class WorkshopViewModel : RoutableHostScreen<RoutableScreen>, IMainScreenViewModel
{
private readonly SearchViewModel _searchViewModel;
private ViewModelBase? _titleBarViewModel;
public WorkshopViewModel(SearchViewModel searchViewModel, WorkshopHomeViewModel homeViewModel)
{
TitleBarViewModel = searchViewModel;
_searchViewModel = searchViewModel;
HomeViewModel = homeViewModel;
}
public ViewModelBase TitleBarViewModel { get; }
public WorkshopHomeViewModel HomeViewModel { get; }
/// <inheritdoc />
public override Task OnNavigating(NavigationArguments args, CancellationToken cancellationToken)
{
TitleBarViewModel = args.Path == "workshop" ? _searchViewModel : null;
return base.OnNavigating(args, cancellationToken);
}
public ViewModelBase? TitleBarViewModel
{
get => _titleBarViewModel;
set => RaiseAndSetIfChanged(ref _titleBarViewModel, value);
}
}