WinForms WebBrowser コントロールで生成された HTML でローカル リソースを参照するにはどうすればよいですか?
-
09-06-2019 - |
質問
winforms ウェブブラウザ コントロールを使用して Windows フォーム アプリに一部のコンテンツを表示しています。DocumentText プロパティを使用して、生成された HTML を記述しています。その部分は見事に機能しています。次に、マークアップでいくつかの画像を使用したいと思います。(リンクされた CSS と JavaScript も使用したいと考えていますが、埋め込むだけで回避できます。)
数日間グーグルで検索しましたが、タイトルの質問に対する答えが見つからないようです。
相対参照を使用してみました。アプリの実行ファイルは bin\debug にあります。画像はプロジェクトのルートにある「Images」ディレクトリにあります。コンパイル時にイメージが出力ディレクトリにコピーされるように設定したため、イメージは bin\debug\Images* に配置されます。そこで、exe に相対的なものであると考えて、「Images...」のような参照を使用します。ただし、埋め込みブラウザ ウィンドウで画像のプロパティを見ると、画像の URL が「about:blankImages/*」であることがわかります。HTML がコントロールに書き込まれるとき、すべては「about:blank」を基準にしているように見えます。場所のコンテキストが欠如しているため、相対ファイル リソース参照に何を使用すればよいのかわかりません。
これを修正するために何か設定する方法があるかどうかを確認するために、コントロールのプロパティを調べてみました。空の HTML ページを作成し、ファイルへの完全なローカル パスを使用して「Navigate()」メソッドを使用してブラウザーにそのページを指定しました。これは、ブラウザがローカルの「file:///...」パスを空白のページに報告することで正常に機能しました。次に、今度は Document.Write() を使用して、再度ブラウザに書き込みました。ここでも、ブラウザは「about:blank」を URL として報告するようになりました。
動的 HTML の結果を実際のファイルに書き込む以外に、ファイル リソースを参照する方法はありませんか?
最後にもう 1 つ試してみたいと思います。画像への絶対ファイル パスを構築し、それらを HTML に書き込みます。私の HTML は、シリアル化されたオブジェクトの XML の XSL 変換を使用して生成されているため、いくつかの XSL パラメーターを操作する必要があります。これにはあまり慣れていないため、少し時間がかかります。
解決
ここでは、カスタム Web ブラウザを使用して、右クリックして古き良き IE コンテキスト メニューを表示する機能などを削除しています。
public class HtmlFormatter
{
/// <summary>
/// Indicator that this is a URI referencing the local
/// file path.
/// </summary>
public static readonly string FILE_URL_PREFIX =
"file://";
/// <summary>
/// The path separator for HTML paths.
/// </summary>
public const string PATH_SEPARATOR = "/";
}
// We need to add the proper paths to each image source
// designation that match where they are being placed on disk.
String html = HtmlFormatter.ReplaceImagePath(
myHtml,
HtmlFormatter.FILE_URL_PREFIX + ApplicationPath.FullAppPath +
HtmlFormatter.PATH_SEPARATOR);
基本的に、ファイル URI を持つ画像パスが必要です。
<img src="file://ApplicationPath/images/myImage.gif">
他のヒント
分かりました。
exe ディレクトリの完全に解決された URL を、イメージ タグを含む HTML 出力を含む XSL 変換に渡すだけです。
XsltArgumentList lstArgs = new XsltArgumentList();
lstArgs.AddParam("absoluteRoot", string.Empty, Path.GetFullPath("."));
次に、すべての画像の前にパラメータ値を追加しました。
<img src="{$absoluteRoot}/Images/SilkIcons/comment_add.gif" align="middle" border="0" />
結局、Ken が提案したものと基本的に同じものを使用しました。ただし、ファイル接頭辞を手動で追加する代わりに、UriBuilder クラスを使用して、「ファイル」プロトコルで完全な URI を構築しました。
これにより、より現実的な場所である Program Files でアプリをテストしたときの問題も解決されました。スペースはエンコードされていましたが、ファイルが標準のシステム パス (つまり、"C:\Program%20Files...")。実際の URI 値 (file:///C:/Program Files/...) を使用すると機能しました。
あるいは、通常のスタイルの相対リンクを維持し、HTML 変換コードを削除し、代わりに次のような C# Web サーバーを埋め込みます。 これ exe ファイル内で、WebControl を内部 URL (localhost:8199/myapp/ など) に指定します。
Ken のコードには、動作するために必要なものがいくつか欠けていました。私はそれを改訂し、物事を少し自動化する新しいメソッドを作成しました。
次のように静的メソッドを呼び出すだけです。
html = HtmlFormatter.ReplaceImagePathAuto(html);
file://ApplicationPath/ に一致する HTML 内のすべてのリンクは、現在の作業ディレクトリと交換されます。代替の場所を指定する場合は、元の静的メソッドが含まれます (加えて、不足していたビットも含まれます)。
public class HtmlFormatter
{
public static readonly string FILE_URL_PREFIX = "file://";
public static readonly string PATH_SEPARATOR = "/";
public static String ReplaceImagePath(String html, String path)
{
return html.Replace("file://ApplicationPath/", path);
}
/// <summary>
/// Replaces URLs matching file://ApplicationPath/... with Executable Path
/// </summary>
/// <param name="html"></param>
/// <returns></returns>
public static String ReplaceImagePathAuto(String html)
{
String executableName = System.Windows.Forms.Application.ExecutablePath;
System.IO.FileInfo executableFileInfo = new System.IO.FileInfo(executableName);
String executableDirectoryName = executableFileInfo.DirectoryName;
String replaceWith = HtmlFormatter.FILE_URL_PREFIX
+ executableDirectoryName
+ HtmlFormatter.PATH_SEPARATOR;
return ReplaceImagePath(html, replaceWith);
}
}