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

MauiReactor 3 based on .NET MAUI 9 #263

Open
adospace opened this issue Nov 14, 2024 · 6 comments
Open

MauiReactor 3 based on .NET MAUI 9 #263

adospace opened this issue Nov 14, 2024 · 6 comments

Comments

@adospace
Copy link
Owner

adospace commented Nov 14, 2024

MauiReactor 3 targeting .NET 9 is here!

Please check it out:

  1. for the latest sources clone the https://github.com/adospace/reactorui-maui/tree/beta-3-net9-1 branch
  2. if you just want to link the package point to Nuget beta 3 versions https://www.nuget.org/packages/Reactor.Maui

This ticket will track all my progress and allow me to collect your suggestions and feedbacks.

Currently, MauiReactor 3.0.1-beta works pretty fine and contains most of the new features of MAUI .net 9 release, including the new controls TitleBar and HybridWebView.

Also, there is a breaking change required to load the XAML resources in case you use styles from an XAML dictionary: no reflection is involved and XAML resources are precompiled just like the normal MAUI application.
This is how you can continue to use the XAML resources in MauiReactor:
https://github.com/adospace/reactorui-maui/tree/beta-3-net9-1/samples/MauiReactor.TestApp

More info and documentation coming soon.

@adospace adospace pinned this issue Nov 14, 2024
@adospace
Copy link
Owner Author

New feature in MauiReactor 3, FormattedString() has now full fluent syntax:

Label(
    FormattedString(
        Span("Red bold, ", Colors.Red, FontAttributes.Bold),
        Span("default, ",
            TapGestureRecognizer(async () => await ContainerPage!.DisplayAlert("Tapped", "This is a tapped Span.", "OK"))
            ),
        Span("italic small.", FontAttributes.Italic, 14)
        )
    )

it was:

.FormattedText(()=>
{
    //of course FomattedText here, being static, can be created as a static variable and passed to Label().FormattedText(myStaticFormattedText)
    MauiControls.FormattedString formattedString = new();
    formattedString.Spans.Add(new MauiControls.Span { Text = "Red bold, ", TextColor = Colors.Red, FontAttributes = FontAttributes.Bold });

    MauiControls.Span span = new() { Text = "default, " };
    span.GestureRecognizers.Add(new MauiControls.TapGestureRecognizer { Command = new Command(async () => await ContainerPage!.DisplayAlert("Tapped", "This is a tapped Span.", "OK")) });
    formattedString.Spans.Add(span);
    formattedString.Spans.Add(new MauiControls.Span { Text = "italic small.", FontAttributes = FontAttributes.Italic, FontSize = 14 });

    return formattedString;
})

@adospace
Copy link
Owner Author

adospace commented Nov 22, 2024

New feature coming to MauiReactor 3

MauiReactor 3 will support async handlers for events.

For example, you'll be able to write something like this:

public override VisualNode Render()
    => ContentPage("Counter Sample",
        VStack(
            Button("Click To Increment")
                .OnClicked(IncrementCounter)
        )
    );

async Task IncrementCounter()
{
     //...
}

The button doesn't call the handler again until the first invocation is completed (of course you can freely disable the button with a specific state property while the task is running).

For example

class State
{
    public bool IsBusy{get;set;}
}

public override VisualNode Render()
    => ContentPage("Counter Sample",
        VStack(
            Button("Click To Increment")
                .IsEnabled(!State.IsBusy)
                .OnClicked(IncrementCounter)
        )
    );

async Task IncrementCounter()
{
    SetState(s => s.IsBusy = true);
     //... make async calls
    SetState(s => s.IsBusy = false);
}

Other improvements are also coming to the supported signatures that should further simplify your code.

Please check it out in version 3.0.5-beta

@adospace
Copy link
Owner Author

Hot-reload improvement in MauiReactor 3

In MauiReactor 2, if you're using injected services in components, you are surely aware that service interface/implementation types must be defined in a separate assembly to allow hot-reload to work.

For example, considering this component and the ICounterService:

partial class CounterWithServicePage : Component<CounterPageState>
{
    [Inject]
    IncrementService _incrementService;

    public override VisualNode Render() 
        => ContentPage("Counter Sample",
            VStack(
                Label($"Counter: {State.Counter}"),
                Button("Click To Increment", () => SetState(s => s.Counter = _incrementService.Increment(s.Counter)))
            )
        );
}

The IncrementService must be defined in a different assembly otherwise the hot-reload won't work.

Starting 3.0.7-beta, hot-reload works also for injected services that are defined in the same assembly of the application.

You have to create one or more static functions that accept IServiceCollection decorated with the attribute [ComponentService] where you register your services. These functions are called automatically during the hot-reload process to register your services in the new assembly loaded at runtime.

I.e.:

    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        //your initialization code for the AppBuilder...
      
        //Warp your service registration in a separate function
        RegisterServices(builder.Services);

        return builder.Build();
    }

    [ComponentServices]
    static void RegisterServices(IServiceCollection services)
    {
#if DEBUG
        services.AddLogging(configure => configure.AddDebug());
#endif

        services.AddSingleton<ProjectRepository>();
        services.AddSingleton<TaskRepository>();
        services.AddSingleton<CategoryRepository>();
        services.AddSingleton<TagRepository>();
        services.AddSingleton<SeedDataService>();
        services.AddSingleton<ModalErrorHandler>();
    }

@adospace
Copy link
Owner Author

Breaking-change for hot-reload

Starting from 3.0.9, hot-reload must be enabled using the new .NET 9+ feature switch (https://github.com/dotnet/designs/blob/main/accepted/2020/feature-switch.md).

You can opt-in hot-reload enabling the switch "MauiReactor.HotReload".

For example add the following to your project definition to enable hot-reload:

  <ItemGroup>
    <RuntimeHostConfigurationOption Include="MauiReactor.HotReload" Value="true" Trim="true" />
  </ItemGroup>

This is preliminary work to make MauiReactor 3 fully AOT-compatible and trimmable. In the near future, it will be enough to disable this switch in release mode to trim out all the code required for hot reload that may not be compatible with AOT requirements.

Using .NET 9 feature switch also allows an easier integration of MauiReactor in CI environments.

Lastly please note that I'm heavily working on this stuff so things may change in the future.

@adospace
Copy link
Owner Author

AOT compliance with version 3.0.12-beta

I'm really glad to share with you that MauiReactor since version 3.0.12-beta is fully AOT compatible.

If you want to compile your application with MauiReactor to a native iOS or Mac Catalyst application please follow the official guidelines:

https://learn.microsoft.com/en-us/dotnet/maui/deployment/nativeaot?view=net-maui-9.0

and set MauiReactor to trim out the hot-reload module in release mode adding these lines to your project definition:

<ItemGroup Condition="'$(Configuration)'=='Release'">
    <RuntimeHostConfigurationOption Include="MauiReactor.HotReload" Value="false" Trim="true" />
</ItemGroup>

@adospace
Copy link
Owner Author

adospace commented Jan 16, 2025

MauiReactor 3 for .NET 9 is coming next week!

I've already built a production app with it for my client and it's going very well.

To give you more context:

  1. LOB application with 10 screens, full of controls, maps, tab bars, and basic animations.
  2. Login with Azure Ad and Login.gov
  3. Data synchronization to an Aspnet core backend through CoreSync
  4. Local database is managed with ReactorData (Ef Core+Sqlite)
  5. Tested so far by several users before going to production at the end of Jan 2025 will be adopted for daily work by 40-50

For questions, ideas, polls, or show to the world your great app, I've opened the discussion board here:

https://github.com/adospace/reactorui-maui/discussions

Come on don't be shy!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant