Xamarin.forms: Custom renderer singleton mode. How do I do this?

Created on 9 Jul 2018  ·  10Comments  ·  Source: xamarin/Xamarin.Forms

Use a custom renderer to control platform-specific controls. Static global classes are singleton mode. How do I do this?

needs-info ❓ question

All 10 comments

Can you please clarify your question and use case scenario?

@pauldipietro XFWebView and XFWebViewRenderer files, I create a singleton like this, each time I execute the OnElementChanged method to create a new object.
TestSingleton.zip

@LeeCenY if I'm understanding you correctly that's really up to you what you want to do with those classes. I'm assuming you're indicating that you don't want to new up a WKWebView every time you navigate to the page? You can store those into your own global structure if you'd like and then just reuse those from the renderer.

The renderer itself though cannot be reused. It's going to be disposed of whenever it's navigated away from.

@pauldipietro I'm sorry! I English is not good, using Google translation: Yes, I do not want to create new WKWebView every time I navigate to the page. So use a Singleton. I use the GetInstance method in XFWebView is not feasible, each time the use of XFWebView.GetInstance () to create, renderer OnElementChanged will be called, so the native control under the renderer will be re created every time, what you say the global structure is, I don't understand. Can you give an example or modify it from my TestSingleton.zip example? Thanks very much

public class XFWebView : View
    {
        private static XFWebView svInstance;
        public static XFWebView GetInstance()
        {
            if (svInstance == null)
            {
                svInstance = new XFWebView();
            }
            return svInstance;
        }
    }

You wouldn't save the XFWebView control. You would reuse the WKWebView inside the renderer

Here's a renderer I made that hopefully answers your question

```C#
using System;

using Xamarin.Forms;
using TestSingleton;
using TestSingleton.iOS;

using System.ComponentModel;
using UIKit;
using Xamarin.Forms.Platform.iOS;
using WebKit;

using Foundation;

[assembly: ExportRenderer(typeof(XFWebView), typeof(XFWebViewRenderer))]
namespace TestSingleton.iOS
{
public class XFWebViewRenderer : ViewRenderer, IWKNavigationDelegate, IWKUIDelegate
{
private XFWebView mvSourceView;

    private static WKWebView svInstance;
    public static WKWebView GetInstance()
    {
        if (svInstance == null)
        {
            WKWebViewConfiguration mvConfiguration = new WKWebViewConfiguration();
            WKPreferences preferences = new WKPreferences();
            preferences.JavaScriptCanOpenWindowsAutomatically = true;
            preferences.JavaScriptEnabled = true;
            preferences.MinimumFontSize = (nfloat)0;
            mvConfiguration.Preferences = preferences;

            WKWebView mvNativeView = new WKWebView(new CoreGraphics.CGRect(0, 0, UIScreen.MainScreen.Bounds.Width, UIScreen.MainScreen.Bounds.Height), mvConfiguration);
            mvNativeView.BackgroundColor = UIColor.Red;
            mvNativeView.NavigationDelegate = new MyDelegate();
            svInstance = mvNativeView;
        }
        return svInstance;
    }

    protected override bool ManageNativeControlLifetime => false;

    protected override void OnElementChanged(ElementChangedEventArgs<XFWebView> e)
    {
        base.OnElementChanged(e);
        if (null == e.NewElement || null != Control)
        {
            return;
        }

        mvSourceView = e.NewElement;

        System.Diagnostics.Debug.WriteLine("Recall every time you create a custom render class");

        var instance = GetInstance();

        SetNativeControl(instance);

        var webViewSourceURL = new NSUrl("https://www.google.com?q=" + Guid.NewGuid().ToString());
        NSMutableUrlRequest request = new NSMutableUrlRequest(webViewSourceURL);
        instance.LoadRequest(request);
    }



    protected override void Dispose(bool disposing)
    {
        Control.RemoveFromSuperview();
        base.Dispose(disposing);
    }

    public class MyDelegate : WKNavigationDelegate
    {
        public override void DidCommitNavigation(WKWebView webView, WKNavigation navigation)
        {
        }

        public override void DidFailNavigation(WKWebView webView, WKNavigation navigation, NSError error)
        {
        }

        public override void DidFinishNavigation(WKWebView webView, WKNavigation navigation)
        {
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
        }
    }
}

}
```

@PureWeen Thanks, I also know this method from your example:

protected override bool ManageNativeControlLifetime => false;

That is to say, PCL does not need private static XFWebView svInstance; it only needs to make global structure in Renderer, is that right?

@LeeCenY are you good? Can we close this ticket?

@PureWeen That is to say, PCL does not need private static XFWebView svInstance; it only needs to make global structure in Renderer, is that right?

Right.

@PureWeen Thanks,Can close this ticket

Was this page helpful?
0 / 5 - 0 ratings