0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Xamarin.Forms+Prism.FormsでViewModelからViewのメソッド(WebView.EvaluateJavaScriptAsync)を呼び出す

Last updated at Posted at 2020-10-01

#Xamarin.Forms+Prism.FormsでViewModelからViewのメソッド(WebView.EvaluateJavaScriptAsync)を呼び出す
WebViewのEvaluateJavaScriptAsyncを使用する際、VM→Vメソッド呼び出しを実装したので覚え書き。

WebViewにはローカルのHTMLファイルを設定している。
WPFなら以下サンプルソースのBindingContextをDataContextに変更する。

##実装

View.xml
<?xml version="1.0" encoding="utf-8 ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:prism="http://prismlibrary.com"
             prism:ViewModelLocator.AutowireViewModel="True"
             x:Class="App.Views.ViewPage">
    <ContentPage.Content>
        <WebView x:Name="webView" Source="{Binding Url}" />
    </ContentPage.Content>
</ContentPage>
  • 「x:Name="webView"」で、View.csから参照できるように。
  • 「Source="{Binding Url}"」で、UrlはViewModel.csで設定。
View.cs
namespace App.Views
{
    public partial class ViewPage : ContentPage
    {
        public ViewPage()
        {
           InitializeComponent();

           var vm = (ViewPageViewModel)BindingContext;
           vm.InvokeJsEvent += JsAsync;
        }
    }

    async void JsAsync(string num)
    {
        var js = $"factorial(num)";
        var result = await webView.EvaluateJavaScriptAsync(js);
    }
}
  • 「vm.InvokeJsEvent += JsAsync」で、ViewModelの当該イベントにViewのメソッドを登録。
ViewModel.cs
namespace App.ViewModels
{
    public class ViewModel : TabItemViewModelBase
    {
        private string _url;
        private IBaseUrl _baseUrl;

        public delegate void InvokeJsAction(string data);
        public event InvokeJsAction InvokeJsEvent;

        public ViewModel(IBaseUrl baseUrl)
        {
            _baseUrl = baseUrl;
        }
    }
    
    public override void Initialize(INavigationParameters parameters)
    {
        Url = $"{_baseUrl.Get()}index.html";
    }

    public override void RaiseIsActiveChanged()
    {
        if (IsActive)
        {
            InvokeJsEvent?Invoke("100");
        }
    }
}
  • 「IBaseUrl」には、デバイス別ローカルHTMLファイルのBaseUrlを格納している。
  • 「InvokeJsEvent?Invoke("100");」で、イベント呼び出し→Viewのメソッド呼び出し→JSのメソッド呼び出し。

※RaiseIsActiveChangedは、TabbedPageでTabがActiveになった際に呼ばれる。
 普通のContentPageなら、OnNavigatedTo()などで呼び出せば良さげ。
 Initialize()などで呼び出すと、htmlが読み込まれる前にJS呼び出しを行おうとし、
 NullReferenceExceptionが発生することがある様子(詳細は未調査)。

##参考
https://stackoverflow.com/questions/8658499/calling-a-method-in-views-codebehind-from-viewmodel
↑ネタ元

https://docs.microsoft.com/ja-jp/xamarin/xamarin-forms/user-interface/webview?tabs=windows
IBaseUrl(ローカルのHTMLファイル読み込み)の実装は公式ドキュメント参照。

https://stackoverflow.com/questions/58922622/how-to-trigger-onnavigatedto-on-the-second-third-tab-in-tabbedpage-using-prism
TabItemViewModelBaseのRaiseIsActiveChanged()については、↑参照。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?