ICON公式ブログ

ICON公式ブログ

静岡大学コンテンツ制作サークルICONの公式ブログです

C#でWebView2コントロールを使ってみた【サマーブログリレー2021 3日目】

この記事はICONサマーブログリレー2021 3日目の記事です。

f:id:iconcreator:20210915121218p:plain

こんにちは。プログラミング班の荒川です。

今回はC#でWebView2コントロールを使用する方法について紹介します。

 

開発環境

Windows 10 (64ビット)

Visual Studio 2019 Community

 

WebView2コントロールとは?

 WebView2コントロールは、ウインドウ上にウェブブラウザを設置するWebBrowserコントロールの後継です。WebBrowserコントロールの内部ブラウザはInternet Explorer (以下、IE) 7のため、最新のウェブページではデザインが乱れたり、JavaScriptの実行エラーが出ることがあります。レジストリの書き換えによって最新のIE11に変更できますが、IEそのものが来年6月にサポート終了するため、ソフトウェア保守を考えると今後開発するソフトウェアでの使用は望ましくありません。

 しかし、WebView2コントロールChromiumベースの最新ブラウザ「Microsoft Edge」を使用しているため、このような問題が解消されます。

 ちなみに、Microsoft Edgeが (Chromiumベースでない) 独自のエンジンを使用していた頃はWebViewコントロールという名称でした。

 

WebView2コントロールの導入

 WebView2コントロールの導入方法についてはこちらのページに書いてあります (他力本願)

 WebView2をVisual Studioで使うには、WebView2ランタイムの「Evergreen Bootstrapper」.NET Framework 4.6.2以降が必要です。後者は現在使われているPCならまず入っていると思います。

 両方のインストールが終わったらVisual Studioを起動し、C#の「Windows フォーム アプリケーション (.NET Framework)」で新規プロジェクトを作成します。

 フレームワークは先述の通り、.NET Framework 4.6.2以降に設定します。パッケージ管理形式をpackages.configからPackageReferenceに変更し、NuGetでWebView2 SDKをインストールしたら準備完了です。

 一般公開する際は、.exeファイルと同時に生成されるファイルやフォルダをまとめて配布します。Evergreen BootstrapperやWebView2 SDKは開発用のツールですので、ビルド済みのソフトウェアを実行するだけなら必要ありません。

 

画面設計

 WebView2 SDKをインストールするとツールボックスに追加される「WebView2」をフォームデザイナーにドラッグ&ドロップするだけです。位置やサイズはプロパティから変更できます。

 

任意のウェブページを読み込む

 WebView2に表示するウェブページのURLはコード中で指定します。例えば、以下のようなコードをビルドすると、起動と同時にICONのウェブサイトを表示するソフトウェアが完成します。これいる?

using System.IO;
using System.Windows.Forms;
using Microsoft.Web.WebView2.Core;

namespace WebView2Test
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            InitializeAsync();
        }

        async void InitializeAsync()
        {
            await webView21.EnsureCoreWebView2Async(null);
            webView21.CoreWebView2.Navigate("https://iconcreator.web.fc2.com/");
        }
    }
}

 ローカルのHTMLファイルも読み込めます。以下のコードでは、起動と同時に bin\Debug(またはRelease)\htdocs\index.html を読み込みます。

using System.IO;
using System.Windows.Forms;
using Microsoft.Web.WebView2.Core;

namespace WebView2Test
{
    public partial class Form1 : Form
    {
        string dir = Directory.GetCurrentDirectory().Replace("\\", "/");

        public Form1()
        {
            InitializeComponent();
            InitializeAsync();
        }

        async void InitializeAsync()
        {
            await webView21.EnsureCoreWebView2Async(null);
            webView21.CoreWebView2.Navigate("file:///" + dir + "/htdocs/index.html");
        }
    }
}

 

データを送信する (C#JavaScript)

 ここからは、WebView2コントロールとウェブページを連携させる方法について紹介します。以下は、C#側が送信した「Hello, world!」をウェブページのJavaScriptで受け取り、alertで表示するコードです。

JavaScript

window.chrome.webview.addEventListener("message", function(e) {
    alert(e.data);
});

C#

webView21.CoreWebView2.PostWebMessageAsString("Hello, world!");

 

データを送信する (JavaScriptC#)

 逆に、ウェブページのJavaScriptが送信したデータをC#側で受け取ることもできます。以下はJavaScript側が送信した「Hello, world!」をC#のMessageBoxで表示するコードです。

C#側 (一部のコードを省略)

async void InitializeAsync()
{
    // (省略)
    webView21.CoreWebView2.WebMessageReceived += MessageReceived;
}

private void MessageReceived(object sender, CoreWebView2WebMessageReceivedEventArgs args)
{
    string text = args.TryGetWebMessageAsString();
    MessageBox.Show(text);
}

JavaScript

window.chrome.webview.postMessage("Hello, world!");

 

簡易型テキストエディタの制作

 ここまでの内容を踏まえ、簡易的なテキストエディタを作成しました。テキストボックスに適当な文字列を入力し「セーブ」を押すと、内容が実行ファイルと同じ階層の「savedata」ファイルに保存され、次回起動時に自動で読み込まれます。

f:id:iconcreator:20210915103124p:plain

 「セーブしました。」のダイアログ表示にはJavaScriptのalertではなく、C#のMessageBoxを使用しました。

f:id:iconcreator:20210915103337p:plain

 コードは以下の通りです。JavaScript側から送信したデータを全てsavedataファイルに書き込み、C#側から送信したデータは全てテキストボックスに反映させるようプログラムしているため、複数の機能を付けたい場合はJSONの使用など工夫が必要です。

・index.html

<html>
    <head>
        <meta charset="utf-8">
        <style type="text/css">
        #button {
            margin-bottom: 10px;
        }
        #textarea {
            width: 300px;
            height: 200px;
        }
        </style>
        <script type="text/javascript">
        document.oncontextmenu = function() { return false; }
        window.chrome.webview.addEventListener("message", function(e) {
            document.getElementById("textarea").value = e.data;
        });
        function save() {
            window.chrome.webview.postMessage(document.getElementById("textarea").value);
        }
        </script>
    </head>
    <body>
        <button id="button" onclick="save()">セーブ</button>
        <br>
        <textarea id="textarea"></textarea>
    </body>
</html>

・Form1.cs

using System.IO;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using Microsoft.Web.WebView2.Core;

namespace WebView2Test
{
    public partial class Form1 : Form
    {
        readonly CountdownEvent condition = new CountdownEvent(1);
        string dir = Directory.GetCurrentDirectory().Replace("\\", "/");

        public Form1()
        {
            InitializeComponent();
            InitializeAsync();
        }

        async void InitializeAsync()
        {
            await webView21.EnsureCoreWebView2Async(null);
            webView21.CoreWebView2.Navigate("file:///" + dir + "/htdocs/index.html");
            webView21.CoreWebView2.NavigationCompleted += webView2_NavigationCompleted;
            webView21.CoreWebView2.WebMessageReceived += MessageReceived;
        }

        private void MessageReceived(object sender, CoreWebView2WebMessageReceivedEventArgs args)
        {
            string text = args.TryGetWebMessageAsString();
            File.WriteAllText(dir + "\\savedata", text);
            MessageBox.Show("セーブしました。");
        }

        private void webView2_NavigationCompleted(object sender, CoreWebView2NavigationCompletedEventArgs e)
        {
            //読み込み成功なら処理続行
            if (e.IsSuccess) {
                condition.Signal();
                Thread.Sleep(1);
                condition.Reset();
                string fileName = dir + "\\savedata";
                if (File.Exists(fileName)) {
                    StreamReader sr = new StreamReader(fileName, Encoding.GetEncoding("UTF-8"));
                    string str = sr.ReadToEnd();
                    sr.Close();
                    webView21.CoreWebView2.PostWebMessageAsString(str);
                }
            }
        }
    }
}

 なお、コード全文とVisual Studio 2019用のプロジェクトファイル、Windows用の実行ファイルは GitHubリポジトリ (ShizUni-ICON/WebView2Test) で公開しています。

 

まとめ

・WebView2では、ウインドウ内にChromiumベースのMicrosoft Edgeブラウザを設置できる

・WebView2を用いたソフトウェアの開発にはSDKなどのインストールが必要だが、実行する側では不要

・読み込むURLはプロパティでなく、コード中で指定する

・ウェブページのJavaScriptC#コードを相互に連携可能

 

 最後までお読みいただきありがとうございました。本文内容は加筆・修正する場合がありますのでご了承ください。