Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option to use CommunityToolkit.Mvvm for template Avalonia.App.CrossPlatform #256

Merged
merged 11 commits into from
Jul 22, 2024
8 changes: 8 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,14 @@ Available parameters:

*By default*: true

``-m, --mvvm``

*Description*: MVVM toolkit to use in the template.

*Options*: **ReactiveUI**, **CommunityToolkit**

*By default*: ReactiveUI

``-av, --avalonia-version``

*Description*: The target version of Avalonia NuGet packages.
Expand Down
5 changes: 4 additions & 1 deletion templates/csharp/xplat/.template.config/dotnetcli.host.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@
"UseCompiledBindings": {
"longName": "compiled-bindings"
},
"MVVMToolkit": {
"longName": "mvvm"
},
"RemoveViewLocator": {
"longName": "remove-view-locator"
}
},
"usageExamples": [
""
"--mvvm communitytoolkit"
]
}
7 changes: 7 additions & 0 deletions templates/csharp/xplat/.template.config/ide.host.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@
},
"isVisible": true
},
{
"id": "MVVMToolkit",
"name": {
"text": "MVVM Toolkit"
},
"isVisible": true
},
{
"id": "UseCompiledBindings",
"name": {
Expand Down
24 changes: 24 additions & 0 deletions templates/csharp/xplat/.template.config/template.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,30 @@
"replaces": "FrameworkParameter",
"defaultValue": "net8.0"
},
"MVVMToolkit": {
"type": "parameter",
"description": "MVVM toolkit to use in the template.",
"datatype": "choice",
"choices": [
{
"choice": "ReactiveUI",
"description": "Choose ReactiveUI as MVVM toolkit in the template."
},
{
"choice": "CommunityToolkit",
"description": "Choose CommunityToolkit as MVVM toolkit in the template."
}
],
"defaultValue": "ReactiveUI"
},
"ReactiveUIToolkitChosen": {
"type": "computed",
"value": "(MVVMToolkit == \"ReactiveUI\")"
},
"CommunityToolkitChosen": {
"type": "computed",
"value": "(MVVMToolkit == \"CommunityToolkit\")"
},
"AvaloniaVersion": {
"type": "parameter",
"description": "The target version of Avalonia NuGet packages.",
Expand Down
6 changes: 6 additions & 0 deletions templates/csharp/xplat/AvaloniaTest.Android/MainActivity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
using Android.Content.PM;
using Avalonia;
using Avalonia.Android;
#if (ReactiveUIToolkitChosen)
using Avalonia.ReactiveUI;
#endif

namespace AvaloniaTest.Android;

Expand All @@ -17,7 +19,11 @@ public class MainActivity : AvaloniaMainActivity<App>
protected override AppBuilder CustomizeAppBuilder(AppBuilder builder)
{
return base.CustomizeAppBuilder(builder)
#if (CommunityToolkitChosen)
.WithInterFont();
#else
.WithInterFont()
.UseReactiveUI();
#endif
}
}
4 changes: 4 additions & 0 deletions templates/csharp/xplat/AvaloniaTest.Browser/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Browser;
#if (ReactiveUIToolkitChosen)
using Avalonia.ReactiveUI;
#endif
using AvaloniaTest;

[assembly: SupportedOSPlatform("browser")]
Expand All @@ -11,7 +13,9 @@ internal sealed partial class Program
{
private static Task Main(string[] args) => BuildAvaloniaApp()
.WithInterFont()
#if (ReactiveUIToolkitChosen)
.UseReactiveUI()
#endif
.StartBrowserAppAsync("out");

public static AppBuilder BuildAvaloniaApp()
Expand Down
8 changes: 6 additions & 2 deletions templates/csharp/xplat/AvaloniaTest.Desktop/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using Avalonia;
#if (ReactiveUIToolkitChosen)
using Avalonia.ReactiveUI;
#endif

namespace AvaloniaTest.Desktop;

Expand All @@ -18,6 +20,8 @@ public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.WithInterFont()
.LogToTrace()
.UseReactiveUI();
#if (ReactiveUIToolkitChosen)
.UseReactiveUI()
#endif
.LogToTrace();
}
6 changes: 6 additions & 0 deletions templates/csharp/xplat/AvaloniaTest.iOS/AppDelegate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
using Avalonia.Controls;
using Avalonia.iOS;
using Avalonia.Media;
#if (ReactiveUIToolkitChosen)
using Avalonia.ReactiveUI;
#endif

namespace AvaloniaTest.iOS;

Expand All @@ -19,7 +21,11 @@ public partial class AppDelegate : AvaloniaAppDelegate<App>
protected override AppBuilder CustomizeAppBuilder(AppBuilder builder)
{
return base.CustomizeAppBuilder(builder)
#if (CommunityToolkitChosen)
.WithInterFont();
#else
.WithInterFont()
.UseReactiveUI();
#endif
}
}
9 changes: 9 additions & 0 deletions templates/csharp/xplat/AvaloniaTest/App.axaml.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
#if (CommunityToolkitChosen)
using Avalonia.Data.Core;
using Avalonia.Data.Core.Plugins;
#endif
using Avalonia.Markup.Xaml;
using AvaloniaTest.ViewModels;
using AvaloniaTest.Views;
Expand All @@ -17,6 +21,11 @@ public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
#if (CommunityToolkitChosen)
// Line below is needed to remove Avalonia data validation.
// Without this line you will get duplicate validations from both Avalonia and CT
BindingPlugins.DataValidators.RemoveAt(0);
#endif
desktop.MainWindow = new MainWindow
{
DataContext = new MainViewModel()
Expand Down
8 changes: 6 additions & 2 deletions templates/csharp/xplat/AvaloniaTest/AvaloniaTest.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@
<ItemGroup>
<PackageReference Include="Avalonia" Version="$(AvaloniaVersion)" />
<PackageReference Include="Avalonia.Themes.Fluent" Version="$(AvaloniaVersion)" />
<PackageReference Include="Avalonia.Fonts.Inter" Version="$(AvaloniaVersion)" />
<PackageReference Include="Avalonia.ReactiveUI" Version="$(AvaloniaVersion)" />
<PackageReference Include="Avalonia.Fonts.Inter" Version="$(AvaloniaVersion)" />
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="$(AvaloniaVersion)" />
<!--#if (ReactiveUIToolkitChosen) -->
<PackageReference Include="Avalonia.ReactiveUI" Version="$(AvaloniaVersion)" />
<!--#elif (CommunityToolkitChosen)-->
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.1" />
<!--#endif -->
</ItemGroup>
</Project>
15 changes: 14 additions & 1 deletion templates/csharp/xplat/AvaloniaTest/ViewModels/MainViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
namespace AvaloniaTest.ViewModels;
#if (CommunityToolkitChosen)
using CommunityToolkit.Mvvm.ComponentModel;
#endif

namespace AvaloniaTest.ViewModels;

#if (CommunityToolkitChosen)
public partial class MainViewModel : ViewModelBase
#else
public class MainViewModel : ViewModelBase
#endif
{
#if (CommunityToolkitChosen)
[ObservableProperty]
private string _greeting = "Welcome to Avalonia!";
#else
#pragma warning disable CA1822 // Mark members as static
public string Greeting => "Welcome to Avalonia!";
#pragma warning restore CA1822 // Mark members as static
#endif
}
12 changes: 10 additions & 2 deletions templates/csharp/xplat/AvaloniaTest/ViewModels/ViewModelBase.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
using ReactiveUI;
#if (CommunityToolkitChosen)
using CommunityToolkit.Mvvm.ComponentModel;
#elif (ReactiveUIToolkitChosen)
using ReactiveUI;
#endif

namespace AvaloniaTest.ViewModels;

public class ViewModelBase : ReactiveObject
#if (CommunityToolkitChosen)
public abstract class ViewModelBase : ObservableObject
#elif (ReactiveUIToolkitChosen)
public abstract class ViewModelBase : ReactiveObject
#endif
{
}
1 change: 1 addition & 0 deletions templates/fsharp/app-mvvm/ViewModels/ViewModelBase.fs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ open CommunityToolkit.Mvvm.ComponentModel
open ReactiveUI
#endif

[<AbstractClass>]
type ViewModelBase() =
#if (CommunityToolkitChosen)
inherit ObservableObject()
Expand Down
5 changes: 4 additions & 1 deletion templates/fsharp/xplat/.template.config/dotnetcli.host.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@
"UseCompiledBindings": {
"longName": "compiled-bindings"
},
"MVVMToolkit": {
"longName": "mvvm"
},
"RemoveViewLocator": {
"longName": "remove-view-locator"
}
},
"usageExamples": [
""
"--mvvm communitytoolkit"
]
}
7 changes: 7 additions & 0 deletions templates/fsharp/xplat/.template.config/ide.host.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@
},
"isVisible": true
},
{
"id": "MVVMToolkit",
"name": {
"text": "MVVM Toolkit"
},
"isVisible": true
},
{
"id": "UseCompiledBindings",
"name": {
Expand Down
24 changes: 24 additions & 0 deletions templates/fsharp/xplat/.template.config/template.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,30 @@
"replaces": "FrameworkParameter",
"defaultValue": "net8.0"
},
"MVVMToolkit": {
"type": "parameter",
"description": "MVVM toolkit to use in the template.",
"datatype": "choice",
"choices": [
{
"choice": "ReactiveUI",
"description": "Choose ReactiveUI as MVVM toolkit in the template."
},
{
"choice": "CommunityToolkit",
"description": "Choose CommunityToolkit as MVVM toolkit in the template."
}
],
"defaultValue": "ReactiveUI"
},
"ReactiveUIToolkitChosen": {
"type": "computed",
"value": "(MVVMToolkit == \"ReactiveUI\")"
},
"CommunityToolkitChosen": {
"type": "computed",
"value": "(MVVMToolkit == \"CommunityToolkit\")"
},
"AvaloniaVersion": {
"type": "parameter",
"description": "The target version of Avalonia NuGet packages.",
Expand Down
4 changes: 4 additions & 0 deletions templates/fsharp/xplat/AvaloniaTest.Android/Activities.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ namespace AvaloniaTest.Android
open Android.App
open Android.Content.PM
open Avalonia
#if (ReactiveUIToolkitChosen)
open Avalonia.ReactiveUI
#endif
open Avalonia.Android
open AvaloniaTest

Expand All @@ -19,4 +21,6 @@ type MainActivity() =
override _.CustomizeAppBuilder(builder) =
base.CustomizeAppBuilder(builder)
.WithInterFont()
#if (ReactiveUIToolkitChosen)
.UseReactiveUI()
#endif
5 changes: 4 additions & 1 deletion templates/fsharp/xplat/AvaloniaTest.Browser/Program.fs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
open System.Runtime.Versioning
open Avalonia
open Avalonia.Browser
#if (ReactiveUIToolkitChosen)
open Avalonia.ReactiveUI

#endif
open AvaloniaTest

module Program =
Expand All @@ -19,7 +20,9 @@ module Program =
task {
do! (buildAvaloniaApp()
.WithInterFont()
#if (ReactiveUIToolkitChosen)
.UseReactiveUI()
#endif
.StartBrowserAppAsync("out"))
}
|> ignore
Expand Down
4 changes: 4 additions & 0 deletions templates/fsharp/xplat/AvaloniaTest.Desktop/Program.fs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
namespace AvaloniaTest.Desktop
open System
open Avalonia
#if (ReactiveUIToolkitChosen)
open Avalonia.ReactiveUI
#endif
open AvaloniaTest

module Program =
Expand All @@ -13,7 +15,9 @@ module Program =
.UsePlatformDetect()
.WithInterFont()
.LogToTrace(areas = Array.empty)
#if (ReactiveUIToolkitChosen)
.UseReactiveUI()
#endif

[<EntryPoint; STAThread>]
let main argv =
Expand Down
6 changes: 5 additions & 1 deletion templates/fsharp/xplat/AvaloniaTest.iOS/AppDelegate.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ namespace AvaloniaTest.iOS
open Foundation
open Avalonia
open Avalonia.iOS
#if (ReactiveUIToolkitChosen)
open Avalonia.ReactiveUI
#endif

// The UIApplicationDelegate for the application. This class is responsible for launching the
// User Interface of the application, as well as listening (and optionally responding) to
Expand All @@ -13,4 +15,6 @@ type [<Register("AppDelegate")>] AppDelegate() =
override _.CustomizeAppBuilder(builder) =
base.CustomizeAppBuilder(builder)
.WithInterFont()
.UseReactiveUI()
#if (ReactiveUIToolkitChosen)
.UseReactiveUI()
#endif
Loading