dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
21.63k stars 1.62k forks source link

The key is that you need to cast the PageHandler as IPlatformViewHandler to access the ViewController, as @PureWeen said. To get to the UINavigationItem, you need to look at the ParentViewController at just the right moment in the page's lifecycle. Unfortunately that moment exists somewhere between the page Appearing event and the Loaded event. #22050

Closed mnidhk closed 2 weeks ago

mnidhk commented 2 weeks ago
          The key is that you need to cast the PageHandler as IPlatformViewHandler to access the ViewController, as @PureWeen said. To get to the UINavigationItem, you need to look at the ParentViewController at just the right moment in the page's lifecycle. Unfortunately that moment exists somewhere between the page Appearing event and the Loaded event.

I have been able to approximate the functionality of overriding ViewWillAppear by using the following handler. In my apps I use a base class for each page called CorePage:

public abstract class CorePage : ContentPage { }

public class CorePageHandler : Microsoft.Maui.Handlers.PageHandler
{
    protected override void ConnectHandler(Microsoft.Maui.Platform.ContentView nativeView) {
        base.ConnectHandler(nativeView);
        CorePage.Loaded += OnLoaded;
    }

    protected override void DisconnectHandler(Microsoft.Maui.Platform.ContentView nativeView) {
        CorePage.Loaded -= OnLoaded;
        base.DisconnectHandler(nativeView);
    }

    CorePage CorePage => VirtualView as CorePage;

    void OnLoaded(object sender, EventArgs e) => ManageBarButtons();

    void ManageBarButtons() {
        if (this is IPlatformViewHandler handler
                && handler.ViewController?.ParentViewController?.NavigationItem is UINavigationItem navItem ) {
            List<UIBarButtonItem> rightBarButtons = new();
            List<UIBarButtonItem> leftBarButtons = new(navItem.LeftBarButtonItems ?? Array.Empty<UIBarButtonItem>());

            // manipulate buttons here

            navItem.RightBarButtonItems = rightBarButtons.ToArray();
            navItem.LeftBarButtonItems = leftBarButtons.ToArray();
        }
    }
}

Note that I say approximate, because there can be visual artifacts when manipulating the buttons during the ContentPage.Loaded event. My implementation replaces generated UIBarButtonItem objects with new ones using native UIBarButtonSystemItem and SF Symbols (this is iOS after all). I overcame the timing issue with a hack: I save/remove the ToolbarItem objects in ConnectHandler and add manually created UIBarButtonItem objects during the Loaded event. This approach works, but I'm not a fan.

For the PageRenderer functionality to ultimately be obsoleted, MAUI needs to implement access to the UIViewController during ViewWillAppear in a manner that not only we Xamarin Forms developers are accustomed to, but that is also easily discoverable by new programmers coming to .NET MAUI.

Originally posted by @agendamatic in https://github.com/dotnet/maui/issues/7174#issuecomment-1244019860

mnidhk commented 2 weeks ago

Wrong issue