« Win8 Store apps / WP8 Advent Calendar のアプリをリリースしました | トップページ | [電子書籍] Windows 8 用の青空文庫ビューア »

2012年12月19日 (水)

[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
Screenshot_12202012_235242a
Windows ストアで公開されてます。 使ってね~♪
# ちなみに、 申請から 2時間16分で認定されたという、 ちょっとしたスピード記録w

◆ jQuery はどこまで使える?
今のとこ、 ハマってません。
やりたいことは全部出来てます。 WebView だから動かない、 といった目には (今のところは) 会っていません。

おかげで、 「青空文庫リーダー・ライト」のバージョンアップがサクサク行けました f(^^;
その中で、 C# との相互作用の部分を挙げておきます。
・onload → C# にロード完了を通知 (この後、 スクロール位置の復元などをする)
・ユーザーのスクロール操作 → C# にスクロール位置を通知
・スクロール ← C# から表示位置を指定
・スクロール ← C# から相対位置を指定(前/次画面、前/次の行)
・スクロール位置を返却 ← C# から取得
・総ページ数を返却 ← C# から取得
・現在ページを返却 ← C# から取得
・特定のCSSを変更 ← C# から指定

Screenshot_12202012_180024

|

« Win8 Store apps / WP8 Advent Calendar のアプリをリリースしました | トップページ | [電子書籍] Windows 8 用の青空文庫ビューア »

プログラミング」カテゴリの記事

* プログラミング ( Metro スタイル )」カテゴリの記事

コメント

ご教示いただき、ありがとうございました。
これからもがんばってください。

投稿: 通りすがり | 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分

この記事へのコメントは終了しました。

トラックバック


この記事へのトラックバック一覧です: [WinRT/Metro] C# で、WebView コントロールの JavaScript と相互作用する方法:

« Win8 Store apps / WP8 Advent Calendar のアプリをリリースしました | トップページ | [電子書籍] Windows 8 用の青空文庫ビューア »