Browser 缓存和重用HtmleElement对象树

Browser 缓存和重用HtmleElement对象树,browser,webbrowser-control,dom,Browser,Webbrowser Control,Dom,我在项目中使用WebBrowser控件来显示运行时生成/操作的复杂HTML文档 我注意到,通过创建HtmlElement对象从C#以编程方式构建DOM比生成HTML字符串并将其传递给WebBrowser慢3倍左右,后者反过来解析该字符串以生成DOM。在冗长的文档之间导航时,这两种方法都会造成明显的延迟 我正在寻找在同一WebBrowser控件中的多个文档之间切换的最快方法,理想情况下不必为每个文档重复生成DOM树。是否可以将HtmlElement对象树缓存在程序中的某个位置,然后根据需要将它们重

我在项目中使用
WebBrowser
控件来显示运行时生成/操作的复杂HTML文档

我注意到,通过创建
HtmlElement
对象从C#以编程方式构建DOM比生成HTML字符串并将其传递给
WebBrowser
慢3倍左右,后者反过来解析该字符串以生成DOM。在冗长的文档之间导航时,这两种方法都会造成明显的延迟


我正在寻找在同一
WebBrowser
控件中的多个文档之间切换的最快方法,理想情况下不必为每个文档重复生成DOM树。是否可以将
HtmlElement
对象树缓存在程序中的某个位置,然后根据需要将它们重新插入到
WebBrowser
中?

可能不需要缓存DOM,而只需要在窗体上的多个WebBrowser控件之间切换-只有活动控件可见?

可能不需要缓存DOM,而只需要在窗体上的多个WebBrowser控件之间切换-只有活动控件一个是可见的?

我真的需要更多地了解您是如何生成这些文档的。将数据转换为XML文档,然后使用XSL转换将数据转换为HTML并将其传递给WebBrowser控件可能会更快

NET的XSLT实现的好处在于它获取XSL源代码并将其编译为临时程序集以加快转换


如果您决定这样做,请查看MVP.XML项目,该项目为股票XSLT实现添加了一些很好的exslt功能。

我真的需要了解有关如何生成这些文档的更多信息。将数据转换为XML文档,然后使用XSL转换将数据转换为HTML并将其传递给WebBrowser控件可能会更快

NET的XSLT实现的好处在于它获取XSL源代码并将其编译为临时程序集以加快转换


如果您决定这样做,请查看MVP.XML项目,该项目为股票XSLT实现添加了一些不错的exslt功能。

我将用本机win32 COM API描述解决方案;用C#(或者在pinvoke.net上找到)编写互操作应该不会太困难。或者,您可能需要使用托管对象公开的属性来获取本机属性

您自己构建DOM的速度不可能比IE的解析器快,因此创建一个空白的HTMLDocument(在本机代码中是CoCreateInstance(CLSID_HTMLDocument))和QueryInterface()HTMLDocument,用于其IMarkupServices实现。还可以使用IMarkupServices::CreateMarkupPointer()方法创建两个imarkuppointer

下一步调用IMarkupServices::ParseString()解析HTML。这将为您提供一个指向包含DOM的IMarkupContainer的指针,以及指向DOM开头和结尾的两个iMarkuppointer。现在,您可以使用IMarkupServices::Move()将数据从一个IMarkupContainer移动到另一个IMarkupContainer

因此,您将使用的一般方案是拥有一个HTMLDocument,它是您的“显示”文档,以及它的关联IMarkupContainer(您可以查询接口())。然后,您就有了一个向量或列表或所有非显示标记容器中的任何内容。然后,您只需为显示文档创建一个标记指针,调用IMarkupPointer::MoveToContainer(displayDocumentContainer,true),然后使用该指针将内容从显示容器移动到非显示容器,反之亦然

需要注意的一点是:只能在创建或获取这些对象的线程上访问这些对象。所有IE对象都是STA对象。如果需要多线程访问,则必须封送

如果您有具体的后续问题,请告诉我

参考资料:


我将用本机win32 COM API描述解决方案;用C#(或者在pinvoke.net上找到)编写互操作应该不会太困难。或者,您可能需要使用托管对象公开的属性来获取本机属性

您自己构建DOM的速度不可能比IE的解析器快,因此创建一个空白的HTMLDocument(在本机代码中是CoCreateInstance(CLSID_HTMLDocument))和QueryInterface()HTMLDocument,用于其IMarkupServices实现。还可以使用IMarkupServices::CreateMarkupPointer()方法创建两个imarkuppointer

下一步调用IMarkupServices::ParseString()解析HTML。这将为您提供一个指向包含DOM的IMarkupContainer的指针,以及指向DOM开头和结尾的两个iMarkuppointer。现在,您可以使用IMarkupServices::Move()将数据从一个IMarkupContainer移动到另一个IMarkupContainer

因此,您将使用的一般方案是拥有一个HTMLDocument,它是您的“显示”文档,以及它的关联IMarkupContainer(您可以查询接口())。然后,您就有了一个向量或列表或所有非显示标记容器中的任何内容。然后,您只需为显示文档创建一个标记指针,调用IMarkupPointer::MoveToContainer(displayDocumentContainer,true),然后使用该指针将内容从显示容器移动到非显示容器,反之亦然

需要注意的一点是:只能在创建或获取这些对象的线程上访问这些对象。所有IE对象都是STA对象。如果需要多线程访问,则必须封送

如果您有具体的后续问题,请告诉我

参考资料:


    • 你能做点像这样的事吗

      • 创建要在DIV中显示的内容
      • 创建secon
        // On screen webbrowser control
        webBrowserControl.Navigate("about:blank");
        webBrowserControl.Document.Write("<div id=\"div1\">This will change</div>");
        var elementToReplace = webBrowserControl.Document.GetElementById("div1");
        var nodeToReplace = elementToReplace.DomElement as mshtml.IHTMLDOMNode;
        
        // In memory webbrowser control to load fragement into
        // It needs this base object as it is a COM control
        var webBrowserFragement = new WebBrowser();
        webBrowserFragement.Navigate("about:blank");
        webBrowserFragement.Document.Write("<div id=\"div1\">Hello World!</div>");
        var elementReplacement = webBrowserFragement.Document.GetElementById("div1");
        var nodeReplacement = elementReplacement.DomElement as mshtml.IHTMLDOMNode;
        
        // The magic happens here!
        nodeToReplace.replaceNode(nodeReplacement);