在WinForms / WPF WebBrowser控件

时间:2015-10-26 08:15:10

标签: javascript c# wpf

我在网站上发现了一个很酷的功能,用JavaScript实现,我想在我的桌面应用程序中使用它(供个人使用)。 在我的实验中,我设法动态生成自定义HTML,使用webBrowser1.DocumentText = [my generated HTML]将其提供给浏览器 我已经设法将一些内联JavaScript放入HTML中,并通过ScriptManager将其连接起来,以便我可以从我的C#代码调用JavaScript,将值传递给它,并获得返回值。

但我试图使用的功能有点复杂:它不少于10个JavaScript文件。其中2个以常规方式<script src="/js/script1.js" type="text/javascript"></script>

直接在网页中引用

其他8个加载在其中一个脚本中:

var elem = document.createElement("script");
            elem.type = "text/javascript";
            elem.src = "/js/" + filename;
            document.body.appendChild(elem);

这8个文件实际上是数据文件,即使数据是用JavaScript表示的。它们非常大,每个超过1MB。将它全部填入HTML文件似乎非常愚蠢。此外,加载数据的脚本会创建一个“文件映射”,并根据它所在的文件进一步引用数据:

  var fileMap = [
                        [/[\u0020-\u00ff]/, 'file1.js'],
                        [/[\u3000-\u30ff]/, 'file2.js'],
                        [/[\u4e00-\u5dff]/, 'file3.js'],
...

我不想求助于修改JavaScript,因为这不是我的强项。因此浏览器需要“查看”js文件才能使用它们。我想到了在本地创建文件结构,并在那里导航浏览器。但我不希望我的解决方案中有任何松散的文件。如果可能的话,我想把所有内容都嵌入。我怀疑我可以让浏览器导航到嵌入式资源,并将其他嵌入资源视为文件。知道如何解决这个问题吗?

编辑:

我已尝试使用本地文件。没运气。我正确地加载HTML,但是当我尝试调用JavaScript调用时,没有任何反应。我试着将浏览器指向那些js文件,以确保它们在那里。他们是。我尝试了一个src属性指向与脚本文件在同一子文件夹中的图像的元素。它被渲染。好像外部js文件拒绝加载。

1 个答案:

答案 0 :(得分:0)

我有与你的场景类似的需求,我使用嵌入在另外两个Stack Overflow答案中的两个关键点来解决它。正如SLaks&#39;所述。回答here第一个关键是使用语法file:///作为外部文件的绝对路径的前缀。第二个是使用.Replace("\\", "/")作为绝对文件路径,如Adam Plocher的答案中所列,以及他的一个后续评论here

简而言之,HTML页面中每个外部文件的最终输出将如下所示:

<link href="file:///c:/users/david/myApp/styles/site.css" rel="stylesheet" type="text/css">

<script src="file:///c:/users/david/myApp/scripts/JavaScript1.js"></script>

在我的HTML文件中使用上面示例中的格式导致WebBrowser控件加载外部CSS,图像或脚本文件。

详细信息并解决问题中的方案

在上面第一个引用的SO答案的womd回答中,他使用方法System.IO.File.ReadAllText()加载脚本文件并将脚本文件的文本嵌入到<head>标记中。正如您在问题中指出的那样,直接将脚本文件加载到HTML页面中并不是您想要做的事情。

以下解决方案涉及使用相同的System.IO.File.ReadAllText()方法,但会加载HTML页面的文本。该前提的工作方式类似于ASP.NET中的Razor View Engine。

下面的解决方案中的主要思想是在HTML页面中添加一个临时字符串,该页面将被加载到WebBrowser控件中,然后在HTML页面设置为加载之前在我的应用程序中的C#方法中替换此临时字符串进入WebBrowser控件。

以下是我的解决方案的基本步骤:

  1. 为HTML文件中的每个外部引用添加一个临时字符串。
  2. 为HTML文件中的脚本标记中的绝对路径声明变量。除非您要在JavaScript代码中的其他位置使用绝对路径,否则无需执行此步骤。您的方案涉及通过JavaScript代码延迟加载外部脚本文件,因此这一步是必要的。
  3. 修改JavaScript代码中的src属性,该属性延迟使用绝对路径变量加载其他脚本文件。
  4. 在您的应用中添加一个方法,将HTML页面文件作为文本字符串加载,然后使用包含前缀&#39; file:///&#39;的绝对路径替换所有临时字符串实例。绝对路径应该有正斜杠。
  5. 设置&#39; DocumentText&#39; WebBrowser控件上的属性更新为HTML。
  6. 设置&#39;复制到输出目录&#39;将项目中的每个外部文件设置为&#39;始终复制&#39;或者&#39;复制如果更新&#39;。如果您的外部文件具有固定位置且该位置不在Visual Studio使用的构建或发布目录中,则可能不需要此步骤。
  7. 以下是每个步骤的详细信息。我添加了很多你可以跳过的细节。由于步骤对项目中的几个地方进行了更改,因此我很难减少任何混淆。

    1。使用临时字符串

    我使用了字符串&#34; / ReplaceWithAbsolutePath /&#34;但你可以使用任何不同的文字。 HTML页面中对外部文件的每个引用如下所示:

    <!DOCTYPE html>
    <html lang="en" xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="utf-8" />
        <title></title>
        <link href="/ReplaceWithAbsolutePath/styles/site.css" rel="stylesheet" type="text/css">
        <script type="text/javascript">
            var absolutePath = "/ReplaceWithAbsolutePath/";
        </script>
    </head>
    <body>
        <p>My web page</p>
        <script src="/ReplaceWithAbsolutePath/scripts/JavaScript1.js"></script>
    </body>
    </html>
    

    2。声明绝对路径变量

    请注意,在上面的HTML页面中,我列出了<script>标记,其中包含声明的变量&#39; absolutePath&#39;设置为临时字符串。 (在上面的HTML页面中,变量添加了一个全局变量,这不一定是最佳实践。您可以在命名空间中声明变量,而不是在全局命名空间中声明它。)

    3。修改延迟加载脚本以包含绝对路径变量

    添加&#39; absolutePath&#39;变量到您的JavaScript文件,延迟加载包含您的数据的其他JavaScript文件。

    elem.src = absolutePath + "/js/" + filename;
    

    4。 C#方法替换所有临时字符串实例

    在项目中,将以下行添加到表单加载事件处理程序中,或将此行放在WebBrowser控件初始化的某处。

    webBrowser1.DocumentText = GetUpdatedHtmlWithAbsolutePaths("/ReplaceWithAbsolutePath/", "HTMLPage1.html");
    

    将以下方法添加到您的代码中。更新上面一行中方法的调用,其中包含放置以下方法的类实例的名称。

        // The result of this method will look like the following example:
        // <script src="file:///c:/users/david/documents/myApp/scripts/JavaScript1.js"></script>
        public string GetUpdatedHtmlWithAbsolutePaths(string tempPathString, string htmlFilename)
        {
            // Get the directory as the application
            // stackoverflow.com/questions/674857/should-i-use-appdomain-currentdomain-basedirectory-or-system-environment-current
            // Note that the 'BaseDirectory' property will return a string with trailing backslashes ('\\')
            string appDirectory = AppDomain.CurrentDomain.BaseDirectory;
            // Replace '//' with '/' in the appDirectory string
            appDirectory = appDirectory.Replace("\\", "/");
            // Read all of the HTML text from the HTML page file
            string html = System.IO.File.ReadAllText(appDirectory + @"\" + htmlFilename);
            // Replace all '/ReplaceWithAbsolutePath/' strings within the HTML text with
            // the absolute path on the local machine
            html = html.Replace(tempPathString, "file:///" + appDirectory);
            return html;
        }
    

    5。设置WebBrowser控件的DocumentText属性

    我在表单加载事件处理程序中添加了WebBrowser控件的初始化,但当然,您可以添加在初始化WebBrowser控件的任何位置设置DocumentText属性的行。

        private void Form1_Load(object sender, EventArgs e)
        {
            // Set the document text of the web browser control with the updated HTML
            webBrowser1.DocumentText = GetUpdatedHtmlWithAbsolutePaths("HTMLPage1.html");
        }
    

    6。设置&#39;复制到输出目录&#39;每个外部文件

    如果您希望外部文件包含在解决方案/项目文件结构中,请查看Matthew Watson在此Stack Overflow question中发布的答案。

      

    您可以将文件添加到项目中并选择其属性:&#34;构建   动作&#34; as&#34;内容&#34;和&#34;复制到输出目录&#34; as&#34;始终复制&#34;   或者如果更新则复制(后者是优选的,因为否则   每次构建项目时都会完全重建项目。)

         

    然后这些文件将被复制到您的输出文件夹。

         

    这比使用后期构建步骤更好,因为Visual Studio会   知道这些文件是项目的一部分。 (这会影响像   ClickOnce应用程序需要知道要添加到哪些文件   clickonce data。)

    简而言之,将外部文件添加到项目中。您可以将外部添加到项目中的任何子文件夹。 (在Visual Studio 2013或2015中 - 我没有VS2012)在解决方案资源管理器中右键单击外部文件,然后从上下文菜单中选择“属性”。将显示“属性”窗格。在“属性”窗格中,更改“复制到输出目录”的设置。到&#39;永远复制&#39;或者&#39;复制如果更新&#39;。

    enter image description here

    使用“查看源”验证绝对路径字符串

    运行您的项目,它应该在WebBrowser控件中加载您的外部文件。假设您尚未在代码或“属性”窗格中为WebBrowser控件设置属性wbChartContainer.IsWebBrowserContextMenuEnabled = false;,则可以在窗体运行时右键单击WebBrowser控件。点击查看来源&#39;从上下文菜单中,在“查看源”窗口中检查外部资源的路径。