WebViewコントロールでの操作

WebViewコントロールでWebサイトを操作する方法

WebBrowserコントロールでは直接DOM操作できるメソッド・プロパティ(getElementByIdメソッドやdocumentプロパティ等)がありましたが、 WebViewコントロールにはありません。

WebViewコントロールでは、InvokeScriptAsyncメソッドとJavaScriptのeval関数を使用して、JavaScriptのコードを使ってWebページを操作します。

また、WebページのJavaScriptからアプリケーションに情報を渡すことができます。
JavaScriptの「window.external.notify」と、アプリケーション側ではScriptNotifyイベントを使用します。

JavaScriptの関数を実行する/DOMを操作する

WebViewでJavaScriptを実行する場合、InvokeScript/InvokeScriptAsyncメソッドとJavaScriptのeval関数を使用します。

							Dim userIdText As String = "abcde"
							Dim functionString As String = String.Format("document.getElementById('userid').innerText = '{0}';", userIdText)
							WebView1.InvokeScript("eval", New String() {functionString})
						
							String userIdText = "abcde";
							String functionString = String.Format("document.getElementById('userid').innerText = '{0}';", userIdText);
							WebView1.InvokeScript("eval", New String[] { functionString });
						

InvokeScript/InvokeScriptAsyncメソッドの第一引数に"eval"、第二引数に実行したいJavaScriptのコードの文字列を渡します。
上記のようにエレメントに値を設定したりできます。

WebViewで表示しているサイトの情報を取得する

JavaScriptでwindow.external.notifyを使用することで、アプリケーションにイベントを通知して情報を渡すことができます。

まず、Webサイト内の情報を受け取れるように、アプリケーション起動時にWebViewコントロールのIsScriptNotifyAllowedプロパティにTrueを設定します。

					'VB.NET
					WebView1.IsScriptNotifyAllowed = True

アプリケーション側でこれらのメッセージを受け取るためにScriptNotifyイベントを定義します。受け取った値はe.Valueで取得します。

					'VB.NET
					Private Sub OnWebViewScriptNotify(sender As Object, e As Microsoft.Toolkit.Win32.UI.Controls.Interop.WinRT.WebViewControlScriptNotifyEventArgs) Handles WebView1.ScriptNotify
						MsgBox(e.Value)
					End Sub

WebViewのInvokeScriptメソッドと、JavaScriptのeval関数を使うのは上記「JavaScriptの関数を実行する」と一緒ですが、 実行するJavaScriptコードとしてwindow.external.notifyを使用します。
JavaScript内でwindow.external.notifyを実行すると、引数に指定した値がアプリケーション側にScriptNotifyイベントで渡されます。

					'VB.NET
					WebView1.InvokeScript("eval", New String() {"window.external.notify(String(document.getElementById('userid').value));"})

						Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

							_objWebView.IsScriptNotifyAllowed = True    'これがないと、window.external.notifyでコード実行結果するとScriptNotifyイベントが発生しない。

						End Sub

						Private _getDataString As String    'WebViewからイベントで取得した文字列
						Private _getDataFlag As Boolean     'WebViewからイベントが発生したか

						Private Sub Button1_Click(sender As Object, e As EventArgs)

							_getDataFlag = False

							'JavaScriptを実行
							WebView1.InvokeScript("eval", New String() {"window.external.notify(String(document.getElementById('userid').value));"})

							Application.DoEvents()

							'イベントが発生しているかチェック
							If _getDataFlag = False Then
								Return
							End If

							'取得できた値を格納
							getDataValue = _getDataString
				
						End Sub

						Private Sub OnWebViewScriptNotify(sender As Object, e As Microsoft.Toolkit.Win32.UI.Controls.Interop.WinRT.WebViewControlScriptNotifyEventArgs) Handles WebView1.ScriptNotify
						
							_getDataString = e.Value
							_getDataFlag = True

						End Sub
					

						
					

JavaScriptで処理を行った結果を取得する

JavaScriptで処理を行った結果を「window.external.notify」で取得することができます。
JavaScriptのeval関数に渡すJavaScriptコードとして、 実行したい処理と、その処理結果を「window.external.notify」に渡すコードを組みます。

					'VB.NET
					WebView1.InvokeScript("eval", New String() {"var foo = document.querySelectorAll('.g');var str = "";foo.forEach(function (elem) {  str += elem.textContent + '\n';});window.external.notify(str);"})

window.external.notifyを使う場合の注意

サイトの情報を取得するために、
					'VB.NET
					WebView1.InvokeScript("eval", New String() {"window.external.notify(String(document.getElementById('userid').value));"})
のように「window.external.notify」でイベントを発生させますが、使い方を誤るとエラーになったり正常に取得できません。
正常に動作しない場合は、以下のポイントを確認してください。

「window.external.notify」の引数はString型になっているか

「window.external.notify」の引数はString型でないとOnWebViewScriptNotifyイベントに値が渡されません。
Stringにキャストして値がわたるようにしましょう。

ダブルクォーテーションとシングルクォーテーションを使い分けているか

VB.NETでプログラムをする場合、2連続するダブルクォーテーションは実態は1つダブルクォーテーションになります。
意図せずダブルクォーテーションの数が減る場合がありますので、 JavaScriptのコード部分はシングルクォーテーションを使って区別しましょう。

						'以下はVisualStudioではエラーにならない。
						'しかし2連続のダブルクォーテーションは1つとして扱われるので、JavaScriptとしてはエラーになる。
						WebView1.InvokeScript("eval", New String() {"var str = "";window.external.notify(str);"})
				
						'シングルクォーテーションで記述しましょう。
						WebView1.InvokeScript("eval", New String() {"var str = '';window.external.notify(str);"})

WebViewのサイト表示待ち方法

WebBrowserコントロールはIsBusy/ReadyStateプロパティで読み込み完了を判定していましたが、 WebViewにはこれらプロパティはありませんので、JavaScriptのdocument.readyStateを使います。
WebViewのNavigateメソッド実行後、InvokeScriptメソッドからWebView内のreadyStateの値を取得して読み込みが完了しているかループでチェックします。

以下のサンプルコードは、上記「JavaScriptの関数を実行する」のサンプルコードで使っている変数や設定を使ってますので、一部流用してください。

						Private Sub Button1_Click(sender As Object, e As EventArgs)

							Dim openFlag As Boolean = False '読み込み完了フラグ

							'サイトを表示する
							_objWebView.Navigate(url)
				
							'読み込み待ち
							Dim timeout As Date = Now.AddMinutes(30)
							While Now < timeout
								System.Windows.Forms.Application.DoEvents()
								System.Threading.Thread.Sleep(100)
				
								'JavaScriptを実行
								WebView1.InvokeScript("eval", New String() {"window.external.notify(String(document.readyState == 'complete'));"})
		
								Application.DoEvents()
		
								'イベントが発生しているかチェック
								If _getDataFlag = False Then
									Msgbox("err")
									Return
								End If
		
								'読み込み完了してれば終了		
								If _getDataString = "true" Then
									openFlag = True
									Exit While
								End If
							End While
				
							If openFlag = True Then
								MsbBox("ok")
							Else
								MsbBox("timeout")
							End If

							Return
				
						End Sub
					

						
					

参考