diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index 6d349e4..39a989f 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -19,12 +19,22 @@ - + + + + + + + + + + + diff --git a/src/ReactiveUI.SourceGenerators.slnx b/src/ReactiveUI.SourceGenerators.slnx index 00f856f..4adf8d0 100644 --- a/src/ReactiveUI.SourceGenerators.slnx +++ b/src/ReactiveUI.SourceGenerators.slnx @@ -9,7 +9,25 @@ - + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/ReactiveUI.SourceGenerators/IViewFor/IViewForGenerator.Execute.cs b/src/ReactiveUI.SourceGenerators/IViewFor/IViewForGenerator.Execute.cs index 812c50a..8246ca0 100644 --- a/src/ReactiveUI.SourceGenerators/IViewFor/IViewForGenerator.Execute.cs +++ b/src/ReactiveUI.SourceGenerators/IViewFor/IViewForGenerator.Execute.cs @@ -93,7 +93,7 @@ internal static CompilationUnitSyntax GetIViewForWpfWinUiUno(IViewForInfo iViewF writer.WriteLine("DependencyProperty.Register("); writer.WriteLine("nameof(ViewModel),"); writer.WriteLine($"typeof({iViewForInfo.ViewModelTypeName}),"); - writer.WriteLine($"typeof(IViewFor<{iViewForInfo.ViewModelTypeName}>),"); + writer.WriteLine($"typeof({iViewForInfo.ClassName}),"); writer.WriteLine("new PropertyMetadata(null));"); writer.WriteLine(); @@ -213,6 +213,7 @@ internal static CompilationUnitSyntax GetIViewForAvalonia(IViewForInfo iViewForI [ UsingDirective(ParseName("System")), UsingDirective(ParseName("ReactiveUI")), + UsingDirective(ParseName("Avalonia")), UsingDirective(ParseName("Avalonia.Controls")), ]; @@ -258,7 +259,7 @@ internal static CompilationUnitSyntax GetIViewForAvalonia(IViewForInfo iViewForI writer.WriteLine($"public static readonly StyledProperty<{iViewForInfo.ViewModelTypeName}?> ViewModelProperty ="); writer.Indent++; writer.WriteLine("AvaloniaProperty"); - writer.WriteLine($".Register, {iViewForInfo.ViewModelTypeName}?>(nameof(ViewModel));"); + writer.WriteLine($".Register<{iViewForInfo.ClassName}, {iViewForInfo.ViewModelTypeName}?>(nameof(ViewModel));"); writer.Indent--; writer.WriteLine("/// "); @@ -286,28 +287,31 @@ internal static CompilationUnitSyntax GetIViewForAvalonia(IViewForInfo iViewForI writer.Indent--; writer.WriteLine(Token(SyntaxKind.CloseBraceToken)); writer.WriteLine(); - writer.WriteLine(@" - protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) - { - base.OnPropertyChanged(change); - - if (change.Property == DataContextProperty) - { - if (ReferenceEquals(change.OldValue, ViewModel) - && change.NewValue is null or TViewModel) - { - SetCurrentValue(ViewModelProperty, change.NewValue); - } - } - else if (change.Property == ViewModelProperty) - { - if (ReferenceEquals(change.OldValue, DataContext)) - { - SetCurrentValue(DataContextProperty, change.NewValue); - } - } - } - "); + writer.WriteLine( + $$""" + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + + if (change.Property == DataContextProperty) + { + if (ReferenceEquals(change.OldValue, ViewModel) + && change.NewValue is null or {{iViewForInfo.ViewModelTypeName}}) + { + SetCurrentValue(ViewModelProperty, change.NewValue); + } + } + else if (change.Property == ViewModelProperty) + { + if (ReferenceEquals(change.OldValue, DataContext)) + { + SetCurrentValue(DataContextProperty, change.NewValue); + } + } + } + + """); writer.Indent--; writer.WriteLine(Token(SyntaxKind.CloseBraceToken)); writer.Indent--; diff --git a/src/TestApps/TestAvaloniaApplication.Desktop/Program.cs b/src/TestApps/TestAvaloniaApplication.Desktop/Program.cs new file mode 100644 index 0000000..a433497 --- /dev/null +++ b/src/TestApps/TestAvaloniaApplication.Desktop/Program.cs @@ -0,0 +1,32 @@ +// Copyright (c) 2024 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +using System; + +using Avalonia; +using Avalonia.ReactiveUI; + +namespace AvaloniaApplication1.Desktop; + +/// +/// Program. +/// +internal static class Program +{ + // Initialization code. Don't use any Avalonia, third-party APIs or any + // SynchronizationContext-reliant code before AppMain is called: things aren't initialized + // yet and stuff might break. + [STAThread] + public static void Main(string[] args) => BuildAvaloniaApp() + .StartWithClassicDesktopLifetime(args); + + // Avalonia configuration, don't remove; also used by visual designer. + public static AppBuilder BuildAvaloniaApp() + => AppBuilder.Configure() + .UsePlatformDetect() + .WithInterFont() + .LogToTrace() + .UseReactiveUI(); +} diff --git a/src/TestApps/TestAvaloniaApplication.Desktop/TestAvaloniaApplication.Desktop.csproj b/src/TestApps/TestAvaloniaApplication.Desktop/TestAvaloniaApplication.Desktop.csproj new file mode 100644 index 0000000..2556b19 --- /dev/null +++ b/src/TestApps/TestAvaloniaApplication.Desktop/TestAvaloniaApplication.Desktop.csproj @@ -0,0 +1,20 @@ + + + WinExe + + net8.0 + enable + true + app.manifest + false + + + + + + + + + + diff --git a/src/TestApps/TestAvaloniaApplication.Desktop/app.manifest b/src/TestApps/TestAvaloniaApplication.Desktop/app.manifest new file mode 100644 index 0000000..e0ce8d0 --- /dev/null +++ b/src/TestApps/TestAvaloniaApplication.Desktop/app.manifest @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + diff --git a/src/TestApps/TestAvaloniaApplication/App.axaml b/src/TestApps/TestAvaloniaApplication/App.axaml new file mode 100644 index 0000000..9cbf330 --- /dev/null +++ b/src/TestApps/TestAvaloniaApplication/App.axaml @@ -0,0 +1,10 @@ + + + + + + + diff --git a/src/TestApps/TestAvaloniaApplication/App.axaml.cs b/src/TestApps/TestAvaloniaApplication/App.axaml.cs new file mode 100644 index 0000000..7b3403b --- /dev/null +++ b/src/TestApps/TestAvaloniaApplication/App.axaml.cs @@ -0,0 +1,51 @@ +// Copyright (c) 2024 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Markup.Xaml; + +using AvaloniaApplication1.ViewModels; +using AvaloniaApplication1.Views; + +namespace AvaloniaApplication1; + +/// +/// App. +/// +/// +public partial class App : Application +{ + /// + /// Initializes the application by loading XAML etc. + /// + public override void Initialize() + { + AvaloniaXamlLoader.Load(this); + } + + /// + /// Called when [framework initialization completed]. + /// + public override void OnFrameworkInitializationCompleted() + { + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + desktop.MainWindow = new MainWindow + { + DataContext = new MainViewModel() + }; + } + else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform) + { + singleViewPlatform.MainView = new MainView + { + DataContext = new MainViewModel() + }; + } + + base.OnFrameworkInitializationCompleted(); + } +} diff --git a/src/TestApps/TestAvaloniaApplication/Assets/avalonia-logo.ico b/src/TestApps/TestAvaloniaApplication/Assets/avalonia-logo.ico new file mode 100644 index 0000000..da8d49f Binary files /dev/null and b/src/TestApps/TestAvaloniaApplication/Assets/avalonia-logo.ico differ diff --git a/src/TestApps/TestAvaloniaApplication/TestAvaloniaApplication.csproj b/src/TestApps/TestAvaloniaApplication/TestAvaloniaApplication.csproj new file mode 100644 index 0000000..ddad94e --- /dev/null +++ b/src/TestApps/TestAvaloniaApplication/TestAvaloniaApplication.csproj @@ -0,0 +1,25 @@ + + + net8.0 + enable + latest + false + + + + + + + + + + + + + + + + + + + diff --git a/src/TestApps/TestAvaloniaApplication/ViewModels/MainViewModel.cs b/src/TestApps/TestAvaloniaApplication/ViewModels/MainViewModel.cs new file mode 100644 index 0000000..bc7a7e0 --- /dev/null +++ b/src/TestApps/TestAvaloniaApplication/ViewModels/MainViewModel.cs @@ -0,0 +1,23 @@ +// Copyright (c) 2024 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +namespace AvaloniaApplication1.ViewModels; + +/// +/// MainViewModel. +/// +/// +public class MainViewModel : ViewModelBase +{ + /// + /// Gets the greeting. + /// + /// + /// The greeting. + /// +#pragma warning disable CA1822 // Mark members as static + public string Greeting => "Welcome to Avalonia!"; +#pragma warning restore CA1822 // Mark members as static +} diff --git a/src/TestApps/TestAvaloniaApplication/ViewModels/ViewModelBase.cs b/src/TestApps/TestAvaloniaApplication/ViewModels/ViewModelBase.cs new file mode 100644 index 0000000..dd371b7 --- /dev/null +++ b/src/TestApps/TestAvaloniaApplication/ViewModels/ViewModelBase.cs @@ -0,0 +1,16 @@ +// Copyright (c) 2024 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +using ReactiveUI; + +namespace AvaloniaApplication1.ViewModels; + +/// +/// ViewModelBase. +/// +/// +public class ViewModelBase : ReactiveObject +{ +} diff --git a/src/TestApps/TestAvaloniaApplication/Views/MainView.axaml b/src/TestApps/TestAvaloniaApplication/Views/MainView.axaml new file mode 100644 index 0000000..b1d11e0 --- /dev/null +++ b/src/TestApps/TestAvaloniaApplication/Views/MainView.axaml @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/src/TestApps/TestAvaloniaApplication/Views/MainView.axaml.cs b/src/TestApps/TestAvaloniaApplication/Views/MainView.axaml.cs new file mode 100644 index 0000000..2042338 --- /dev/null +++ b/src/TestApps/TestAvaloniaApplication/Views/MainView.axaml.cs @@ -0,0 +1,25 @@ +// Copyright (c) 2024 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +using Avalonia.Controls; + +namespace AvaloniaApplication1.Views; + +/// +/// MainView. +/// +/// +[ReactiveUI.SourceGenerators.IViewFor] +public partial class MainView : UserControl +{ + /// + /// Initializes a new instance of the class. + /// + public MainView() + { + InitializeComponent(); + ViewModel = new ViewModels.MainViewModel(); + } +} diff --git a/src/TestApps/TestAvaloniaApplication/Views/MainWindow.axaml b/src/TestApps/TestAvaloniaApplication/Views/MainWindow.axaml new file mode 100644 index 0000000..87e8725 --- /dev/null +++ b/src/TestApps/TestAvaloniaApplication/Views/MainWindow.axaml @@ -0,0 +1,12 @@ + + + diff --git a/src/TestApps/TestAvaloniaApplication/Views/MainWindow.axaml.cs b/src/TestApps/TestAvaloniaApplication/Views/MainWindow.axaml.cs new file mode 100644 index 0000000..3f81182 --- /dev/null +++ b/src/TestApps/TestAvaloniaApplication/Views/MainWindow.axaml.cs @@ -0,0 +1,23 @@ +// Copyright (c) 2024 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +using Avalonia.Controls; + +namespace AvaloniaApplication1.Views; + +/// +/// MainWindow. +/// +/// +public partial class MainWindow : Window +{ + /// + /// Initializes a new instance of the class. + /// + public MainWindow() + { + InitializeComponent(); + } +} diff --git a/src/TestApps/TestMauiApplication/App.xaml b/src/TestApps/TestMauiApplication/App.xaml new file mode 100644 index 0000000..8fb5f38 --- /dev/null +++ b/src/TestApps/TestMauiApplication/App.xaml @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/src/TestApps/TestMauiApplication/App.xaml.cs b/src/TestApps/TestMauiApplication/App.xaml.cs new file mode 100644 index 0000000..79782f9 --- /dev/null +++ b/src/TestApps/TestMauiApplication/App.xaml.cs @@ -0,0 +1,26 @@ +// Copyright (c) 2024 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +namespace MauiApp1 +{ + /// + /// App. + /// + /// + public partial class App : Application + { + /// + /// Initializes a new instance of the class. + /// + /// + /// To be added. + /// + public App() + { + InitializeComponent(); + MainPage = new AppShell(); + } + } +} diff --git a/src/TestApps/TestMauiApplication/AppShell.xaml b/src/TestApps/TestMauiApplication/AppShell.xaml new file mode 100644 index 0000000..5dd865e --- /dev/null +++ b/src/TestApps/TestMauiApplication/AppShell.xaml @@ -0,0 +1,15 @@ + + + + + + diff --git a/src/TestApps/TestMauiApplication/AppShell.xaml.cs b/src/TestApps/TestMauiApplication/AppShell.xaml.cs new file mode 100644 index 0000000..f115914 --- /dev/null +++ b/src/TestApps/TestMauiApplication/AppShell.xaml.cs @@ -0,0 +1,25 @@ +// Copyright (c) 2024 .NET Foundation and Contributors. All rights reserved. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for full license information. + +namespace MauiApp1 +{ + /// + /// AppShell. + /// + /// + public partial class AppShell : Shell + { + /// + /// Initializes a new instance of the class. + /// + /// + /// To be added. + /// + public AppShell() + { + InitializeComponent(); + } + } +} diff --git a/src/TestApps/TestMauiApplication/MainPage.xaml b/src/TestApps/TestMauiApplication/MainPage.xaml new file mode 100644 index 0000000..4ff41e1 --- /dev/null +++ b/src/TestApps/TestMauiApplication/MainPage.xaml @@ -0,0 +1,36 @@ + + + + + + + +