Кэширование и повторное использование дерева объектов HtmlElement - PullRequest
0 голосов
/ 16 февраля 2009

Я использую элемент управления WebBrowser в своем проекте для отображения сложных документов HTML, которые создаются / обрабатываются во время выполнения.

Я заметил, что программное построение DOM из C # путем создания HtmlElement объектов примерно в 3 раза медленнее, чем генерация строки HTML и ее передача в WebBrowser, который, в свою очередь, анализирует ее для генерации DOM. Оба способа создают заметную задержку при навигации между длинными документами.

Я ищу самый быстрый способ переключения между несколькими документами в одном элементе управления WebBrowser, в идеале без необходимости многократного создания дерева DOM для каждого документа. Можно ли кешировать дерево из HtmlElement объектов где-нибудь в моей программе, а затем заново вставить их в WebBrowser при необходимости?

Ответы [ 5 ]

2 голосов
/ 13 марта 2009

Это сделает это

// 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);
2 голосов
/ 11 марта 2009

Я опишу решение в терминах собственных API-интерфейсов win32 COM; не должно быть слишком сложно написать взаимодействие, чтобы сделать это на C # (или найти его на pinvoke.net). В качестве альтернативы вам может понадобиться использовать свойства, предоставляемые управляемыми объектами, для получения собственных.

Вы вряд ли сможете создать DOM самостоятельно быстрее, чем парсер IE, поэтому создайте пустой HTMLDocument (в нативном коде это будет CoCreateInstance (CLSID_HTMLDocument)) и QueryInterface () HTMLDocument для его реализации IMarkupServices. Также создайте два IMarkupPointers, используя метод IMarkupServices :: CreateMarkupPointer ().

Следующий вызов IMarkupServices :: ParseString () для анализа вашего HTML. Это даст вам указатель на IMarkupContainer, который содержит вашу DOM, так же, как два IMarkupPointer, которые указывают на начало и конец вашей DOM. Теперь вы можете использовать IMarkupServices :: Move () для перемещения ваших данных из одного IMarkupContainer в другой.

Таким образом, общая схема, которую вы бы использовали, это иметь один HTMLDocument, который является вашим «отображаемым» документом, и связанный с ним IMarkupContainer (для которого вы можете просто использовать QueryInterface ()). Тогда у вас есть вектор или список или что-то из всех не отображаемых контейнеров разметки. Затем вы просто создаете указатель разметки для вашего экранного документа, вызываете IMarkupPointer :: MoveToContainer (displayDocumentContainer, true), а затем используете его для перемещения содержимого из контейнера отображения в контейнеры, не отображаемые на экране, и наоборот.

Заметьте одно: вы должны получать доступ к этим объектам только в потоке, из которого вы их создали, или приобретать их. Все объекты IE являются объектами STA. Если вам нужен многопоточный доступ, вы должны выполнить маршал.

Если у вас есть конкретные уточняющие вопросы, дайте мне знать.

Ссылки:

1 голос
/ 11 марта 2009

Мне действительно нужно знать больше о том, как вы генерируете эти документы. Возможно, будет быстрее получить ваши данные в XML-документе, а затем использовать XSL-преобразование для преобразования данных в HTML и передачи их в элемент управления WebBrowser.

Приятной особенностью XSLT-реализации .NET является то, что он берет исходный код XSL и компилирует его во временную сборку для ускорения преобразований.

Если вы решите пойти по этому пути, посмотрите проект MVP.XML, который добавляет некоторые полезные функции exslt в стандартную реализацию XSLT.

0 голосов
/ 11 марта 2009

Не могли бы вы сделать что-то подобное?

  • Создайте содержимое, которое вы хотите отобразить внутри DIV
  • Создание вторичного содержимого (в фоновом режиме) внутри невидимых DIVs
  • Поменяйте содержимое, играя с видимостью
0 голосов
/ 25 февраля 2009

Может быть, вместо кэширования DOM, вы можете просто переключаться между несколькими элементами управления WebBrowser в форме - при этом виден только активный элемент?

...