[WinRT/Metro] C# で、WebView コントロールの JavaScript と相互作用する方法
Windows 8 Store apps Advent Calendar の 19日目の記事です*1。
前日: @tanaka_733 さんの「Windows Stroe App での検索コントラクトの追加」
翌日: @Fujiwo さんの「[Windows 8][Windows ストア アプリ][C#] ポータブル クラス ライブラリに関する検証」
※ *1 ウソです、 ホントは 22日に書いています:-p
◆ WebView コントロールって?
ここで扱うのは、 Windows ストア アプリ用の WebView です。
・HTML が表示できます
・IE10 のエンジンを使った COM コンポーネントっぽいです
…いじょ。(w
meta タグで指定しても互換表示になってくれないとか、 ヘンな癖はありますが、 まぁだいたい IE だと思ってそう間違いはないです。
◆ C# から JavaScript を呼び出したい!
で、 WebView を Windows ストア アプリに貼り付けて使ってると、 C# (あ、 もちろん VB でも OK ですけどf(^^; ) から WebView コントロール内の JavaScript を呼び出したくなるのですよ。
はい、 こんな風にして呼び出すことができます♪
【JavaScript】function add(a, b){
var result = (eval(a) + eval(b)).toString();
return result;
}
【C#】string result = webView1.InvokeScript("add", new string[]{"1", "2",});
// result は "3" になる
注意事項として。
引数も戻り値も、 string 型のみです。 C# 側にも JavaScript 側にも、 ラッパー関数を作っておくのが正義でしょう。
◆ JavaScript から C# を呼び出したい!!
これは、 直接にはサポートされてませんorz
しかし、 C# 側で拾えるイベントを起こせるので、 なんとかなります (^^;
JavaScript 側では、 window.external.notify() という関数を呼び出してイベントを叩きます。
【JavaScript】document.onmousemove = function(e){
var result = 'MOUSE: ' + e.clientX + ', ' + e.clientY;
window.external.notify(result); // ← C# 側を呼び出すイベントを起動
}
すると C# 側に ScriptNotify イベントが発生するので、 まずイベントハンドラをくっつけて…
【XAML】<WebView x:Name="webView1" ScriptNotify="webView_ScriptNotify" />
ハンドラの中では、 引数 NotifyEventArgs から、 JavaScript でセットした値を引っ張り出します。
【C#】private async void webView_ScriptNotify(object sender, NotifyEventArgs e)
{
textResult.Text = e.Value; // マウスの座標が表示される
}
これまた、 受け渡しできるのは string 型だけです。
◆ jQuery を使ってみる!
ついでに。
素で JavaScript をゴリゴリ書いてる人って、 いまだに居るのかな~?
普通 jQuery 使うよね!? f(^^;
てことで、 やってみました。
プロジェクトに JS ってフォルダを作って、 jQuery のファイルを置いて、 HTML の head 要素にはこんな風↓。<script type='text/javascript' src='ms-appx-web:///JS/jquery-1.8.3.js' ></script>
で、 onload で動くか実験 f(^^;$(function() {
$('#title').html('WebView Test Bench');
$('#title').css('color', '#00a2e8');
});
ぉお、 こいつ動くぞ♪
ということで、 WebView は C# から関数を呼び出したりイベントを受け取ったりできるし、 jQuery を使って JavaScript をサクサク書けるよ、 と。
◆ 毎回ビルドして画面操作してやっと確認 …勘弁してよ!?
…となれば、 TextBox にでも入力してやった HTML を WebView に叩き込んで、JavaScript の関数を呼び出したり ScriptNotify の結果を表示したりする、 汎用のテスト ツールを作ればいいのよ~♪
ってことで、 作っちゃいました f(^^;
bwDevTools: WebView Test Bench
Windows ストアで公開されてます。 使ってね~♪
# ちなみに、 申請から 2時間16分で認定されたという、 ちょっとしたスピード記録w
◆ jQuery はどこまで使える?
今のとこ、 ハマってません。
やりたいことは全部出来てます。 WebView だから動かない、 といった目には (今のところは) 会っていません。
おかげで、 「青空文庫リーダー・ライト」のバージョンアップがサクサク行けました f(^^;
その中で、 C# との相互作用の部分を挙げておきます。
・onload → C# にロード完了を通知 (この後、 スクロール位置の復元などをする)
・ユーザーのスクロール操作 → C# にスクロール位置を通知
・スクロール ← C# から表示位置を指定
・スクロール ← C# から相対位置を指定(前/次画面、前/次の行)
・スクロール位置を返却 ← C# から取得
・総ページ数を返却 ← C# から取得
・現在ページを返却 ← C# から取得
・特定のCSSを変更 ← C# から指定
| 固定リンク
「プログラミング」カテゴリの記事
- 【.NET / Win8.1 ストアアプリ】 HttpClient で TLS 1.1 / 1.2 に対応するには(2018.06.17)
- 【VS2017 15.7pv2】 XAML のランタイム ツールに 「ヒートマップ」 が増えた(2018.03.28)
- 【.NET Core】 プロジェクトを作ると 「project.assets.json が見つかりません」 エラー(2018.02.10)
- 【#UWP】 ビットマップの表示色を変える (Win2D.uwp 経由で Direct2D を使う)(2017.08.23)
- 【#UWP】 CompactOverlay モード: Picture in Picture というか、「最前面に表示」するウィンドウを作る(2017.08.16)
「* プログラミング ( Metro スタイル )」カテゴリの記事
- 【.NET / Win8.1 ストアアプリ】 HttpClient で TLS 1.1 / 1.2 に対応するには(2018.06.17)
- 【VS2017 15.7pv2】 XAML のランタイム ツールに 「ヒートマップ」 が増えた(2018.03.28)
- 【#UWP】 ビットマップの表示色を変える (Win2D.uwp 経由で Direct2D を使う)(2017.08.23)
- 【#UWP】 CompactOverlay モード: Picture in Picture というか、「最前面に表示」するウィンドウを作る(2017.08.16)
- 【#UWP】 15063用の Acrylic Effect を、ちゃんと実装してみる(2017.08.05)
この記事へのコメントは終了しました。
コメント
ご教示いただき、ありがとうございました。
これからもがんばってください。
投稿: 通りすがり | 2013年6月 5日 (水) 19時24分
window.external.notify()で渡せる引数は文字列1つだけなので、「引数を受け取ったC#側で文字列走査により判断する」ことになります。
というか、そうやってます。まさに':'で区切って、タイプ(前半)で分岐するswitch文を通して、caseでバリュー(後半)を引数にしてそれぞれのメソッドを呼び出しています。
投稿: biac | 2013年6月 4日 (火) 18時14分
こんにちわ、有益な情報の公開をありがとうございます。
window.external.notify();で複数のnotifyというかeventを使い分けることはできますか?それとも引数を受け取ったC#側で文字列走査により判断する、という感じでしょうか?
window.external.notify('mode:1');
window.external.notify('data:2');
private async void webView_ScriptNotify(object sender, NotifyEventArgs e){
//jsのコードですが...
var eventType = e.Value.split(':')[0];
var eventValue = e.Value.split(':')[1];
if(eventType=== 'mode'){
console.log('foo');
}
else if(eventType=== 'data'){
console.log(e.split(':')[1]);
}
}
投稿: 通りすがり | 2013年6月 4日 (火) 17時33分