Skip to content

Commit e3cecdc

Browse files
authored
Merge pull request #1 from LaoSparrow/main
feat: basic NavigationService && left panel
2 parents 3170da6 + 692c2e2 commit e3cecdc

24 files changed

Lines changed: 617 additions & 134 deletions

PCL2.Neo/App.axaml.cs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
1-
using System;
21
using System.Linq;
32
using Avalonia;
43
using Avalonia.Controls.ApplicationLifetimes;
5-
using Avalonia.Data.Core;
64
using Avalonia.Data.Core.Plugins;
75
using Avalonia.Markup.Xaml;
8-
using PCL2.Neo.Helpers;
9-
using PCL2.Neo.Utils;
6+
using CommunityToolkit.Mvvm.DependencyInjection;
7+
using Microsoft.Extensions.DependencyInjection;
8+
using PCL2.Neo.Services;
109
using PCL2.Neo.ViewModels;
10+
using PCL2.Neo.ViewModels.Download;
11+
using PCL2.Neo.ViewModels.Home;
1112
using PCL2.Neo.Views;
13+
using System;
1214

1315
namespace PCL2.Neo
1416
{
@@ -19,14 +21,33 @@ public override void Initialize()
1921
AvaloniaXamlLoader.Load(this);
2022
}
2123

24+
private static IServiceProvider ConfigureServices() => new ServiceCollection()
25+
.AddTransient<MainWindowViewModel>()
26+
27+
.AddTransient<HomeViewModel>()
28+
.AddTransient<HomeSubViewModel>()
29+
30+
.AddTransient<DownloadViewModel>()
31+
.AddTransient<DownloadGameViewModel>()
32+
.AddTransient<DownloadModViewModel>()
33+
34+
.AddSingleton<NavigationService>(s => new NavigationService(s))
35+
.BuildServiceProvider();
36+
2237
public override void OnFrameworkInitializationCompleted()
2338
{
39+
Ioc.Default.ConfigureServices(ConfigureServices());
40+
41+
var vm = Ioc.Default.GetRequiredService<MainWindowViewModel>();
2442
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
2543
{
2644
// Avoid duplicate validations from both Avalonia and the CommunityToolkit.
2745
// More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins
2846
DisableAvaloniaDataAnnotationValidation();
29-
desktop.MainWindow = new MainWindow();
47+
desktop.MainWindow = new MainWindow
48+
{
49+
DataContext = vm
50+
};
3051
}
3152

3253
base.OnFrameworkInitializationCompleted();

PCL2.Neo/Attributes.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System;
2+
3+
namespace PCL2.Neo;
4+
5+
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
6+
public class SubViewModelOfAttribute(Type parentViewModel) : Attribute
7+
{
8+
public Type ParentViewModel { get; } = parentViewModel;
9+
}
10+
11+
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
12+
public class DefaultSubViewModelAttribute(Type subViewModel) : Attribute
13+
{
14+
public Type SubViewModel { get; } = subViewModel;
15+
}

PCL2.Neo/PCL2.Neo.csproj

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@
3535
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
3636
</PackageReference>
3737
<PackageReference Include="Avalonia.Xaml.Behaviors" Version="11.2.7.1" />
38-
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
3938
<PackageReference Include="DotNet.Bundle" Version="0.9.13" />
39+
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
40+
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.4" />
4041
</ItemGroup>
4142

4243
<ItemGroup>
@@ -46,4 +47,22 @@
4647
<ItemGroup>
4748
<UpToDateCheckInput Remove="Controls\Style\ListBoxStyle.axaml" />
4849
</ItemGroup>
50+
51+
<ItemGroup>
52+
<Compile Update="Views\HomeView.axaml.cs">
53+
<DependentUpon>HomeLeftView.axaml</DependentUpon>
54+
</Compile>
55+
<Compile Update="Views\Home\HomeSubView.axaml.cs">
56+
<DependentUpon>HomeRightView.axaml</DependentUpon>
57+
<SubType>Code</SubType>
58+
</Compile>
59+
<Compile Update="Views\Download\DownloadGameView.axaml.cs">
60+
<DependentUpon>DownloadRightView.axaml</DependentUpon>
61+
<SubType>Code</SubType>
62+
</Compile>
63+
<Compile Update="Views\Download\DownloadModView.axaml.cs">
64+
<DependentUpon>DownloadModView.axaml</DependentUpon>
65+
<SubType>Code</SubType>
66+
</Compile>
67+
</ItemGroup>
4968
</Project>
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
using Microsoft.Extensions.DependencyInjection;
2+
using PCL2.Neo.ViewModels;
3+
using System;
4+
using System.Reflection;
5+
6+
namespace PCL2.Neo.Services;
7+
8+
public class NavigationService
9+
{
10+
public IServiceProvider ServiceProvider { get; init; }
11+
12+
public event Action<ViewModelBase?>? CurrentViewModelChanged;
13+
public event Action<ViewModelBase?>? CurrentSubViewModelChanged;
14+
15+
private ViewModelBase? _currentViewModel;
16+
public ViewModelBase? CurrentViewModel
17+
{
18+
get => _currentViewModel;
19+
protected set
20+
{
21+
if (value == _currentViewModel)
22+
return;
23+
_currentViewModel = value;
24+
CurrentViewModelChanged?.Invoke(value);
25+
}
26+
}
27+
28+
private ViewModelBase? _currentSubViewModel;
29+
public ViewModelBase? CurrentSubViewModel
30+
{
31+
get => _currentSubViewModel;
32+
protected set
33+
{
34+
if (value == _currentSubViewModel)
35+
return;
36+
_currentSubViewModel = value;
37+
CurrentSubViewModelChanged?.Invoke(value);
38+
}
39+
}
40+
41+
public NavigationService(IServiceProvider serviceProvider)
42+
{
43+
ServiceProvider = serviceProvider;
44+
}
45+
46+
public virtual T Goto<T>() where T : ViewModelBase
47+
{
48+
if (typeof(T).GetCustomAttribute<DefaultSubViewModelAttribute>() is { } dsvm)
49+
{
50+
var vm = CurrentViewModel as T;
51+
if (vm?.GetType() != typeof(T))
52+
{
53+
vm = ServiceProvider.GetRequiredService<T>();
54+
CurrentViewModel = vm;
55+
}
56+
if (CurrentSubViewModel?.GetType() != dsvm.SubViewModel)
57+
CurrentSubViewModel = ServiceProvider.GetRequiredService(dsvm.SubViewModel) as ViewModelBase;
58+
return vm;
59+
}
60+
61+
if (typeof(T).GetCustomAttribute<SubViewModelOfAttribute>() is { } svmo)
62+
{
63+
var subVm = CurrentSubViewModel as T;
64+
if (CurrentViewModel?.GetType() != svmo.ParentViewModel)
65+
CurrentViewModel = ServiceProvider.GetRequiredService(svmo.ParentViewModel) as ViewModelBase;
66+
if (subVm?.GetType() != typeof(T))
67+
{
68+
subVm = ServiceProvider.GetRequiredService<T>();
69+
CurrentSubViewModel = subVm;
70+
}
71+
return subVm;
72+
}
73+
74+
var targetVm = CurrentViewModel?.GetType() != typeof(T) || CurrentSubViewModel?.GetType() != typeof(T)
75+
? ServiceProvider.GetRequiredService<T>()
76+
: (T)CurrentViewModel;
77+
if (CurrentViewModel?.GetType() != typeof(T))
78+
CurrentViewModel = targetVm;
79+
if (CurrentSubViewModel?.GetType() != typeof(T))
80+
CurrentSubViewModel = targetVm;
81+
return targetVm;
82+
}
83+
}

PCL2.Neo/ViewLocator.cs

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,28 @@
33
using Avalonia.Controls.Templates;
44
using PCL2.Neo.ViewModels;
55

6-
namespace PCL2.Neo
6+
namespace PCL2.Neo;
7+
8+
public class ViewLocator : IDataTemplate
79
{
8-
public class ViewLocator : IDataTemplate
10+
public Control? Build(object? param)
911
{
10-
public Control? Build(object? param)
11-
{
12-
if (param is null)
13-
return null;
12+
if (param is null)
13+
return null;
1414

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

18-
if (type != null)
19-
{
20-
return (Control)Activator.CreateInstance(type)!;
21-
}
22-
23-
return new TextBlock { Text = "Not Found: " + name };
24-
}
25-
public bool Match(object? data)
18+
if (type != null)
2619
{
27-
return data is ViewModelBase;
20+
return (Control)Activator.CreateInstance(type)!;
2821
}
22+
23+
return new TextBlock { Text = "Not Found: " + name };
24+
}
25+
26+
public bool Match(object? data)
27+
{
28+
return data is ViewModelBase;
2929
}
30-
}
30+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace PCL2.Neo.ViewModels.Download;
2+
3+
[SubViewModelOf(typeof(DownloadViewModel))]
4+
public class DownloadGameViewModel : ViewModelBase
5+
{
6+
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace PCL2.Neo.ViewModels.Download;
2+
3+
[SubViewModelOf(typeof(DownloadViewModel))]
4+
public class DownloadModViewModel : ViewModelBase
5+
{
6+
7+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using CommunityToolkit.Mvvm.ComponentModel;
2+
using CommunityToolkit.Mvvm.Input;
3+
using PCL2.Neo.Services;
4+
using PCL2.Neo.ViewModels.Download;
5+
6+
namespace PCL2.Neo.ViewModels;
7+
8+
[DefaultSubViewModel(typeof(DownloadGameViewModel))]
9+
public partial class DownloadViewModel : ViewModelBase
10+
{
11+
public NavigationService NavigationService { get; }
12+
13+
[ObservableProperty]
14+
private string _message = "I am from DownloadViewModel";
15+
16+
public DownloadViewModel(NavigationService navigationService)
17+
{
18+
NavigationService = navigationService;
19+
}
20+
21+
[RelayCommand]
22+
private void NavigateToDownloadGame()
23+
{
24+
this.NavigationService.Goto<DownloadGameViewModel>();
25+
}
26+
27+
[RelayCommand]
28+
private void NavigateToDownloadMod()
29+
{
30+
this.NavigationService.Goto<DownloadModViewModel>();
31+
}
32+
33+
[RelayCommand]
34+
private void Btn_Test1()
35+
{
36+
Message = "I am from DownloadViewModel Test1";
37+
}
38+
39+
[RelayCommand]
40+
private void Btn_Test2()
41+
{
42+
Message = "I am from DownloadViewModel Test2";
43+
}
44+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using CommunityToolkit.Mvvm.Input;
2+
using PCL2.Neo.Services;
3+
using PCL2.Neo.ViewModels.Download;
4+
5+
namespace PCL2.Neo.ViewModels.Home;
6+
7+
[SubViewModelOf(typeof(HomeViewModel))]
8+
public partial class HomeSubViewModel : ViewModelBase
9+
{
10+
public NavigationService NavigationService { get; }
11+
12+
public HomeSubViewModel(NavigationService navigationService)
13+
{
14+
this.NavigationService = navigationService;
15+
}
16+
17+
[RelayCommand]
18+
private void NavigateToDownloadMod()
19+
{
20+
this.NavigationService.Goto<DownloadModViewModel>();
21+
}
22+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using PCL2.Neo.ViewModels.Home;
2+
3+
namespace PCL2.Neo.ViewModels;
4+
5+
[DefaultSubViewModel(typeof(HomeSubViewModel))]
6+
public class HomeViewModel : ViewModelBase
7+
{
8+
9+
}

0 commit comments

Comments
 (0)