WebViewコントロールでの操作
WebViewコントロールでWebを操作する方法
WebView2コントロールでの操作
WebView2コントロールを使ってWebページを表示したりする方法は、左メニューの「基本操作」を参照してください。
基本的にはWebBrowserコントロールと大差ありません。
ただしDOM操作は大きく異なります。
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のコードの文字列を渡します。
上記のようにエレメントに値を設定したりできます。
もしevalで実行しようとしているJavaScriptの構文に誤りがあった場合、「System.AggregateException」の例外が発生します。
例外の詳細を確認しても何が間違っているのかはわかりません。
そんなときはブラウザの開発者ツールを使ってJavaScriptが正常に動作するか確認しましょう。
例えばChromeのデベロッパーツールではConsoleでJavaScriptのコードを入力して実行できます。
下記はセレクターのJavaScriptを実行して、期待通りに結果が得られていることが確認できます。

また後述している「window.external.notifyを使う場合の注意」も参考にしてください。
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));"})
Public Class Form1
Private _getDataString As String 'WebViewからイベントで取得した文字列
Private _getDataFlag As Boolean 'WebViewからイベントが発生したか
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
WebView1.IsScriptNotifyAllowed = True 'これがないと、window.external.notifyでコード実行結果するとScriptNotifyイベントが発生しない。
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
_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
'取得できた値を表示
MsgBox(_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
End Class
public partial class Form1 : Form
{
private string _getDataString; //WebViewからイベントで取得した文字列
private bool _getDataFlag; //WebViewからイベントが発生したか
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
webView1.IsScriptNotifyAllowed = true; //これがないと、window.external.notifyでコード実行結果するとScriptNotifyイベントが発生しない。
}
//WebViewで表示しているページの情報を取得する
private void Button1_Click(object sender, EventArgs e)
{
_getDataFlag = false;
//JavaScriptを実行
webView1.InvokeScript("eval", new string[] {"window.external.notify(String(document.getElementById(\'userid\').value));"});
Application.DoEvents();
//イベントが発生しているかチェック
if (_getDataFlag == false) return;
//取得できた値を表示
MessageBox.Show(_getDataString);
}
private void OnWebViewScriptNotify(object sender, Microsoft.Toolkit.Win32.UI.Controls.Interop.WinRT.WebViewControlScriptNotifyEventArgs e)
{
_getDataString = e.Value;
_getDataFlag = true;
}
}
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);"})
要素の指定や操作の方法について
具体的な要素の指定や操作の方法については、左メニューの「HTML要素の指定」
「HTML要素の操作(DOM操作)」を参照してください。
window.external.notifyを使う場合の注意
'VB.NET
WebView1.InvokeScript("eval", New String() {"window.external.notify(String(document.getElementById('userid').value));"})
正常に動作しない場合は、以下のポイントを確認してください。
「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の関数を実行する」のサンプルコードで使っている変数や設定を使ってますので、一部流用してください。
Public Class Form1
Private _getDataString As String 'WebViewからイベントで取得した文字列
Private _getDataFlag As Boolean 'WebViewからイベントが発生したか
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
WebView1.IsScriptNotifyAllowed = True 'これがないと、window.external.notifyでコード実行結果するとScriptNotifyイベントが発生しない。
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim openFlag As Boolean = False '読み込み完了フラグ
'ページを表示する
WebView1.Navigate("https://web.biz-prog.net/")
'読み込み待ち
Dim timeout As Date = Now.AddMinutes(30)
While Now < timeout
System.Windows.Forms.Application.DoEvents()
System.Threading.Thread.Sleep(100)
'JavaScriptを実行
_getDataFlag = False
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
MsgBox("ok")
Else
MsgBox("timeout")
End If
Return
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
End Class
public partial class Form1 : Form
{
private string _getDataString; //WebViewからイベントで取得した文字列
private bool _getDataFlag; //WebViewからイベントが発生したか
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
webView1.IsScriptNotifyAllowed = true; //これがないと、window.external.notifyでコード実行結果するとScriptNotifyイベントが発生しない。
}
//WebViewのページ表示待ち方法
private void button2_Click(object sender, EventArgs e)
{
bool openFlag = false; //読み込み完了フラグ
webView1.Navigate("https://web.biz-prog.net/");
//読み込み待ち
DateTime timeout = DateTime.Now.AddMinutes(30);
while ((DateTime.Now < timeout))
{
System.Windows.Forms.Application.DoEvents();
System.Threading.Thread.Sleep(100);
//JavaScriptを実行
_getDataFlag = false;
webView1.InvokeScript("eval", new string[] {"window.external.notify(String(document.readyState == 'complete'));"});
Application.DoEvents();
//イベントが発生しているかチェック
if (_getDataFlag == false)
{
MessageBox.Show("err");
return;
}
//読み込み完了してれば終了
if ((_getDataString == "true"))
{
openFlag = true;
break;
}
}
if ((openFlag == true))
MessageBox.Show("ok");
else
MessageBox.Show("timeout");
return;
}
private void OnWebViewScriptNotify(object sender, Microsoft.Toolkit.Win32.UI.Controls.Interop.WinRT.WebViewControlScriptNotifyEventArgs e)
{
_getDataString = e.Value;
_getDataFlag = true;
}
}
WebViewのページ表示待ち方法2
ページの表示完了時に発生するイベントNavigationCompletedを使った表示待ちです。
Public Class Form1
Private ReadOnly condition As New System.Threading.CountdownEvent(1)
Private Async Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
Dim result As String = ""
'非同期実行
Await Task.Run(
Sub()
'ページの表示を開始
WebView1.Navigate("https://web.biz-prog.net/")
'読み込み完了まで待機
If condition.Wait(5000) Then
result = "ok"
Else
result = "timeout"
End If
End Sub
)
MsgBox(result)
End Sub
Private Sub WebView1_NavigationCompleted(sender As Object, e As Microsoft.Toolkit.Win32.UI.Controls.Interop.WinRT.WebViewControlNavigationCompletedEventArgs) Handles WebView1.NavigationCompleted
Console.WriteLine(e.Uri.ToString())
'読み込み結果を判定
If e.IsSuccess Then
Console.WriteLine("complete")
Else
Console.WriteLine(e.WebErrorStatus)
End If
'シグナル初期化
condition.Signal()
System.Threading.Thread.Sleep(1)
condition.Reset()
End Sub
End Class
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private readonly System.Threading.CountdownEvent condition = new System.Threading.CountdownEvent(1);
private async void button3_Click(object sender, EventArgs e)
{
string result = "";
//非同期実行
await Task.Run(() =>
{
//ページの表示を開始
webView1.Navigate("https://web.biz-prog.net/");
//読み込み完了まで待機
if (condition.Wait(5000))
result = "ok";
else
result = "timeout";
});
MessageBox.Show(result);
}
private void webView1_NavigationCompleted(object sender, Microsoft.Toolkit.Win32.UI.Controls.Interop.WinRT.WebViewControlNavigationCompletedEventArgs e)
{
Console.WriteLine(e.Uri.ToString());
//読み込み結果を判定
if (e.IsSuccess)
Console.WriteLine("complete");
else
Console.WriteLine(e.WebErrorStatus);
//シグナル初期化
condition.Signal();
System.Threading.Thread.Sleep(1);
condition.Reset();
}
}
参考
