Accessing UI thread from Windows Runtime Component

2019-08-17 05:00发布

问题:

I have the following problem. I am using a simple Windows Runtime Component to communicate between the application and a WebView. I am doing this according to documentation

This is the code for the Windows Runtime Component

 public delegate void NotifyAppHandler( string str );

[AllowForWeb]
public sealed class WebViewInjectionObject
{
    public event NotifyAppHandler OnNotifyApp;

    public void NotifyApp( string str )
    {
        OnNotifyApp?.Invoke( str );
    }
}

In the OnNavigatedTo method I initialize the WebViewInjectionObject and subscribe to the OnNotifyApp event.

 webViewInjectionObject = new WebViewInjectionObject();
 webViewInjectionObject.OnNotifyApp += WebViewInjectionObject_OnNotifyApp;    

Then on the NavigationStarting event of the WebView I call AddWebAllowedObject on the WebView

 private void WebView_NavigationStarting( WebView sender, WebViewNavigationStartingEventArgs args ) {
        sender.AddWebAllowedObject( "nativeObject", webViewInjectionObject );
    }

The code in the WebViewInjectionObject_OnNotifyApp method which then interacts with the WebView looks like this.

if (somethingGood) {
    await WebView.InvokeScriptAsync( successFunctionName, functionArguments ); 
}

When running this on the Desktop (Version 1709, Build 16299.371) everything works fine.

When running this on the mobile phone (Version 1709 and Version 1607) I get this exception.

The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))

Usually esceptions like this are solved by using the dspatcher to make the call from the UI thread. I tried doing the followig

 await Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync( Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
      {
           await WebView.InvokeScriptAsync( successFunctionName, functionArguments );
      } );

But this lead to a deeper exception

A COM call to an ASTA was blocked because the call chain originated in or passed through another ASTA. This call pattern is deadlock-prone and disallowed by apartment call control. A COM call (IID: {638BB2DB-451D-4661-B099-414F34FFB9F1}, method index: 6) to an ASTA (thread 3036) was blocked because the call chain originated in or passed through another ASTA (thread 5964). This call pattern is deadlock-prone and disallowed by apartment call control.

After that I thought of using the SynchronizationContext so I did this. In OnNavigatedTo

syncContext = SynchronizationContext.Current;

And then in WebViewInjectionObject_OnNotifyApp

 syncContext.Post( async delegate
        {
             await WBTWebView.InvokeScriptAsync( successFunctionName, functionArguments );
        }, null );

This leads again to the first exception.

I am at a loss at what to do next. The goal is to catch the event thrown from the Windows Runtime Component and then call InvokeScriptAsync on the WebView in a way that works both for Desktop and Mobile.