Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 26 additions & 5 deletions PCL2.Neo/App.axaml.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
using System;
using System.Linq;
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Data.Core;
using Avalonia.Data.Core.Plugins;
using Avalonia.Markup.Xaml;
using PCL2.Neo.Helpers;
using PCL2.Neo.Utils;
using CommunityToolkit.Mvvm.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using PCL2.Neo.Services;
using PCL2.Neo.ViewModels;
using PCL2.Neo.ViewModels.Download;
using PCL2.Neo.ViewModels.Home;
using PCL2.Neo.Views;
using System;

namespace PCL2.Neo
{
Expand All @@ -19,14 +21,33 @@
AvaloniaXamlLoader.Load(this);
}

private static IServiceProvider ConfigureServices() => new ServiceCollection()
.AddTransient<MainWindowViewModel>()

.AddTransient<HomeViewModel>()
.AddTransient<HomeSubViewModel>()

.AddTransient<DownloadViewModel>()
.AddTransient<DownloadGameViewModel>()
.AddTransient<DownloadModViewModel>()

.AddSingleton<NavigationService>(s => new NavigationService(s))
.BuildServiceProvider();

public override void OnFrameworkInitializationCompleted()
{
Ioc.Default.ConfigureServices(ConfigureServices());

var vm = Ioc.Default.GetRequiredService<MainWindowViewModel>();
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
// Avoid duplicate validations from both Avalonia and the CommunityToolkit.
// More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins
DisableAvaloniaDataAnnotationValidation();
desktop.MainWindow = new MainWindow();
desktop.MainWindow = new MainWindow
{
DataContext = vm
};
}

base.OnFrameworkInitializationCompleted();
Expand All @@ -36,12 +57,12 @@
{
// Get an array of plugins to remove
var dataValidationPluginsToRemove =
BindingPlugins.DataValidators.OfType<DataAnnotationsValidationPlugin>().ToArray();

Check warning on line 60 in PCL2.Neo/App.axaml.cs

View workflow job for this annotation

GitHub Actions / build-AppImage

Using member 'Avalonia.Data.Core.Plugins.BindingPlugins.DataValidators.get' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. PropertyAccessors might require unreferenced code.

Check warning on line 60 in PCL2.Neo/App.axaml.cs

View workflow job for this annotation

GitHub Actions / build-WinExe

Using member 'Avalonia.Data.Core.Plugins.BindingPlugins.DataValidators.get' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. PropertyAccessors might require unreferenced code.

Check warning on line 60 in PCL2.Neo/App.axaml.cs

View workflow job for this annotation

GitHub Actions / build-MacOsApp

Using member 'Avalonia.Data.Core.Plugins.BindingPlugins.DataValidators.get' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. PropertyAccessors might require unreferenced code.

// remove each entry found
foreach (var plugin in dataValidationPluginsToRemove)
{
BindingPlugins.DataValidators.Remove(plugin);

Check warning on line 65 in PCL2.Neo/App.axaml.cs

View workflow job for this annotation

GitHub Actions / build-AppImage

Using member 'Avalonia.Data.Core.Plugins.BindingPlugins.DataValidators.get' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. PropertyAccessors might require unreferenced code.

Check warning on line 65 in PCL2.Neo/App.axaml.cs

View workflow job for this annotation

GitHub Actions / build-WinExe

Using member 'Avalonia.Data.Core.Plugins.BindingPlugins.DataValidators.get' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. PropertyAccessors might require unreferenced code.

Check warning on line 65 in PCL2.Neo/App.axaml.cs

View workflow job for this annotation

GitHub Actions / build-MacOsApp

Using member 'Avalonia.Data.Core.Plugins.BindingPlugins.DataValidators.get' which has 'RequiresUnreferencedCodeAttribute' can break functionality when trimming application code. PropertyAccessors might require unreferenced code.
}
}
}
Expand Down
15 changes: 15 additions & 0 deletions PCL2.Neo/Attributes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System;

namespace PCL2.Neo;

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public class SubViewModelOfAttribute(Type parentViewModel) : Attribute
{
public Type ParentViewModel { get; } = parentViewModel;
}

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public class DefaultSubViewModelAttribute(Type subViewModel) : Attribute
{
public Type SubViewModel { get; } = subViewModel;
}
21 changes: 20 additions & 1 deletion PCL2.Neo/PCL2.Neo.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
</PackageReference>
<PackageReference Include="Avalonia.Xaml.Behaviors" Version="11.2.7.1" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
<PackageReference Include="DotNet.Bundle" Version="0.9.13" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.4" />
</ItemGroup>

<ItemGroup>
Expand All @@ -46,4 +47,22 @@
<ItemGroup>
<UpToDateCheckInput Remove="Controls\Style\ListBoxStyle.axaml" />
</ItemGroup>

<ItemGroup>
<Compile Update="Views\HomeView.axaml.cs">
<DependentUpon>HomeLeftView.axaml</DependentUpon>
</Compile>
<Compile Update="Views\Home\HomeSubView.axaml.cs">
<DependentUpon>HomeRightView.axaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Update="Views\Download\DownloadGameView.axaml.cs">
<DependentUpon>DownloadRightView.axaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Update="Views\Download\DownloadModView.axaml.cs">
<DependentUpon>DownloadModView.axaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
</ItemGroup>
</Project>
83 changes: 83 additions & 0 deletions PCL2.Neo/Services/NavigationService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using Microsoft.Extensions.DependencyInjection;
using PCL2.Neo.ViewModels;
using System;
using System.Reflection;

namespace PCL2.Neo.Services;

public class NavigationService
{
public IServiceProvider ServiceProvider { get; init; }

public event Action<ViewModelBase?>? CurrentViewModelChanged;
public event Action<ViewModelBase?>? CurrentSubViewModelChanged;

private ViewModelBase? _currentViewModel;
public ViewModelBase? CurrentViewModel
{
get => _currentViewModel;
protected set
{
if (value == _currentViewModel)
return;
_currentViewModel = value;
CurrentViewModelChanged?.Invoke(value);
}
}

private ViewModelBase? _currentSubViewModel;
public ViewModelBase? CurrentSubViewModel
{
get => _currentSubViewModel;
protected set
{
if (value == _currentSubViewModel)
return;
_currentSubViewModel = value;
CurrentSubViewModelChanged?.Invoke(value);
}
}

public NavigationService(IServiceProvider serviceProvider)
{
ServiceProvider = serviceProvider;
}

public virtual T Goto<T>() where T : ViewModelBase
{
if (typeof(T).GetCustomAttribute<DefaultSubViewModelAttribute>() is { } dsvm)
{
var vm = CurrentViewModel as T;
if (vm?.GetType() != typeof(T))
{
vm = ServiceProvider.GetRequiredService<T>();
CurrentViewModel = vm;
}
if (CurrentSubViewModel?.GetType() != dsvm.SubViewModel)
CurrentSubViewModel = ServiceProvider.GetRequiredService(dsvm.SubViewModel) as ViewModelBase;
return vm;
}

if (typeof(T).GetCustomAttribute<SubViewModelOfAttribute>() is { } svmo)
{
var subVm = CurrentSubViewModel as T;
if (CurrentViewModel?.GetType() != svmo.ParentViewModel)
CurrentViewModel = ServiceProvider.GetRequiredService(svmo.ParentViewModel) as ViewModelBase;
if (subVm?.GetType() != typeof(T))
{
subVm = ServiceProvider.GetRequiredService<T>();
CurrentSubViewModel = subVm;
}
return subVm;
}

var targetVm = CurrentViewModel?.GetType() != typeof(T) || CurrentSubViewModel?.GetType() != typeof(T)
? ServiceProvider.GetRequiredService<T>()
: (T)CurrentViewModel;
if (CurrentViewModel?.GetType() != typeof(T))
CurrentViewModel = targetVm;
if (CurrentSubViewModel?.GetType() != typeof(T))
CurrentSubViewModel = targetVm;
return targetVm;
}
}
36 changes: 18 additions & 18 deletions PCL2.Neo/ViewLocator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,28 @@
using Avalonia.Controls.Templates;
using PCL2.Neo.ViewModels;

namespace PCL2.Neo
namespace PCL2.Neo;

public class ViewLocator : IDataTemplate
{
public class ViewLocator : IDataTemplate
public Control? Build(object? param)
{
public Control? Build(object? param)
{
if (param is null)
return null;
if (param is null)
return null;

var name = param.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal);
var type = Type.GetType(name);
var name = param.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal);
var type = Type.GetType(name);

if (type != null)
{
return (Control)Activator.CreateInstance(type)!;
}

return new TextBlock { Text = "Not Found: " + name };
}
public bool Match(object? data)
if (type != null)
{
return data is ViewModelBase;
return (Control)Activator.CreateInstance(type)!;
}

return new TextBlock { Text = "Not Found: " + name };
}

public bool Match(object? data)
{
return data is ViewModelBase;
}
}
}
7 changes: 7 additions & 0 deletions PCL2.Neo/ViewModels/Download/DownloadGameViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace PCL2.Neo.ViewModels.Download;

[SubViewModelOf(typeof(DownloadViewModel))]
public class DownloadGameViewModel : ViewModelBase
{

}
7 changes: 7 additions & 0 deletions PCL2.Neo/ViewModels/Download/DownloadModViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace PCL2.Neo.ViewModels.Download;

[SubViewModelOf(typeof(DownloadViewModel))]
public class DownloadModViewModel : ViewModelBase
{

}
44 changes: 44 additions & 0 deletions PCL2.Neo/ViewModels/DownloadViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using PCL2.Neo.Services;
using PCL2.Neo.ViewModels.Download;

namespace PCL2.Neo.ViewModels;

[DefaultSubViewModel(typeof(DownloadGameViewModel))]
public partial class DownloadViewModel : ViewModelBase
{
public NavigationService NavigationService { get; }

[ObservableProperty]
private string _message = "I am from DownloadViewModel";

public DownloadViewModel(NavigationService navigationService)
{
NavigationService = navigationService;
}

[RelayCommand]
private void NavigateToDownloadGame()
{
this.NavigationService.Goto<DownloadGameViewModel>();
}

[RelayCommand]
private void NavigateToDownloadMod()
{
this.NavigationService.Goto<DownloadModViewModel>();
}

[RelayCommand]
private void Btn_Test1()
{
Message = "I am from DownloadViewModel Test1";
}

[RelayCommand]
private void Btn_Test2()
{
Message = "I am from DownloadViewModel Test2";
}
}
22 changes: 22 additions & 0 deletions PCL2.Neo/ViewModels/Home/HomeSubViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using CommunityToolkit.Mvvm.Input;
using PCL2.Neo.Services;
using PCL2.Neo.ViewModels.Download;

namespace PCL2.Neo.ViewModels.Home;

[SubViewModelOf(typeof(HomeViewModel))]
public partial class HomeSubViewModel : ViewModelBase
{
public NavigationService NavigationService { get; }

public HomeSubViewModel(NavigationService navigationService)
{
this.NavigationService = navigationService;
}

[RelayCommand]
private void NavigateToDownloadMod()
{
this.NavigationService.Goto<DownloadModViewModel>();
}
}
9 changes: 9 additions & 0 deletions PCL2.Neo/ViewModels/HomeViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using PCL2.Neo.ViewModels.Home;

namespace PCL2.Neo.ViewModels;

[DefaultSubViewModel(typeof(HomeSubViewModel))]
public class HomeViewModel : ViewModelBase
{

}
Loading
Loading