Bunch of insane work

This commit is contained in:
TheXamlGuy
2024-02-08 22:16:58 +00:00
parent 28d79f77d0
commit 2aeb4d1b54
58 changed files with 547 additions and 326 deletions
@@ -1,15 +0,0 @@
using Microsoft.UI.Xaml.Controls;
namespace Hyperbar.UI.Windows;
public class DataTemplateConverter :
ValueConverter<object, DataTemplateSelector>
{
protected override DataTemplateSelector? ConvertTo(object value,
Type? targetType,
object? parameter,
string? language)
{
return new TemplateGenerator();
}
}
-23
View File
@@ -1,23 +0,0 @@
using Microsoft.Extensions.DependencyInjection;
namespace Hyperbar.UI.Windows;
public class TemplateFactory(IEnumerable<IContentTemplateDescriptor> descriptors,
IServiceProvider provider) :
ITemplateFactory
{
public object? Create(object key)
{
if (descriptors.FirstOrDefault(x => x.Key == key)
is IContentTemplateDescriptor descriptor)
{
if (provider.GetRequiredKeyedService(descriptor.TemplateType,
descriptor.Key) is { } template)
{
return template;
}
}
return default;
}
}
-36
View File
@@ -1,36 +0,0 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Markup;
namespace Hyperbar.UI.Windows;
public class TemplateGenerator : DataTemplateSelector
{
protected override DataTemplate SelectTemplateCore(object item)
{
string xamlString = @"
<DataTemplate xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
xmlns:ui=""using:Hyperbar.UI.Windows"">
<ui:TemplateGeneratorControl VerticalContentAlignment=""Stretch""
HorizontalContentAlignment=""Stretch""
HorizontalAlignment=""Stretch""
VerticalAlignment=""Stretch""/>
</DataTemplate>";
return (DataTemplate)XamlReader.Load(xamlString);
}
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
string xamlString = @"
<DataTemplate xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
xmlns:ui=""using:Hyperbar.UI.Windows"">
<ui:TemplateGeneratorControl VerticalContentAlignment=""Stretch""
HorizontalContentAlignment=""Stretch""
HorizontalAlignment=""Stretch""
VerticalAlignment=""Stretch""/>
</DataTemplate>";
return (DataTemplate)XamlReader.Load(xamlString);
}
}
@@ -1,22 +0,0 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
namespace Hyperbar.UI.Windows;
public class TemplateGeneratorControl :
ContentControl
{
public TemplateGeneratorControl()
{
DataContextChanged += OnDataContextChanged;
}
private void OnDataContextChanged(FrameworkElement sender,
DataContextChangedEventArgs args)
{
if (DataContext is ITemplatedViewModel templatedViewModel)
{
Content = templatedViewModel.TemplateFactory.Create(DataContext.GetType().Name);
}
}
}
@@ -0,0 +1,23 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
namespace Hyperbar.UI.Windows;
public class ViewModelTemplatePresenter :
ContentPresenter
{
public ViewModelTemplatePresenter()
{
DataContextChanged += OnDataContextChanged;
}
private void OnDataContextChanged(FrameworkElement sender,
DataContextChangedEventArgs args)
{
//if (DataContext is IViewModelTemplate templatedViewModel)
//{
// Content = templatedViewModel.TemplateFactory
// .Create(DataContext.GetType().Name);
//}
}
}
@@ -0,0 +1,92 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Markup;
namespace Hyperbar.UI.Windows;
public class ImplicitTemplate :
MarkupExtension
{
protected override object ProvideValue(IXamlServiceProvider serviceProvider) =>
new ImplicitTemplateSelector();
internal class ImplicitTemplateSelector :
DataTemplateSelector
{
protected override DataTemplate SelectTemplateCore(object item,
DependencyObject container)
{
string xamlString = @"
<DataTemplate xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
xmlns:ui=""using:Hyperbar.UI.Windows"">
<ui:ViewModelTemplatePresenter VerticalContentAlignment=""Stretch""
HorizontalContentAlignment=""Stretch""
HorizontalAlignment=""Stretch""
VerticalAlignment=""Stretch""/>
</DataTemplate>";
return (DataTemplate)XamlReader.Load(xamlString);
}
}
}
public class ViewModelTemplate :
MarkupExtension
{
protected override object ProvideValue(IXamlServiceProvider serviceProvider) =>
new ViewModelTemplateSelector();
internal class ViewModelTemplateSelector :
DataTemplateSelector
{
protected override DataTemplate SelectTemplateCore(object item)
{
if (item is IObservableViewModel observableViewModel)
{
if (observableViewModel.ServiceProvider.GetService<IViewModelTemplateDescriptorProvider>()
is ViewModelTemplateDescriptorProvider descriptors)
{
if (descriptors.Get(item.GetType().Name) is IViewModelTemplateDescriptor descriptor)
{
string xamlString = @$"
<DataTemplate xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
xmlns:ui=""using:{descriptor.TemplateType.Namespace}"">
<ui:{descriptor.TemplateType.Name} />
</DataTemplate>";
return (DataTemplate)XamlReader.Load(xamlString);
}
}
}
return new DataTemplate();
}
protected override DataTemplate SelectTemplateCore(object item,
DependencyObject container)
{
if (item is IObservableViewModel observableViewModel)
{
if (observableViewModel.ServiceProvider.GetService<IViewModelTemplateDescriptorProvider>()
is ViewModelTemplateDescriptorProvider descriptors)
{
if (descriptors.Get(item.GetType().Name) is IViewModelTemplateDescriptor descriptor)
{
string xamlString = @$"
<DataTemplate xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
xmlns:ui=""using:{descriptor.TemplateType.Namespace}"">
<ui:{descriptor.TemplateType.Name} />
</DataTemplate>";
return (DataTemplate)XamlReader.Load(xamlString);
}
}
}
return new DataTemplate();
}
}
}
+16
View File
@@ -1,11 +1,17 @@
using Hyperbar.Interop.Windows;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Windows.Graphics;
using WinRT.Interop;
namespace Hyperbar.UI.Windows;
public class NavigationItemTemplateSelector :
DataTemplateSelector
{
}
public static class WindowExtensions
{
public static WindowMessageListener CreateMessageListener(this Window window) =>
@@ -36,6 +42,16 @@ public static class WindowExtensions
public static void SetStyle(this Window window,
ExtendedWindowStyle style) => window.GetHandle().SetExtendedWindowStyle(style);
public static void TitleBarConfiguration(this Window window,
Action<AppWindowTitleBar> titleBarDelegate)
{
AppWindow appWindow = window.AppWindow;
if (appWindow.TitleBar is AppWindowTitleBar titleBar)
{
titleBarDelegate.Invoke(titleBar);
}
}
public static void SetTopMost(this Window window,
bool value)
{
@@ -1,13 +1,12 @@
namespace Hyperbar.Widget.Contextual.Windows;
public class ContextualWidgetViewModel(ITemplateFactory templateFactory,
public class ContextualWidgetViewModel(IViewModelTemplateFactory templateFactory,
IServiceFactory serviceFactory,
IMediator mediator,
IDisposer disposer,
IEnumerable<IWidgetComponentViewModel> items) :
ObservableCollectionViewModel<IWidgetComponentViewModel>(serviceFactory, mediator, disposer, items),
IWidgetViewModel,
ITemplatedViewModel
IWidgetViewModel
{
public ITemplateFactory TemplateFactory => templateFactory;
public IViewModelTemplateFactory TemplateFactory => templateFactory;
}
@@ -3,12 +3,13 @@ using CommunityToolkit.Mvvm.Input;
namespace Hyperbar.Widget.MediaController.Windows;
public partial class MediaButtonViewModel<TMediaButton>(IServiceFactory serviceFactory,
public partial class MediaButtonViewModel<TMediaButton>(IServiceProvider serviceProvider,
IServiceFactory serviceFactory,
IMediator mediator,
IDisposer disposer,
ITemplateFactory templateFactory,
IViewModelTemplateFactory templateFactory,
IRelayCommand invokeCommand) :
WidgetComponentViewModel(serviceFactory, mediator, disposer, templateFactory),
WidgetComponentViewModel(serviceProvider, serviceFactory, mediator, disposer, templateFactory),
INotificationHandler<Changed<MediaButton<TMediaButton>>>,
IMediaButtonViewModel
{
@@ -3,18 +3,16 @@
x:Class="Hyperbar.Widget.MediaController.Windows.MediaControllerView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:windows="using:Hyperbar.UI.Windows">
<Grid>
<ItemsControl
HorizontalAlignment="Right"
HorizontalContentAlignment="Right"
ItemTemplateSelector="{Binding Converter={windows:DataTemplateConverter}}"
ItemsSource="{x:Bind ViewModel}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Spacing="8" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
xmlns:ui="using:Hyperbar.UI.Windows">
<ItemsControl
HorizontalAlignment="Right"
HorizontalContentAlignment="Right"
ItemTemplateSelector="{ui:ViewModelTemplate}"
ItemsSource="{x:Bind ViewModel}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Spacing="8" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</UserControl>
@@ -2,17 +2,15 @@
namespace Hyperbar.Widget.MediaController.Windows;
[NotificationHandler(nameof(MediaControllerViewModel))]
public class MediaControllerViewModel :
ObservableCollectionViewModel<WidgetComponentViewModel>,
ITemplatedViewModel
ObservableCollectionViewModel<WidgetComponentViewModel>
{
public MediaControllerViewModel(ITemplateFactory templateFactory,
public MediaControllerViewModel(IViewModelTemplateFactory templateFactory,
IServiceProvider serviceProvider,
IServiceFactory serviceFactory,
IMediator mediator,
IDisposer disposer) : base(serviceFactory, mediator, disposer)
IDisposer disposer) : base(serviceProvider, serviceFactory, mediator, disposer)
{
TemplateFactory = templateFactory;
@@ -28,5 +26,5 @@ public class MediaControllerViewModel :
await mediator.PublishAsync<Request<MediaNext>>()));
}
public ITemplateFactory TemplateFactory { get; set; }
public IViewModelTemplateFactory TemplateFactory { get; set; }
}
@@ -3,9 +3,9 @@
x:Class="Hyperbar.Widget.MediaController.Windows.MediaControllerWidgetView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:windows="using:Hyperbar.UI.Windows">
xmlns:ui="using:Hyperbar.UI.Windows">
<FlipView
Width="360"
ItemTemplateSelector="{Binding Converter={windows:DataTemplateConverter}}"
ItemTemplateSelector="{ui:ViewModelTemplate}"
ItemsSource="{Binding}" />
</UserControl>
@@ -1,15 +1,13 @@
using Hyperbar.Widget;
namespace Hyperbar.Widget.MediaController.Windows;
namespace Hyperbar.Widget.MediaController.Windows;
public class MediaControllerWidgetViewModel(ITemplateFactory templateFactory,
public class MediaControllerWidgetViewModel(IViewModelTemplateFactory templateFactory,
IServiceProvider serviceProvider,
IServiceFactory serviceFactory,
IMediator mediator,
IDisposer disposer,
IEnumerable<MediaControllerViewModel> items) :
ObservableCollectionViewModel<MediaControllerViewModel>(serviceFactory, mediator, disposer, items),
IWidgetViewModel,
ITemplatedViewModel
ObservableCollectionViewModel<MediaControllerViewModel>(serviceProvider, serviceFactory, mediator, disposer, items),
IWidgetViewModel
{
public ITemplateFactory TemplateFactory => templateFactory;
public IViewModelTemplateFactory TemplateFactory => templateFactory;
}
@@ -2,11 +2,12 @@
namespace Hyperbar.Widget.MediaController.Windows;
public partial class MediaInformationViewModel(IServiceFactory serviceFactory,
public partial class MediaInformationViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory,
IMediator mediator,
IDisposer disposer,
ITemplateFactory templateFactory) :
WidgetComponentViewModel(serviceFactory, mediator, disposer, templateFactory),
IViewModelTemplateFactory templateFactory) :
WidgetComponentViewModel(serviceProvider, serviceFactory, mediator, disposer, templateFactory),
INotificationHandler<Changed<MediaInformation>>
{
[ObservableProperty]
@@ -3,13 +3,13 @@
namespace Hyperbar.Widget.Primary.Windows;
[NotificationHandler(nameof(PrimaryWidgetViewModel))]
public class PrimaryWidgetViewModel(ITemplateFactory templateFactory,
public class PrimaryWidgetViewModel(IViewModelTemplateFactory templateFactory,
IServiceProvider serviceProvider,
IServiceFactory serviceFactory,
IMediator mediator,
IDisposer disposer) :
ObservableCollectionViewModel<IWidgetComponentViewModel>(serviceFactory, mediator, disposer),
IWidgetViewModel,
ITemplatedViewModel
ObservableCollectionViewModel<IWidgetComponentViewModel>(serviceProvider, serviceFactory, mediator, disposer),
IWidgetViewModel
{
public ITemplateFactory TemplateFactory => templateFactory;
public IViewModelTemplateFactory TemplateFactory => templateFactory;
}
@@ -1,5 +1,4 @@
using CommunityToolkit.Mvvm.Input;
using Hyperbar.Widget;
namespace Hyperbar.Widget.Primary.Windows;
@@ -19,7 +19,8 @@ public static class IServiceCollectionExtensions
services.AddSingleton(provider.GetRequiredService<IList<IXamlMetadataProvider>>());
services.AddSingleton(provider.GetRequiredService<IDispatcher>());
services.AddTransient<ITemplateFactory, TemplateFactory>();
services.AddTransient<IViewModelTemplateDescriptorProvider, ViewModelTemplateDescriptorProvider>();
services.AddTransient<IViewModelTemplateFactory, ViewModelTemplateFactory>();
services.AddScoped<IVirtualKeyboard, VirtualKeyboard>();
services.AddHandler<KeyAcceleratorHandler>();
+2 -2
View File
@@ -5,9 +5,9 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:interactions="using:Microsoft.Xaml.Interactions.Core"
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
xmlns:windows="using:Hyperbar.UI.Windows">
xmlns:ui="using:Hyperbar.UI.Windows">
<Grid>
<ItemsControl ItemTemplateSelector="{Binding Converter={windows:DataTemplateConverter}}" ItemsSource="{Binding Mode=TwoWay}">
<ItemsControl ItemTemplateSelector="{ui:ViewModelTemplate}" ItemsSource="{Binding Mode=TwoWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Spacing="8" />
@@ -33,7 +33,7 @@ public static class IServiceCollectionExtensions
services.AddKeyedTransient(typeof(IWidgetViewModel), key, contentType);
services.TryAddKeyedTransient(key, (provider, key) => provider.GetService<IWidgetView>()!);
services.AddTransient<IContentTemplateDescriptor>(provider => new ContentTemplateDescriptor { ContentType = contentType, TemplateType = templateType, Key = key });
services.AddTransient<IViewModelTemplateDescriptor>(provider => new ViewModelTemplateDescriptor { ViewModelType = contentType, TemplateType = templateType, Key = key });
return services;
}
@@ -54,8 +54,8 @@ public static class IServiceCollectionExtensions
services.AddKeyedTransient(typeof(IWidgetViewModel), key, contentType);
services.TryAddKeyedTransient(templateType, key);
services.AddTransient<IContentTemplateDescriptor>(provider =>
new ContentTemplateDescriptor { ContentType = contentType,
services.AddTransient<IViewModelTemplateDescriptor>(provider =>
new ViewModelTemplateDescriptor { ViewModelType = contentType,
TemplateType = templateType, Key = key });
return services;
+4 -3
View File
@@ -4,14 +4,15 @@ using CommunityToolkit.Mvvm.Input;
namespace Hyperbar.Widget;
[NotificationHandler(nameof(Id))]
public partial class WidgetButtonViewModel(IServiceFactory serviceFactory,
public partial class WidgetButtonViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory,
IMediator mediator,
IDisposer disposer,
ITemplateFactory templateFactory,
IViewModelTemplateFactory templateFactory,
Guid id,
string? text = null,
string? icon = null,
RelayCommand? invokeCommand = null) : WidgetComponentViewModel(serviceFactory, mediator, disposer, templateFactory)
RelayCommand? invokeCommand = null) : WidgetComponentViewModel(serviceProvider, serviceFactory, mediator, disposer, templateFactory)
{
[ObservableProperty]
private string? icon = icon;
+9 -8
View File
@@ -2,25 +2,26 @@
public partial class WidgetComponentViewModel :
ObservableCollectionViewModel<IWidgetComponentViewModel>,
IWidgetComponentViewModel,
ITemplatedViewModel
IWidgetComponentViewModel
{
public WidgetComponentViewModel(IServiceFactory serviceFactory,
public WidgetComponentViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory,
IMediator mediator,
IDisposer disposer,
ITemplateFactory templateFactory,
IEnumerable<IWidgetComponentViewModel> items) : base(serviceFactory, mediator, disposer, items)
IViewModelTemplateFactory templateFactory,
IEnumerable<IWidgetComponentViewModel> items) : base(serviceProvider, serviceFactory, mediator, disposer, items)
{
TemplateFactory = templateFactory;
}
public WidgetComponentViewModel(IServiceFactory serviceFactory,
public WidgetComponentViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory,
IMediator mediator,
IDisposer disposer,
ITemplateFactory templateFactory) : base(serviceFactory, mediator, disposer)
IViewModelTemplateFactory templateFactory) : base(serviceProvider, serviceFactory, mediator, disposer)
{
TemplateFactory = templateFactory;
}
public ITemplateFactory TemplateFactory { get; private set; }
public IViewModelTemplateFactory TemplateFactory { get; private set; }
}
+4 -3
View File
@@ -4,14 +4,15 @@ using CommunityToolkit.Mvvm.Input;
namespace Hyperbar.Widget;
[NotificationHandler(nameof(Id))]
public partial class WidgetMenuViewModel(IServiceFactory serviceFactory,
public partial class WidgetMenuViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory,
IMediator mediator,
IDisposer disposer,
ITemplateFactory templateFactory,
IViewModelTemplateFactory templateFactory,
Guid id = default,
string? text = null,
string? icon = null,
RelayCommand? command = null) : WidgetComponentViewModel(serviceFactory, mediator, disposer, templateFactory)
RelayCommand? command = null) : WidgetComponentViewModel(serviceProvider, serviceFactory, mediator, disposer, templateFactory)
{
[ObservableProperty]
private IRelayCommand? click = command;
@@ -4,15 +4,16 @@ using CommunityToolkit.Mvvm.Input;
namespace Hyperbar.Widget;
[NotificationHandler(nameof(Id))]
public partial class WidgetSplitButtonViewModel(IServiceFactory serviceFactory,
public partial class WidgetSplitButtonViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory,
IMediator mediator,
IDisposer disposer,
ITemplateFactory templateFactory,
IViewModelTemplateFactory templateFactory,
IEnumerable<IWidgetComponentViewModel> items,
Guid id = default,
string? text = null,
string? icon = null,
RelayCommand? command = null) : WidgetComponentViewModel(serviceFactory, mediator, disposer, templateFactory, items)
RelayCommand? command = null) : WidgetComponentViewModel(serviceProvider, serviceFactory, mediator, disposer, templateFactory, items)
{
[ObservableProperty]
private IRelayCommand? click = command;
+1 -1
View File
@@ -10,7 +10,7 @@
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
</ResourceDictionary.MergedDictionaries>
<DataTemplate x:Key="DefaultDataTemplate">
<ui:TemplateGeneratorControl />
<ui:ViewModelTemplatePresenter />
</DataTemplate>
</ResourceDictionary>
</Application.Resources>
+6 -1
View File
@@ -37,7 +37,9 @@ public partial class App :
services.AddHostedService<AppService>();
services.AddSingleton<IDispatcher>(new Dispatcher(DispatcherQueue.GetForCurrentThread()));
services.AddTransient<ITemplateFactory, TemplateFactory>();
services.AddTransient<IViewModelTemplateDescriptorProvider, ViewModelTemplateDescriptorProvider>();
services.AddTransient<IViewModelTemplateFactory, ViewModelTemplateFactory>();
services.AddHandler<AppConfigurationChangedHandler>();
services.AddConfiguration<AppConfiguration>(args =>
@@ -55,6 +57,9 @@ public partial class App :
services.AddContentTemplate<SettingsButtonViewModel, SettingsButtonView>();
services.AddContentTemplate<SettingsViewModel, SettingsView>("Settings");
services.AddContentTemplate<GeneralSettingsNavigationViewModel, GeneralSettingsNavigationView>();
services.AddContentTemplate<WidgetSettingsNavigationViewModel, WidgetSettingsNavigationView>();
services.AddTransient<IInitializer, AppInitializer>();
})
.Build();
+3 -3
View File
@@ -3,7 +3,7 @@
x:Class="Hyperbar.Windows.ApplicationBarView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:windows="using:Hyperbar.UI.Windows">
xmlns:ui="using:Hyperbar.UI.Windows">
<UserControl.Resources>
<SolidColorBrush x:Key="ButtonBackground" Color="Transparent" />
<SolidColorBrush x:Key="ButtonBorderBrush" Color="Transparent" />
@@ -17,7 +17,7 @@
</UserControl.Resources>
<ItemsControl
Margin="6,0,6,0"
ItemTemplateSelector="{Binding Converter={windows:DataTemplateConverter}}"
ItemTemplateSelector="{ui:ViewModelTemplate}"
ItemsSource="{x:Bind ViewModel, Mode=OneWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
@@ -36,7 +36,7 @@
</ItemsControl.ItemContainerTransitions>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="windows:GridExtension.GridColumnBindingPath" Value="Index" />
<Setter Property="ui:GridExtension.GridColumnBindingPath" Value="Index" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
+5 -5
View File
@@ -2,13 +2,13 @@
[NotificationHandler(nameof(IWidgetHostViewModel))]
public partial class ApplicationBarViewModel :
ObservableCollectionViewModel<IDisposable>,
ITemplatedViewModel
ObservableCollectionViewModel<IDisposable>
{
public ApplicationBarViewModel(ITemplateFactory templateFactory,
public ApplicationBarViewModel(IViewModelTemplateFactory templateFactory,
IServiceProvider serviceProvider,
IServiceFactory serviceFactory,
IMediator mediator,
IDisposer disposer) : base(serviceFactory, mediator, disposer)
IDisposer disposer) : base(serviceProvider, serviceFactory, mediator, disposer)
{
TemplateFactory = templateFactory;
@@ -16,5 +16,5 @@ public partial class ApplicationBarViewModel :
Add<SecondaryViewModel>(1);
}
public ITemplateFactory TemplateFactory { get; }
public IViewModelTemplateFactory TemplateFactory { get; }
}
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<NavigationViewItem
x:Class="Hyperbar.Windows.GeneralSettingsNavigationView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Content="General" />
@@ -0,0 +1,10 @@
using Microsoft.UI.Xaml.Controls;
namespace Hyperbar.Windows;
public sealed partial class GeneralSettingsNavigationView :
NavigationViewItem
{
public GeneralSettingsNavigationView() =>
InitializeComponent();
}
@@ -0,0 +1,10 @@
namespace Hyperbar.Windows;
public class GeneralSettingsNavigationViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory,
IMediator mediator,
IDisposer disposer,
string text) :
NavigationViewModel(serviceProvider, serviceFactory, mediator, disposer, text)
{
}
+12
View File
@@ -15,10 +15,12 @@
</PropertyGroup>
<ItemGroup>
<None Remove="ApplicationBarView.xaml" />
<None Remove="GeneralSettingsNavigationView.xaml" />
<None Remove="PrimaryView.xaml" />
<None Remove="SecondaryView.xaml" />
<None Remove="SettingsButtonView.xaml" />
<None Remove="SettingsView.xaml" />
<None Remove="WidgetSettingsNavigationView.xaml" />
</ItemGroup>
<ItemGroup>
<Content Include="Assets\SplashScreen.scale-200.png" />
@@ -55,6 +57,16 @@
<ProjectReference Include="..\Hyperbar.Widget\Hyperbar.Widget.csproj" />
<ProjectReference Include="..\Hyperbar\Hyperbar.csproj" />
</ItemGroup>
<ItemGroup>
<Page Update="GeneralSettingsNavigationView.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="WidgetSettingsNavigationView.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="SettingsView.xaml">
<Generator>MSBuild:Compile</Generator>
+2 -2
View File
@@ -3,10 +3,10 @@
x:Class="Hyperbar.Windows.PrimaryView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:windows="using:Hyperbar.UI.Windows">
xmlns:ui="using:Hyperbar.UI.Windows">
<ItemsControl
HorizontalAlignment="Center"
ItemTemplateSelector="{Binding Converter={windows:DataTemplateConverter}}"
ItemTemplateSelector="{ui:ViewModelTemplate}"
ItemsSource="{x:Bind ViewModel}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
+5 -5
View File
@@ -3,17 +3,17 @@
namespace Hyperbar.Widget;
[NotificationHandler(nameof(IWidgetHostViewModel))]
public partial class PrimaryViewModel(ITemplateFactory templateFactory,
public partial class PrimaryViewModel(IViewModelTemplateFactory templateFactory,
IServiceProvider serviceProvider,
IServiceFactory serviceFactory,
IMediator mediator,
IDisposer disposer,
int index) :
ObservableCollectionViewModel<IWidgetViewModel>(serviceFactory, mediator, disposer),
IWidgetHostViewModel,
ITemplatedViewModel
ObservableCollectionViewModel<IWidgetViewModel>(serviceProvider, serviceFactory, mediator, disposer),
IWidgetHostViewModel
{
[ObservableProperty]
private int index = index;
public ITemplateFactory TemplateFactory => templateFactory;
public IViewModelTemplateFactory TemplateFactory => templateFactory;
}
+2 -2
View File
@@ -3,9 +3,9 @@
x:Class="Hyperbar.Windows.SecondaryView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:windows="using:Hyperbar.UI.Windows">
xmlns:ui="using:Hyperbar.UI.Windows">
<Grid>
<ItemsControl ItemTemplateSelector="{Binding Converter={windows:DataTemplateConverter}}" ItemsSource="{x:Bind ViewModel, Mode=OneWay}">
<ItemsControl ItemTemplateSelector="{ui:ViewModelTemplate}" ItemsSource="{x:Bind ViewModel, Mode=OneWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<ItemsStackPanel Orientation="Horizontal" />
+5 -5
View File
@@ -4,17 +4,17 @@ using Hyperbar.Windows;
namespace Hyperbar.Widget;
public partial class SecondaryViewModel :
ObservableCollectionViewModel<IDisposable>,
ITemplatedViewModel
ObservableCollectionViewModel<IDisposable>
{
[ObservableProperty]
private int index;
public SecondaryViewModel(ITemplateFactory templateFactory,
public SecondaryViewModel(IViewModelTemplateFactory templateFactory,
IServiceProvider serviceProvider,
IServiceFactory serviceFactory,
IMediator mediator,
IDisposer disposer,
int index) : base(serviceFactory, mediator, disposer)
int index) : base(serviceProvider, serviceFactory, mediator, disposer)
{
TemplateFactory = templateFactory;
this.index = index;
@@ -22,5 +22,5 @@ public partial class SecondaryViewModel :
Add<SettingsButtonViewModel>();
}
public ITemplateFactory TemplateFactory { get; }
public IViewModelTemplateFactory TemplateFactory { get; }
}
+5 -5
View File
@@ -4,21 +4,21 @@ using CommunityToolkit.Mvvm.Input;
namespace Hyperbar.Windows;
public partial class SettingsButtonViewModel :
ObservableViewModel,
ITemplatedViewModel
ObservableViewModel
{
[ObservableProperty]
private IRelayCommand? invokeCommand;
public SettingsButtonViewModel(ITemplateFactory templateFactory,
public SettingsButtonViewModel(IViewModelTemplateFactory templateFactory,
IServiceProvider serviceProvider,
IServiceFactory serviceFactory,
IMediator mediator,
IDisposer disposer) : base(serviceFactory, mediator, disposer)
IDisposer disposer) : base(serviceProvider, serviceFactory, mediator, disposer)
{
TemplateFactory = templateFactory;
InvokeCommand = new AsyncRelayCommand(async () =>
await mediator.PublishAsync(new Navigate("Settings")));
}
public ITemplateFactory TemplateFactory { get; }
public IViewModelTemplateFactory TemplateFactory { get; }
}
+4 -8
View File
@@ -3,7 +3,8 @@
x:Class="Hyperbar.Windows.SettingsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:hyperbar="using:Hyperbar">
xmlns:ui="using:Hyperbar.UI.Windows"
xmlns:windows="using:Hyperbar.Windows">
<Window.SystemBackdrop>
<MicaBackdrop />
</Window.SystemBackdrop>
@@ -11,11 +12,6 @@
IsBackButtonVisible="Collapsed"
IsPaneToggleButtonVisible="False"
IsSettingsVisible="False"
MenuItemsSource="{x:Bind ViewModel, Mode=OneWay}">
<NavigationView.MenuItemTemplate>
<DataTemplate x:DataType="hyperbar:NavigationViewModel">
<NavigationViewItem Content="{x:Bind Text, Mode=OneWay}" />
</DataTemplate>
</NavigationView.MenuItemTemplate>
</NavigationView>
MenuItemTemplateSelector="{ui:ViewModelTemplate}"
MenuItemsSource="{x:Bind ViewModel, Mode=OneWay}" />
</Window>
+12 -1
View File
@@ -1,3 +1,5 @@
using Hyperbar.UI.Windows;
using Microsoft.UI;
using Microsoft.UI.Xaml;
namespace Hyperbar.Windows;
@@ -5,9 +7,18 @@ namespace Hyperbar.Windows;
public partial class SettingsView :
Window
{
public SettingsView() =>
public SettingsView()
{
InitializeComponent();
this.TitleBarConfiguration(args =>
{
args.ExtendsContentIntoTitleBar = true;
args.ButtonBackgroundColor = Colors.Transparent;
args.ButtonInactiveBackgroundColor = Colors.Transparent;
});
}
protected SettingsViewModel ViewModel =>
(SettingsViewModel)(Content as FrameworkElement)!.DataContext;
}
+11 -5
View File
@@ -1,13 +1,19 @@
namespace Hyperbar.Windows;
public partial class SettingsViewModel :
ObservableCollectionViewModel<NavigationViewModel>
ObservableCollectionViewModel<INavigationViewModel>
{
public SettingsViewModel(IServiceFactory serviceFactory,
public SettingsViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory,
IMediator mediator,
IDisposer disposer) : base(serviceFactory, mediator, disposer)
IDisposer disposer,
IViewModelTemplateFactory templateFactory) : base(serviceProvider, serviceFactory, mediator, disposer)
{
Add<NavigationViewModel>("General");
Add<NavigationViewModel>("Widgets");
Add<GeneralSettingsNavigationViewModel>("General");
Add<WidgetSettingsNavigationViewModel>("Widgets");
TemplateFactory = templateFactory;
}
public IViewModelTemplateFactory TemplateFactory { get; }
}
@@ -0,0 +1,10 @@
namespace Hyperbar.Windows;
public class WidgetNavigationViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory,
IMediator mediator,
IDisposer disposer,
string text) :
NavigationViewModel(serviceProvider, serviceFactory, mediator, disposer, text)
{
}
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<NavigationViewItem
x:Class="Hyperbar.Windows.WidgetSettingsNavigationView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Content="Widgets" />
@@ -0,0 +1,10 @@
using Microsoft.UI.Xaml.Controls;
namespace Hyperbar.Windows;
public sealed partial class WidgetSettingsNavigationView :
NavigationViewItem
{
public WidgetSettingsNavigationView() =>
InitializeComponent();
}
@@ -0,0 +1,11 @@
namespace Hyperbar.Windows;
public class WidgetSettingsNavigationViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory,
IMediator mediator,
IDisposer disposer,
string text) :
NavigationViewModel<WidgetNavigationViewModel>(serviceProvider, serviceFactory, mediator, disposer, text)
{
}
@@ -164,9 +164,9 @@ public static class IServiceCollectionExtensions
services.AddKeyedTransient(contentType, key);
services.AddKeyedTransient(templateType, key);
services.AddTransient<IContentTemplateDescriptor>(provider => new ContentTemplateDescriptor
services.AddTransient<IViewModelTemplateDescriptor>(provider => new ViewModelTemplateDescriptor
{
ContentType = contentType,
ViewModelType = contentType,
TemplateType = templateType,
Key = key
});
@@ -0,0 +1,7 @@
namespace Hyperbar;
public interface INavigationViewModel :
IObservableViewModel
{
string Text { get; set; }
}
+11 -5
View File
@@ -1,8 +1,14 @@
using System.Windows.Input;
namespace Hyperbar;
namespace Hyperbar;
public interface IObservableViewModel
public interface IObservableViewModel :
IInitialization,
IDisposable
{
ICommand InitializeCommand { get; }
public IDisposer Disposer { get; }
public IMediator Mediator { get; }
public IServiceFactory ServiceFactory { get; }
public IServiceProvider ServiceProvider { get; }
}
+4 -4
View File
@@ -5,7 +5,7 @@ namespace Hyperbar;
public class NavigateHandler :
INotificationHandler<Navigate>
{
private readonly IEnumerable<IContentTemplateDescriptor> contentTemplateDescriptors;
private readonly IEnumerable<IViewModelTemplateDescriptor> contentTemplateDescriptors;
private readonly IServiceProvider provider;
private readonly IMediator mediator;
private readonly IEnumerable<INavigationDescriptor> navigationDescriptors;
@@ -13,7 +13,7 @@ public class NavigateHandler :
public NavigateHandler(IServiceProvider provider,
IMediator mediator,
IEnumerable<INavigationDescriptor> navigationDescriptors,
IEnumerable<IContentTemplateDescriptor> contentTemplateDescriptors)
IEnumerable<IViewModelTemplateDescriptor> contentTemplateDescriptors)
{
this.provider = provider;
this.mediator = mediator;
@@ -25,7 +25,7 @@ public class NavigateHandler :
CancellationToken cancellationToken)
{
if (contentTemplateDescriptors.FirstOrDefault(x => x.Key == args.Key)
is IContentTemplateDescriptor contentTemplateDescriptor)
is IViewModelTemplateDescriptor contentTemplateDescriptor)
{
if (navigationDescriptors.FirstOrDefault(x => contentTemplateDescriptor.TemplateType == x.Type ||
contentTemplateDescriptor.TemplateType.BaseType == x.Type) is { } navigationDescriptor)
@@ -35,7 +35,7 @@ public class NavigateHandler :
{
if (provider.GetRequiredKeyedService(contentTemplateDescriptor.TemplateType,
contentTemplateDescriptor.Key) is { } template &&
provider.GetRequiredKeyedService(contentTemplateDescriptor.ContentType,
provider.GetRequiredKeyedService(contentTemplateDescriptor.ViewModelType,
contentTemplateDescriptor.Key) is { } content)
{
Type navigateType = typeof(Navigate<>)
+19 -3
View File
@@ -3,16 +3,32 @@
namespace Hyperbar;
public partial class NavigationViewModel :
ObservableCollectionViewModel<NavigationViewModel>
ObservableCollectionViewModel<INavigationViewModel>,
INavigationViewModel
{
[ObservableProperty]
private string? text;
public NavigationViewModel(IServiceFactory serviceFactory,
public NavigationViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory,
IMediator mediator,
IDisposer disposer,
string text) : base(serviceFactory, mediator, disposer)
string text) : base(serviceProvider, serviceFactory, mediator, disposer)
{
this.text = text;
}
}
public partial class NavigationViewModel<TNavigationViewModel>(IServiceProvider serviceProvider,
IServiceFactory serviceFactory,
IMediator mediator,
IDisposer disposer,
string text) :
ObservableCollectionViewModel<TNavigationViewModel>(serviceProvider, serviceFactory, mediator, disposer),
INavigationViewModel
where TNavigationViewModel :
INavigationViewModel
{
[ObservableProperty]
private string? text = text;
}
@@ -8,31 +8,29 @@ using System.Windows.Input;
namespace Hyperbar;
public partial class ObservableCollectionViewModel<TItem> :
public partial class ObservableCollectionViewModel<TViewModel> :
ObservableObject,
IObservableCollectionViewModel<TItem>,
IList<TItem>,
IObservableCollectionViewModel<TViewModel>,
IList<TViewModel>,
IList,
IReadOnlyList<TItem>,
IReadOnlyList<TViewModel>,
INotifyCollectionChanged,
INotificationHandler<Remove<TItem>>,
INotificationHandler<Create<TItem>>,
INotificationHandler<Insert<TItem>>,
INotificationHandler<Move<TItem>>,
INotificationHandler<Replace<TItem>>,
IDisposable,
IInitialization
where TItem :
IDisposable
INotificationHandler<Remove<TViewModel>>,
INotificationHandler<Create<TViewModel>>,
INotificationHandler<Insert<TViewModel>>,
INotificationHandler<Move<TViewModel>>,
INotificationHandler<Replace<TViewModel>>
{
private readonly ObservableCollection<TItem> collection = [];
private readonly ObservableCollection<TViewModel> collection = [];
private bool isInitialized;
public ObservableCollectionViewModel(IServiceFactory serviceFactory,
public ObservableCollectionViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory,
IMediator mediator,
IDisposer disposer)
{
ServiceProvider = serviceProvider;
ServiceFactory = serviceFactory;
Mediator = mediator;
Disposer = disposer;
@@ -42,11 +40,13 @@ public partial class ObservableCollectionViewModel<TItem> :
collection.CollectionChanged += OnCollectionChanged;
}
public ObservableCollectionViewModel(IServiceFactory serviceFactory,
public ObservableCollectionViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory,
IMediator mediator,
IDisposer disposer,
IEnumerable<TItem> items)
IEnumerable<TViewModel> items)
{
ServiceProvider = serviceProvider;
ServiceFactory = serviceFactory;
Mediator = mediator;
Disposer = disposer;
@@ -61,28 +61,28 @@ public partial class ObservableCollectionViewModel<TItem> :
public int Count => collection.Count;
public IDisposer Disposer { get; private set; }
public ICommand InitializeCommand =>
new AsyncRelayCommand(CoreInitializeAsync);
new AsyncRelayCommand(CoreInitializeAsync);
bool IList.IsFixedSize => false;
bool ICollection<TItem>.IsReadOnly => false;
bool ICollection<TViewModel>.IsReadOnly => false;
bool IList.IsReadOnly => false;
bool ICollection.IsSynchronized => false;
public IMediator Mediator { get; private set; }
public IServiceFactory ServiceFactory { get; private set; }
object ICollection.SyncRoot => this;
protected IDisposer Disposer { get; private set; }
public IServiceProvider ServiceProvider { get; private set; }
protected IList<TItem> Items => collection;
protected IMediator Mediator { get; private set; }
protected IServiceFactory ServiceFactory { get; private set; }
public TItem this[int index]
public TViewModel this[int index]
{
get => collection[index];
set => SetItem(index, value);
@@ -93,11 +93,11 @@ public partial class ObservableCollectionViewModel<TItem> :
get => collection[index];
set
{
TItem? item = default;
TViewModel? item = default;
try
{
item = (TItem)value!;
item = (TViewModel)value!;
}
catch (InvalidCastException)
{
@@ -108,16 +108,16 @@ public partial class ObservableCollectionViewModel<TItem> :
}
}
public TItem Add()
public TViewModel Add()
{
TItem? item = ServiceFactory.Create<TItem>();
TViewModel? item = ServiceFactory.Create<TViewModel>();
Add(item);
return item;
}
public TItem Add<T>(params object?[] parameters)
where T : TItem
public TViewModel Add<T>(params object?[] parameters)
where T : TViewModel
{
T? item = ServiceFactory.Create<T>(parameters);
Add(item);
@@ -125,9 +125,9 @@ public partial class ObservableCollectionViewModel<TItem> :
return item;
}
public TItem Add<T>()
public TViewModel Add<T>()
where T :
TItem
TViewModel
{
T? item = ServiceFactory.Create<T>();
Add(item);
@@ -135,7 +135,7 @@ public partial class ObservableCollectionViewModel<TItem> :
return item;
}
public void Add(TItem item)
public void Add(TViewModel item)
{
int index = collection.Count;
InsertItem(index, item);
@@ -144,16 +144,16 @@ public partial class ObservableCollectionViewModel<TItem> :
public void Add(object item)
{
int index = collection.Count;
InsertItem(index, (TItem)item);
InsertItem(index, (TViewModel)item);
}
int IList.Add(object? value)
{
TItem? item = default;
TViewModel? item = default;
try
{
item = (TItem)value!;
item = (TViewModel)value!;
}
catch (InvalidCastException)
{
@@ -164,9 +164,9 @@ public partial class ObservableCollectionViewModel<TItem> :
return Count - 1;
}
public void AddRange(IEnumerable<TItem> items)
public void AddRange(IEnumerable<TViewModel> items)
{
foreach (TItem? item in items)
foreach (TViewModel? item in items)
{
Add(item);
}
@@ -174,7 +174,7 @@ public partial class ObservableCollectionViewModel<TItem> :
public void Clear()
{
foreach (TItem item in collection)
foreach (TViewModel item in collection)
{
Disposer.Dispose(item);
}
@@ -182,17 +182,17 @@ public partial class ObservableCollectionViewModel<TItem> :
ClearItems();
}
public bool Contains(TItem item) =>
public bool Contains(TViewModel item) =>
collection.Contains(item);
bool IList.Contains(object? value) =>
IsCompatibleObject(value) && Contains((TItem)value!);
IsCompatibleObject(value) && Contains((TViewModel)value!);
public void CopyTo(TItem[] array, int index) =>
public void CopyTo(TViewModel[] array, int index) =>
collection.CopyTo(array, index);
void ICollection.CopyTo(Array array, int index) =>
collection.CopyTo((TItem[])array, index);
collection.CopyTo((TViewModel[])array, index);
public virtual void Dispose()
{
@@ -200,16 +200,16 @@ public partial class ObservableCollectionViewModel<TItem> :
Disposer.Dispose(this);
}
public System.Collections.Generic.IEnumerator<TItem> GetEnumerator() =>
public System.Collections.Generic.IEnumerator<TViewModel> GetEnumerator() =>
collection.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() =>
((IEnumerable)collection).GetEnumerator();
public Task Handle(Remove<TItem> notification,
public Task Handle(Remove<TViewModel> notification,
CancellationToken cancellationToken)
{
foreach (TItem item in this.ToList())
foreach (TViewModel item in this.ToList())
{
if (notification.Value is not null && notification.Value.Equals(item))
{
@@ -220,10 +220,10 @@ public partial class ObservableCollectionViewModel<TItem> :
return Task.CompletedTask;
}
public Task Handle(Create<TItem> notification,
public Task Handle(Create<TViewModel> notification,
CancellationToken cancellationToken)
{
if (notification.Value is TItem item)
if (notification.Value is TViewModel item)
{
Add(item);
}
@@ -231,10 +231,10 @@ public partial class ObservableCollectionViewModel<TItem> :
return Task.CompletedTask;
}
public Task Handle(Insert<TItem> notification,
public Task Handle(Insert<TViewModel> notification,
CancellationToken cancellationToken)
{
if (notification.Value is TItem item)
if (notification.Value is TViewModel item)
{
Insert(notification.Index, item);
}
@@ -242,10 +242,10 @@ public partial class ObservableCollectionViewModel<TItem> :
return Task.CompletedTask;
}
public Task Handle(Move<TItem> notification,
public Task Handle(Move<TViewModel> notification,
CancellationToken cancellationToken)
{
if (notification.Value is TItem item)
if (notification.Value is TViewModel item)
{
Move(notification.Index, item);
}
@@ -253,10 +253,10 @@ public partial class ObservableCollectionViewModel<TItem> :
return Task.CompletedTask;
}
public Task Handle(Replace<TItem> notification,
public Task Handle(Replace<TViewModel> notification,
CancellationToken cancellationToken)
{
if (notification.Value is TItem item)
if (notification.Value is TViewModel item)
{
Replace(notification.Index, item);
}
@@ -264,25 +264,27 @@ public partial class ObservableCollectionViewModel<TItem> :
return Task.CompletedTask;
}
public int IndexOf(TItem item) =>
public int IndexOf(TViewModel item) =>
collection.IndexOf(item);
int IList.IndexOf(object? value) =>
IsCompatibleObject(value) ?
IndexOf((TItem)value!) : -1;
public void Insert(int index, TItem item) =>
InsertItem(index, item);
IndexOf((TViewModel)value!) : -1;
public virtual Task InitializeAsync() => Task.CompletedTask;
public void Insert(int index, TViewModel item) =>
InsertItem(index, item);
void IList.Insert(int index,
object? value)
{
if (value is TItem item)
if (value is TViewModel item)
{
Insert(index, item);
}
}
public bool Move(int index, TItem item)
public bool Move(int index, TViewModel item)
{
int oldIndex = collection.IndexOf(item);
if (oldIndex < 0)
@@ -295,13 +297,7 @@ public partial class ObservableCollectionViewModel<TItem> :
return true;
}
public virtual Task InitializeAsync()
{
return Task.CompletedTask;
}
public bool Remove(TItem item)
public bool Remove(TViewModel item)
{
int index = collection.IndexOf(item);
if (index < 0)
@@ -319,14 +315,14 @@ public partial class ObservableCollectionViewModel<TItem> :
{
if (IsCompatibleObject(value))
{
Remove((TItem)value!);
Remove((TViewModel)value!);
}
}
public void RemoveAt(int index) =>
RemoveItem(index);
public bool Replace(int index, TItem item)
public bool Replace(int index, TViewModel item)
{
if (index <= Count - 1)
{
@@ -346,7 +342,7 @@ public partial class ObservableCollectionViewModel<TItem> :
collection.Clear();
protected virtual void InsertItem(int index,
TItem value)
TViewModel value)
{
Disposer.Add(this, value);
Disposer.Add(value, value, Disposable.Create(() =>
@@ -363,11 +359,11 @@ public partial class ObservableCollectionViewModel<TItem> :
protected virtual void RemoveItem(int index) =>
collection.RemoveAt(index);
protected virtual void SetItem(int index, TItem item) =>
protected virtual void SetItem(int index, TViewModel item) =>
collection[index] = item;
private static bool IsCompatibleObject(object? value) =>
(value is TItem) || (value == null && default(TItem) == null);
(value is TViewModel) || (value == null && default(TViewModel) == null);
private async Task CoreInitializeAsync()
{
@@ -378,7 +374,7 @@ public partial class ObservableCollectionViewModel<TItem> :
isInitialized = true;
await Mediator.PublishAsync<Enumerate<TItem>>();
await Mediator.PublishAsync<Enumerate<TViewModel>>();
await InitializeAsync();
}
@@ -386,7 +382,8 @@ public partial class ObservableCollectionViewModel<TItem> :
CollectionChanged?.Invoke(this, args);
}
public class ObservableCollectionViewModel(IServiceFactory serviceFactory,
public class ObservableCollectionViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory,
IMediator mediator,
IDisposer disposer) :
ObservableCollectionViewModel<IDisposable>(serviceFactory, mediator, disposer);
ObservableCollectionViewModel<IDisposable>(serviceProvider, serviceFactory, mediator, disposer);
+33 -4
View File
@@ -1,16 +1,45 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.Windows.Input;
namespace Hyperbar;
public class ObservableViewModel(IServiceFactory serviceFactory,
public class ObservableViewModel(IServiceProvider serviceProvider,
IServiceFactory serviceFactory,
IMediator mediator,
IDisposer disposer) :
ObservableObject,
IDisposable
IObservableViewModel
{
public IServiceFactory ServiceFactory => serviceFactory;
private bool isInitialized;
public IDisposer Disposer => disposer;
public ICommand InitializeCommand =>
new AsyncRelayCommand(CoreInitializeAsync);
public IMediator Mediator => mediator;
public void Dispose() => disposer.Dispose(this);
public IServiceFactory ServiceFactory => serviceFactory;
public IServiceProvider ServiceProvider => serviceProvider;
public void Dispose()
{
GC.SuppressFinalize(this);
disposer.Dispose(this);
}
public virtual Task InitializeAsync() => Task.CompletedTask;
private async Task CoreInitializeAsync()
{
if (isInitialized)
{
return;
}
isInitialized = true;
await InitializeAsync();
}
}
@@ -1,11 +0,0 @@
namespace Hyperbar;
public record ContentTemplateDescriptor :
IContentTemplateDescriptor
{
public required Type ContentType { get; set; }
public required Type TemplateType { get; set; }
public required object Key { get; set; }
}
@@ -1,6 +0,0 @@
namespace Hyperbar;
public interface ITemplatedViewModel
{
ITemplateFactory TemplateFactory { get; }
}
@@ -1,10 +1,10 @@
namespace Hyperbar;
public interface IContentTemplateDescriptor
public interface IViewModelTemplateDescriptor
{
Type ContentType { get; set; }
object Key { get; set; }
Type TemplateType { get; set; }
Type ViewModelType { get; set; }
}
@@ -0,0 +1,6 @@
namespace Hyperbar;
public interface IViewModelTemplateDescriptorProvider
{
IViewModelTemplateDescriptor? Get(object key);
}
@@ -1,6 +1,6 @@
namespace Hyperbar;
public interface ITemplateFactory
public interface IViewModelTemplateFactory
{
object? Create(object key);
}
@@ -0,0 +1,11 @@
namespace Hyperbar;
public record ViewModelTemplateDescriptor :
IViewModelTemplateDescriptor
{
public required Type ViewModelType { get; set; }
public required Type TemplateType { get; set; }
public required object Key { get; set; }
}
@@ -0,0 +1,16 @@
namespace Hyperbar;
public class ViewModelTemplateDescriptorProvider(IEnumerable<IViewModelTemplateDescriptor> descriptors) :
IViewModelTemplateDescriptorProvider
{
public IViewModelTemplateDescriptor? Get(object key)
{
if (descriptors.FirstOrDefault(x => x.Key == key)
is IViewModelTemplateDescriptor descriptor)
{
return descriptor;
}
return default;
}
}
@@ -0,0 +1,23 @@
using Microsoft.Extensions.DependencyInjection;
namespace Hyperbar;
public class ViewModelTemplateFactory(IViewModelTemplateDescriptorProvider descriptors,
IServiceProvider services) :
IViewModelTemplateFactory
{
public object? Create(object key)
{
if (descriptors.Get(key)
is IViewModelTemplateDescriptor descriptor)
{
if (services.GetRequiredKeyedService(descriptor.TemplateType,
descriptor.Key) is { } template)
{
return template;
}
}
return default;
}
}