Search code examples
c#mauimaui-blazor

Reload BlazorWebView in a MAUI xaml page


I have a basic MAUI Blazor Hybrid app with one xaml page: MainPage.xaml and in it there is one component, the BlazorWebView

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
    x:Class="MyApp.MainPage"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:ios="clr-namespace:Microsoft.Maui.Controls.PlatformConfiguration.iOSSpecific;assembly=Microsoft.Maui.Controls"
    xmlns:local="clr-namespace:MyApp"
    ios:Page.UseSafeArea="True"
    BackgroundColor="{DynamicResource PageBackgroundColor}">

    <BlazorWebView x:Name="blazorWebView" HostPage="wwwroot/index.html">
        <BlazorWebView.RootComponents>
            <RootComponent ComponentType="{x:Type local:Components.Routes}" Selector="#app" />
        </BlazorWebView.RootComponents>
    </BlazorWebView>

</ContentPage>

I would like to be able to reload the BlazorWebView's content (load it as though I just arrived at the MainPage.xaml)

I tried doing

var hostPage = blazorWebView.HostPage;
blazorWebView.HostPage = null;
blazorWebView.HostPage = hostPage;

but this had no effect.

Even setting blazorWebView = null; did nothing


Solution

  • In my test, the blazorwebview's default url is https://0.0.0.0/, so you can call the platform code to reload the url. But to make the url always correct, I get it programmatically.

    In the MainPage:

    public partial class MainPage : ContentPage
        {
            public string url;
            public BlazorWebView view;
            public MainPage()
            {
                InitializeComponent();
                view = blazorWebView;
            }
            public void Reload()
            {
    #if Android
                var androidweb = blazorWebView.Handler.PlatformView as Android.Webkit.WebView;
                androidweb.LoadUrl(url);
    #elif WINDOWS
                var windowweb = blazorWebView.Handler.PlatformView as Microsoft.UI.Xaml.Controls.WebView2;
                windowweb.Source = new Uri(url);
    #elif IOS
                var iosweb = blazorWebView.Handler.PlatformView as WebKit.WKWebView;
                iosweb.LoadRequest(new Foundation.NSUrlRequest(new Uri(url)));
    #endif
            }
        }
    

    In the Home.Razor:

    @code{
       protected override void OnInitialized()
       {
           base.OnInitialized();
    #if Android
            var androidweb = (App.Current.MainPage as MainPage).view.Handler.PlatformView as Android.Webkit.WebView;
            (App.Current.MainPage as MainPage).url = androidweb.Url;
    #elif WINDOWS
            var windowweb = (App.Current.MainPage as MainPage).view.Handler.PlatformView as Microsoft.UI.Xaml.Controls.WebView2;
            (App.Current.MainPage as MainPage).url = windowweb.Source.ToString();
    #elif IOS
            var iosweb = (App.Current.MainPage as MainPage).view.Handler.PlatformView as WebKit.WKWebView;
            (App.Current.MainPage as MainPage).url = iosweb.Url.ToString();
    #endif
       }
    }
    

    And then you can call the Reload method to reload the blazor webview. Why I get the default Url in the Home.Razor is I can't get it in the MainPage's life cycle method on the windows platform.

    =====================

    I get another easier way to do this. You can create a new BlazorWebView and set it as the Page's Content:

    public partial class MainPage : ContentPage
        {
            public MainPage()
            {
                InitializeComponent();
            }
            public void Reload()
            {
                var newview = new BlazorWebView() { HostPage = "wwwroot/index.html" };
                newview.RootComponents.Add(new RootComponent() { Selector = "#app", ComponentType = typeof(Routes) });
                this.Content = newview;
    
            }
        }