kumar Sudheer
kumar Sudheer

Reputation: 705

Calling C# function from AngularJs script in Xamarin Forms PCL Universal Windows Application

I am developing a cross platform xamarin forms application. I have created a Portable Cross-Platform App, in which I am trying to open local HTML pages in webview. For calling C# function from Angularjs, I have implemented hybrid web view concepts.

My Angularjs Function

 $scope.SyncServerJobs = function () {
    //$scope.loadActList();
   window.CommInterface.syncServerJobs("");
}

In My Universal Windows Project

 public class HybridWebViewRenderer : ViewRenderer<HybridWebView, Windows.UI.Xaml.Controls.WebView>
{
    public CommInterface communicator = new CommInterface();

    const string JavaScriptFunction = "function invokeCSharpAction(data){window.external.notify(data);}";
    const string SyncServerJobs = "function syncServerJobs(data){window.external.notify(data);}";

    protected override void OnElementChanged(ElementChangedEventArgs<HybridWebView> e)
    {
        base.OnElementChanged(e);

        if (Control == null)
        {
            var webView = new WebView();
            webView.Settings.IsJavaScriptEnabled = true;
            SetNativeControl(webView);
        }
        if (e.OldElement != null)
        {
            Control.NavigationStarting -= OnWebViewNavigationStarted;
            Control.NavigationCompleted -= OnWebViewNavigationCompleted;
            Control.ScriptNotify -= OnWebViewScriptNotify;
        }
        if (e.NewElement != null)
        {
            Control.NavigationStarting += OnWebViewNavigationStarted;
            Control.NavigationCompleted += OnWebViewNavigationCompleted;
            Control.ScriptNotify += OnWebViewScriptNotify;
            Control.Source = new Uri(string.Format("ms-appx-web:///Content//{0}", Element.Uri));
        }
    }

    private void OnWebViewNavigationStarted(WebView sender, WebViewNavigationStartingEventArgs args)
    {
        if (Control != null && Element != null)
        {
            communicator = new CommInterface();
            Control.AddWebAllowedObject("CommInterface", communicator);
        }
    }

    async void OnWebViewNavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
    {
        if (args.IsSuccess)
        {
            // Inject JS script
            await Control.InvokeScriptAsync("eval", new[] { JavaScriptFunction });
            await Control.InvokeScriptAsync("eval", new[] { SyncServerJobs });
        }
    }

    void OnWebViewScriptNotify(object sender, NotifyEventArgs e)
    {
        Element.InvokeAction(e.Value);
    }
}

My commInterface class

 [AllowForWeb]
public sealed class CommInterface
{
    readonly WeakReference<HybridWebViewRenderer> hybridWebViewRenderer;

    public CommInterface()
    {

    }

    public void syncServerJobs(string data)
    {
        HybridWebViewRenderer hybridRenderer;
        if (hybridWebViewRenderer != null && hybridWebViewRenderer.TryGetTarget(out hybridRenderer))
        {
            hybridRenderer.Element.SyncServerJobs(data);
        }
    }
}

As like in Android project I am using CommInterface class to communicate with database class in Portable library. But in my Universal Windows project, I am not able to communicate with Csharp functions to run CSharp CRUD functions. How can I call the CSharp function from script?

Upvotes: 0

Views: 1152

Answers (1)

Nico Zhu
Nico Zhu

Reputation: 32775

I am not able to communicate with Csharp functions to run CSharp CRUD functions. How can I call the CSharp function from script?

You have injected JS script after webView navigation Completed. In another words the await Control.InvokeScriptAsync("eval", new[] { JavaScriptFunction }); was declared in JS scope.

Scripts in the web view content can use window.external.notify with a string parameter to send information back to your app. To receive these messages, handle the ScriptNotify event.

So The ScriptNotify event would be triggered when you executed the JavaScriptFunction in JS scope like the follwing code.

<button type="button" onclick="javascript:invokeCSCode($('#name').val());">Invoke C# Code</button>
<br/>
<p id="result">Result:</p>
<script type="text/javascript">
function log(str)
{
    $('#result').text($('#result').text() + " " + str);
}

function invokeCSCode(data) {
    try {
        log("Sending Data:" + data);
        invokeCSharpAction(data);    
    }
    catch (err){
        log(err);
    }
}

I found you have handled the ScriptNotify event by excuted Element.InvokeAction(e.Value); So I infer that you declared the InvokeAction for hybrid web view.

public void RegisterAction(Action<string> callback)
{
    action = callback;
}

public void Cleanup()
{
    action = null;
}

public void InvokeAction(string data)
{
    if (action == null || data == null)
    {
        return;
    }
    action.Invoke(data);
}

And then you could process CSharp CRUD functions in the callback function like the following code.

smbridwebview.RegisterAction(data => {
// process CSharp CRUD functions 
});

Upvotes: 1

Related Questions