Caliburn.Micro icon indicating copy to clipboard operation
Caliburn.Micro copied to clipboard

MAUI support is completely broken in version 5

Open claytonone opened this issue 1 year ago • 10 comments

It currently doesn't seem possible to create a working MAUI app with Caliburn Micro 5 (5.0.181-beta also tried with latest myget version 5.0.196-beta). I've tried using two different approaches:

using DisplayRootView

This is what we used to do in Xamarin Forms, however in MAUI this doesn't work at all. View models never get resolved from the container and the flyout page never shows it's menu icon. It does correctly register a navigation page though.

using DisplayRootViewForAsync

This has different problems but view models do get resolved from the container. However it never registers a navigation page instance so navigation between pages is impossible.

Other problems

The below used to work in an earlier preview version but now Bind.Model no longer works at all.

cal:Bind.Model="{Binding MainViewModel}"

I've created a very simple repro where this can easily be observed. https://github.com/claytonone/CaliburnMicroMaui

claytonone avatar Feb 10 '25 12:02 claytonone

@claytonone I will look at it

vb2ae avatar Feb 10 '25 15:02 vb2ae

Created a pull request into your sample with a fix. I removed the tizen support and added code for the other platforms to work with caliburn.micro.

the change that fixed it was this

	<PackageReference Include="Microsoft.Maui.Controls" Version="8.0.92" />
	<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="8.0.92" />  

vb2ae avatar Feb 11 '25 01:02 vb2ae

please close the bug if it fixed your issue

vb2ae avatar Feb 11 '25 01:02 vb2ae

@vb2ae Thanks for looking into this but that doesn't seem to have fixed it (at least on Android and iOS).

Try pressing the increment button - notice that it doesn't call the function in the view model and that it doesn't update the label text.

Also try injecting INavigationService to navigate to a different view model with NavigateToViewModelAsync. Calling it does nothing. (I've updated the sample to show this)

claytonone avatar Feb 11 '25 09:02 claytonone

Sorry I could not get sample to run so I was thinking that was only issue. Looking at the button in Microsoft documentation. I did not see a Tapped event. It works if you use Clicked

https://learn.microsoft.com/en-us/dotnet/api/microsoft.maui.controls.button?view=net-maui-9.0

 <Button Text="Increment" cal:Message.Attach="[Event Clicked] = [Action Increment]" />

Actually it works on Windows get an error on android

vb2ae avatar Feb 11 '25 11:02 vb2ae

Sorry yes typo by me, it should have been Clicked. (I've updated the sample)

That makes the click handler work but the label binding from the viewmodel to the view still doesn't work and neither does the navigation service.

Regarding the navigation service I notice that PrepareViewFirst never gets called hence it never getting added to the container

claytonone avatar Feb 11 '25 11:02 claytonone

For the Navigation Service you need to register the NavigationService with dependency injection to have something to inject into the MainViewModel constructor.

Change the following in the HomeView.xaml

<FlyoutPage.Detail>
    <NavigationPage cal:Message.Attach="[Loaded] = [RegisterNavigationService($Source)];">
    </NavigationPage>
</FlyoutPage.Detail>

in the HomeViewModel make the following changes

public class HomeViewModel : Screen
{
    public MainViewModel MainViewModel { get; set; }
    private readonly SimpleContainer _simpleContainer;

    public HomeViewModel(MainViewModel mainViewModel, SimpleContainer simpleContainer)
    {
        _simpleContainer = simpleContainer;
        MainViewModel = mainViewModel;
        MainViewModel.ConductWith(this);
    }

    public void RegisterNavigationService(NavigationPage navigationPage)
    {
        var navigationService = new NavigationPageAdapter(navigationPage);
        _simpleContainer.Instance<INavigationService>(navigationService);

        navigationService.NavigateToViewModelAsync<MainViewModel>();
    }
}

vb2ae avatar Feb 12 '25 17:02 vb2ae

Thanks. this would work in some situations but not all. This method registers the navigation service pretty late so any view models that were created at the same time as HomeViewModel would not receive it. That's easy to replicate in this example because MainViewModel needs the navigation service but it hasn't been registered at the point that it is created.

The Xamarin Forms version of Caliburn Micro had a much simpler way of doing this. You simply added an override of PrepareViewFirst in the App class which ensured it got registered before items were added to the container. Why can we not use this method in Maui as that code still exists in the MauiApplication class?

protected override void PrepareViewFirst(NavigationPage navigationPage)
{
    _container.Instance<INavigationService>(new NavigationPageAdapter(navigationPage));
}

Also can you please look into why cal:Bind.Model is not working properly. In my example the binding works from the view to the view model but not from the view model to the view.

Thanks!

claytonone avatar Feb 12 '25 20:02 claytonone

The PrepareViewFirst does exist in Caliburn.Micro.Maui. It creates a NavigationPage as the start page. You can create and register the INavigationService with SimpleContainer or the DependencyInjection library of your choice so it can be injected into the constructor of your view model. Keep in mind it will change the whole page. When you included the flyout on the page I thought you wanted the navigation to work on the flyout page

vb2ae avatar Feb 14 '25 14:02 vb2ae

If you use PrepareViewFirst with MAUI and the root page is a flyout page then the flyout menu is never displayed. That did used to work perfectly fine in my Xamarin app before I migrated it over to MAUI. So something has definitely regressed or changed between the two versions.

claytonone avatar Feb 18 '25 09:02 claytonone