Skip to content

Commit 105168d

Browse files
committed
feat: Add WinUI3
1 parent 84439b5 commit 105168d

22 files changed

+667
-6
lines changed

NatTypeTester.ViewModels/MainWindowViewModel.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using NatTypeTester.Models;
55
using ReactiveUI;
66
using STUN;
7+
using System.Collections.Frozen;
78
using System.Reactive.Linq;
89
using Volo.Abp.DependencyInjection;
910

@@ -19,15 +20,15 @@ public class MainWindowViewModel : ViewModelBase, IScreen
1920

2021
public Config Config => LazyServiceProvider.LazyGetRequiredService<Config>();
2122

22-
private readonly IEnumerable<string> _defaultServers = new HashSet<string>
23+
private static readonly FrozenSet<string> DefaultServers = new[]
2324
{
2425
@"stunserver.stunprotocol.org",
25-
@"stun.fitauto.ru",
2626
@"stun.hot-chilli.net",
27+
@"stun.fitauto.ru",
2728
@"stun.syncthing.net",
2829
@"stun.qq.com",
2930
@"stun.miwifi.com"
30-
};
31+
}.ToFrozenSet();
3132

3233
private SourceList<string> List { get; } = new();
3334
public readonly IObservableCollection<string> StunServers = new ObservableCollectionExtended<string>();
@@ -43,12 +44,12 @@ public MainWindowViewModel()
4344

4445
public void LoadStunServer()
4546
{
46-
foreach (string? server in _defaultServers)
47+
foreach (string? server in DefaultServers)
4748
{
4849
List.Add(server);
4950
}
5051

51-
Config.StunServer = _defaultServers.First();
52+
Config.StunServer = DefaultServers.First();
5253

5354
Task.Run(() =>
5455
{

NatTypeTester.ViewModels/ViewModelBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ namespace NatTypeTester.ViewModels;
55

66
public abstract class ViewModelBase : ReactiveObject, ISingletonDependency
77
{
8-
public IAbpLazyServiceProvider LazyServiceProvider { get; set; } = null!;
8+
public IAbpLazyServiceProvider LazyServiceProvider { get; init; } = null!;
99
}

NatTypeTester.WinUI/App.xaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<Application
2+
x:Class="NatTypeTester.App"
3+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
5+
<Application.Resources>
6+
<ResourceDictionary>
7+
<ResourceDictionary.MergedDictionaries>
8+
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
9+
<!-- Other merged dictionaries here -->
10+
</ResourceDictionary.MergedDictionaries>
11+
<!-- Other app resources here -->
12+
</ResourceDictionary>
13+
</Application.Resources>
14+
</Application>

NatTypeTester.WinUI/App.xaml.cs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
namespace NatTypeTester;
2+
3+
public partial class App
4+
{
5+
private readonly IAbpApplicationWithInternalServiceProvider _application;
6+
7+
public App()
8+
{
9+
InitializeComponent();
10+
_application = AbpApplicationFactory.Create<NatTypeTesterModule>(options => options.UseAutofac());
11+
_application.Initialize();
12+
_application.ServiceProvider.UseMicrosoftDependencyResolver();
13+
}
14+
15+
protected override void OnLaunched(LaunchActivatedEventArgs args)
16+
{
17+
_application.ServiceProvider.GetRequiredService<MainWindow>().Activate();
18+
}
19+
}

NatTypeTester.WinUI/Assets/icon.ico

159 KB
Binary file not shown.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
namespace NatTypeTester.Extensions;
2+
3+
internal static class ContentDialogExtensions
4+
{
5+
public static async ValueTask HandleExceptionWithContentDialogAsync(this Exception ex, XamlRoot root)
6+
{
7+
ContentDialog dialog = new();
8+
try
9+
{
10+
dialog.XamlRoot = root;
11+
dialog.Title = nameof(NatTypeTester);
12+
dialog.Content = ex.Message;
13+
dialog.PrimaryButtonText = @"OK";
14+
15+
await dialog.ShowAsync();
16+
}
17+
finally
18+
{
19+
dialog.Hide();
20+
}
21+
}
22+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace NatTypeTester.Extensions;
2+
3+
internal static class DIExtension
4+
{
5+
public static T GetRequiredService<T>(this IReadonlyDependencyResolver resolver, string? contract = null) where T : notnull
6+
{
7+
Requires.NotNull(resolver);
8+
9+
T? service = resolver.GetService<T>(contract);
10+
11+
Verify.Operation(service is not null, $@"No service for type {typeof(T)} has been registered.");
12+
13+
return service;
14+
}
15+
}

NatTypeTester.WinUI/MainWindow.xaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<Window
2+
x:Class="NatTypeTester.MainWindow"
3+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
6+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
7+
mc:Ignorable="d"
8+
>
9+
<Frame x:Name="MainFrame" />
10+
</Window>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
namespace NatTypeTester;
2+
3+
public sealed partial class MainWindow : ISingletonDependency
4+
{
5+
public MainWindow()
6+
{
7+
InitializeComponent();
8+
9+
Title = nameof(NatTypeTester);
10+
ExtendsContentIntoTitleBar = true;
11+
12+
AppWindow.Resize(new SizeInt32(500, 590));
13+
AppWindow.SetIcon(@"Assets\icon.ico");
14+
15+
// CenterScreen
16+
{
17+
DisplayArea displayArea = DisplayArea.GetFromWindowId(AppWindow.Id, DisplayAreaFallback.Nearest);
18+
int x = (displayArea.WorkArea.Width - AppWindow.Size.Width) / 2;
19+
int y = (displayArea.WorkArea.Height - AppWindow.Size.Height) / 2;
20+
AppWindow.Move(new PointInt32(x, y));
21+
}
22+
23+
MainFrame.Navigate(typeof(MainPage));
24+
}
25+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<Import Project="..\common.props" />
4+
5+
<PropertyGroup>
6+
<OutputType>WinExe</OutputType>
7+
<TargetFramework>net8.0-windows10.0.22621.0</TargetFramework>
8+
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
9+
<RootNamespace>NatTypeTester</RootNamespace>
10+
<AssemblyName>NatTypeTester</AssemblyName>
11+
<ApplicationManifest>app.manifest</ApplicationManifest>
12+
<Platforms>x64;ARM64</Platforms>
13+
<RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers>
14+
<UseWinUI>true</UseWinUI>
15+
<ApplicationIcon>Assets\icon.ico</ApplicationIcon>
16+
<Version>8.0.0</Version>
17+
<EnableMsixTooling>true</EnableMsixTooling>
18+
<WindowsPackageType>None</WindowsPackageType>
19+
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
20+
</PropertyGroup>
21+
22+
<ItemGroup>
23+
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
24+
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.4.231115000" />
25+
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" />
26+
<PackageReference Include="ReactiveMarbles.ObservableEvents.SourceGenerator" Version="1.3.1" PrivateAssets="all" />
27+
<PackageReference Include="ReactiveUI.WinUI" Version="19.5.1" />
28+
<PackageReference Include="Splat.Microsoft.Extensions.DependencyInjection" Version="14.8.6" />
29+
<PackageReference Include="Volo.Abp.Autofac" Version="7.4.2" />
30+
<Manifest Include="$(ApplicationManifest)" />
31+
</ItemGroup>
32+
33+
<ItemGroup>
34+
<ProjectReference Include="..\NatTypeTester.ViewModels\NatTypeTester.ViewModels.csproj" />
35+
</ItemGroup>
36+
37+
</Project>
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
global using JetBrains.Annotations;
2+
global using Microsoft;
3+
global using Microsoft.Extensions.DependencyInjection;
4+
global using Microsoft.Extensions.DependencyInjection.Extensions;
5+
global using Microsoft.UI.Windowing;
6+
global using Microsoft.UI.Xaml;
7+
global using Microsoft.UI.Xaml.Controls;
8+
global using Microsoft.VisualStudio.Threading;
9+
global using NatTypeTester.Extensions;
10+
global using NatTypeTester.ViewModels;
11+
global using NatTypeTester.Views;
12+
global using ReactiveMarbles.ObservableEvents;
13+
global using ReactiveUI;
14+
global using Splat;
15+
global using Splat.Microsoft.Extensions.DependencyInjection;
16+
global using STUN.Enums;
17+
global using System.Reactive.Disposables;
18+
global using System.Reactive.Linq;
19+
global using Volo.Abp;
20+
global using Volo.Abp.Autofac;
21+
global using Volo.Abp.DependencyInjection;
22+
global using Volo.Abp.Modularity;
23+
global using Windows.Graphics;
24+
global using Windows.System;
25+
26+
namespace NatTypeTester;
27+
28+
[DependsOn(
29+
typeof(AbpAutofacModule),
30+
typeof(NatTypeTesterViewModelModule)
31+
)]
32+
[UsedImplicitly]
33+
internal class NatTypeTesterModule : AbpModule
34+
{
35+
public override void PreConfigureServices(ServiceConfigurationContext context)
36+
{
37+
context.Services.UseMicrosoftDependencyResolver();
38+
Locator.CurrentMutable.InitializeSplat();
39+
Locator.CurrentMutable.InitializeReactiveUI(RegistrationNamespace.WinUI);
40+
}
41+
42+
public override void ConfigureServices(ServiceConfigurationContext context)
43+
{
44+
context.Services.TryAddTransient<RoutingState>();
45+
}
46+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<views:MainReactivePage
2+
x:Class="NatTypeTester.Views.MainPage"
3+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
6+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
7+
xmlns:views="using:NatTypeTester.Views"
8+
xmlns:reactiveUi="using:ReactiveUI"
9+
mc:Ignorable="d"
10+
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
11+
12+
<Grid RowDefinitions="28,Auto,*" >
13+
14+
<!-- TitleBar -->
15+
<StackPanel
16+
Padding="8,0,0,0"
17+
Orientation="Horizontal"
18+
Spacing="5">
19+
<Image Height="16" Source="/Assets/icon.ico" />
20+
<TextBlock
21+
Style="{StaticResource CaptionTextBlockStyle}"
22+
VerticalAlignment="Center"
23+
Text="NatTypeTester" />
24+
</StackPanel>
25+
26+
<StackPanel Grid.Row="1">
27+
<ComboBox x:Name="ServersComboBox"
28+
Margin="10,10"
29+
IsEditable="True"
30+
Header="STUN Server"
31+
HorizontalAlignment="Stretch">
32+
<ComboBox.ItemTemplate>
33+
<DataTemplate>
34+
<TextBlock Text="{Binding }"/>
35+
</DataTemplate>
36+
</ComboBox.ItemTemplate>
37+
</ComboBox>
38+
</StackPanel>
39+
40+
<NavigationView
41+
Grid.Row="2"
42+
x:Name="NavigationView"
43+
IsBackEnabled="False"
44+
IsBackButtonVisible="Collapsed"
45+
PaneDisplayMode="LeftCompact"
46+
IsPaneOpen="False">
47+
48+
<NavigationView.MenuItems>
49+
<NavigationViewItem Content="RFC 5780" Tag="1">
50+
<NavigationViewItem.Icon>
51+
<FontIcon Glyph="&#xEDA3;" />
52+
</NavigationViewItem.Icon>
53+
</NavigationViewItem>
54+
<NavigationViewItem Content="RFC 3489" Tag="2">
55+
<NavigationViewItem.Icon>
56+
<FontIcon Glyph="&#xE969;" />
57+
</NavigationViewItem.Icon>
58+
</NavigationViewItem>
59+
</NavigationView.MenuItems>
60+
61+
<reactiveUi:RoutedViewHost
62+
x:Name="RoutedViewHost"
63+
HorizontalContentAlignment="Stretch"
64+
VerticalContentAlignment="Stretch">
65+
<reactiveUi:RoutedViewHost.ContentTransitions>
66+
<TransitionCollection>
67+
<ContentThemeTransition />
68+
</TransitionCollection>
69+
</reactiveUi:RoutedViewHost.ContentTransitions>
70+
</reactiveUi:RoutedViewHost>
71+
72+
</NavigationView>
73+
74+
</Grid>
75+
</views:MainReactivePage>
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
namespace NatTypeTester.Views;
2+
3+
internal sealed partial class MainPage
4+
{
5+
public MainPage()
6+
{
7+
InitializeComponent();
8+
ViewModel = Locator.Current.GetRequiredService<MainWindowViewModel>();
9+
10+
IAbpLazyServiceProvider serviceProvider = Locator.Current.GetRequiredService<IAbpLazyServiceProvider>();
11+
12+
this.WhenActivated(d =>
13+
{
14+
this.Bind(ViewModel,
15+
vm => vm.Config.StunServer,
16+
v => v.ServersComboBox.Text
17+
).DisposeWith(d);
18+
19+
this.OneWayBind(ViewModel,
20+
vm => vm.StunServers,
21+
v => v.ServersComboBox.ItemsSource
22+
).DisposeWith(d);
23+
24+
this.OneWayBind(ViewModel, vm => vm.Router, v => v.RoutedViewHost.Router).DisposeWith(d);
25+
26+
NavigationView.Events().SelectionChanged.Subscribe(parameter =>
27+
{
28+
if (parameter.args.IsSettingsSelected)
29+
{
30+
ViewModel.Router.Navigate.Execute(serviceProvider.LazyGetRequiredService<SettingViewModel>()).Subscribe().Dispose();
31+
return;
32+
}
33+
34+
if (parameter.args.SelectedItem is not NavigationViewItem { Tag: string tag })
35+
{
36+
return;
37+
}
38+
39+
switch (tag)
40+
{
41+
case @"1":
42+
{
43+
ViewModel.Router.Navigate.Execute(serviceProvider.LazyGetRequiredService<RFC5780ViewModel>()).Subscribe().Dispose();
44+
break;
45+
}
46+
case @"2":
47+
{
48+
ViewModel.Router.Navigate.Execute(serviceProvider.LazyGetRequiredService<RFC3489ViewModel>()).Subscribe().Dispose();
49+
break;
50+
}
51+
}
52+
}).DisposeWith(d);
53+
NavigationView.SelectedItem = NavigationView.MenuItems.OfType<NavigationViewItem>().First();
54+
55+
ViewModel.LoadStunServer();
56+
});
57+
}
58+
}

0 commit comments

Comments
 (0)