2

I'm trying to get the height of a web page rendered in a Webview using a Custom Renderer. I've managed to hook into Load_Completed event which correctly fires when the page has fully rendered, but there doesn't seem to be anything exposing the content's height.

What can I use to get this?

Thanks in advance.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Xamarin.Forms.Platform.UWP;
    using Xamarin.Forms;
    using Windows.UI.Xaml.Navigation;
    using Windows.UI.Xaml.Controls;

    [assembly: ExportRenderer(typeof(Xamarin.Forms.WebView), typeof(ExtendedViewWebRenderer))] 
    namespace Project.UWP.CustomRenderers
    {
        public class ExtendedViewWebRenderer : WebViewRenderer
        {

            protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
            {
                base.OnElementChanged(e);
                if (Control != null)
                {
                    Control.LoadCompleted += Load_Completed;
                }
            }

            private void Load_Completed(object sender, Windows.UI.Xaml.Navigation.NavigationEventArgs e)
            {
                var _webView = (Windows.UI.Xaml.Controls.WebView)sender;
               //Grab content's height here
            }

        }
    }
Rexxo
  • 156
  • 3
  • 16
  • This SO answer might help: http://stackoverflow.com/a/29150321/2913599 – jgoldberger - MSFT Oct 14 '16 at 00:02
  • Possible duplicate of [Windows Store WebView rendered html size](http://stackoverflow.com/questions/29127890/windows-store-webview-rendered-html-size) – jgoldberger - MSFT Oct 14 '16 at 00:03
  • @jgoldberger is Javascript the only way of capturing the height of the page rendered? – Rexxo Oct 14 '16 at 08:51
  • You may use the method `InvokeScriptAsync` like @jgoldberger says, but it seems you can't avoid js. Here is the sample code you may refer to: https://github.com/elvisxia/WebViewDynamicHeightSample – Scavenger Oct 14 '16 at 09:11
  • Thanks, i've managed to get the JS part of it working, but now it doesn't redraw / rerender the view after i've passed the content height to the webview.height... is there a way to force it to redraw? – Rexxo Oct 14 '16 at 15:45
  • Thanks, think i'm getting somewhere now. Is there an equivalent of scriptnotify for a Xamarin Webview? – Rexxo Oct 17 '16 at 16:09

1 Answers1

2

Here's where I landed. Know very little about UWP so please feel free to suggest improvements, but this seems to work fairly well. Note that in my case I'm passing an HTML string from my custom control to render/"navigate" to, if you're going to an actual page just use Control.Navigate(Uri source) instead.

public class ExtendedWebViewRenderer : ViewRenderer<ExtendedWebView, Windows.UI.Xaml.Controls.WebView>
    {
        protected override void OnElementChanged(ElementChangedEventArgs<ExtendedWebView> e)
        {
            try
            {
                base.OnElementChanged(e);

                if (e.OldElement != null && Control != null)
                {
                    Control.NavigationCompleted -= OnWebViewNavigationCompleted;
                }

                if (e.NewElement != null)
                {
                    if (Control == null)
                    {
                        SetNativeControl(new Windows.UI.Xaml.Controls.WebView());
                    }

                    Control.NavigationCompleted += OnWebViewNavigationCompleted;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error at ExtendedWebViewRenderer OnElementChanged: " + ex.Message);
            }
        }

        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

        // update this based on your custom webview control and what you want it to do
            if (Element is ExtendedWebView element && e.PropertyName.Equals(nameof(ExtendedWebView.Html)) && !string.IsNullOrWhiteSpace(element.Html))
                Control.NavigateToString(element.Html); 
        }

        private async void OnWebViewNavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
        {
            if (!args.IsSuccess)
                return;

            var heightString = await Control.InvokeScriptAsync("eval", new[] {"document.body.scrollHeight.toString()" });
            if (int.TryParse(heightString, out int height))
            {
                Element.HeightRequest = height;
            }

            var widthString = await Control.InvokeScriptAsync("eval", new[] {"document.body.scrollWidth.toString()" });
            if (int.TryParse(widthString, out int width))
            {
                Element.WidthRequest = width;
            }
        }
    }
Mark Z.
  • 2,127
  • 16
  • 33