- Используем HTML и WebBrowser control в качестве UI для обычных windows-приложений на C#
- Creating an HTML UI for Desktop .NET Applications
- Key takeaways
- Why Create HTML UI for Desktop Apps?
- Related Sponsored Content
- Related Sponsor
- Choosing the Tool
- Getting Started
- Using DotNetBrowser API
- Adding BrowserView to Window
- Chromium DevTools
- Loading Web Page
- DOM Events
- Improving Interaction
- Using VB.NET or WinForms
- Conclusion
- About the Author
Используем HTML и WebBrowser control в качестве UI для обычных windows-приложений на C#
Как известно, контрол WebBrowser это просто обертка над ActiveX компонентом Internet Explorer. Следовательно он предоставляет доступ к полноценному layout-движку со всеми современными плюшками. А раз так, то попробуем (сам не знаю правда зачем) на его основе сделать пользовательский интерфейс для обычного windows-приложения.
Можно, конечно, было бы запустить в этом же процессе мини веб-сервер (на HttpListener например) и ловить запросы через него, но это слишком просто, скучно и неспортивно. Попробуем обойтись без сетевых компонентов, just for fun.
Итак, задача проста — необходимо перехватывать отправку HTML-форм и выводить новый HTML-документ, сгенерированный логикой приложения в зависимости от POST-параметров.
Прежде всего нам понадобится Windows Forms Application с одной единственной формой на которой будет один единственный контрол — WebBrowser занимающий все пространство.
Для примера рисуем пару простых страниц интерфейса (с минимальным содержимым для краткости, а так скрипты и стили добавлять по вкусу).
Примечание: X-UA-Compatible необходим для корректного отображения некоторых стилей, в данном примере они не используются, но проблема есть. Не буду вдаваться в детали, но без этого компонент рисует страницы в режиме совместимости с чем то очень старым, со всеми вытекающими последствиями.
WebBrowser предоставляет несколько событий, среди которых есть например Navigating, которое срабатывает перед тем как отправить форму или перейти по ссылке.
Практически то что нужно, но это событие не предоставляет никакой информации о post-параметрах. GET-параметры использовать не получится поскольку у наших HTML-форм атрибут action отсутствует, что приведет к тому что в качестве URL всегда будет about:blank и никакой информации о GET параметрах не будет.
Для получения более подробной информации о запросе надо подписаться на событие BeforeNavigate2 (подробнее тут) у внутреннего COM-объекта браузера, благо он доступен через свойство ActiveXInstance.
Сделать это проще всего через dynamic, чтобы не возиться с объявлением COM-интерфейсов:
Объявляем делегат:
Затем подписываемся на событие (в конструкторе формы у WebBrowser свойство ActiveXInstance будет null, потому это лучше сделать после того как окно загрузится, т.е. в OnLoad например):
Итак, в PostData лежат post-параметры в виде строки состоящей из пар ключ=значение объединенных через &. Разделяем их и укладываем в словарь:
Кроме того, в этом обработчике лучше отменить действие через параметр Cancel, чтобы лишний раз не попадать на about:blank.
Имея параметры генерируем текст новой страницы. Сюда теоретически прикручивается какой-н менеджер обработчиков, выбирающий необходимый обработчик в зависимости от параметров, которые по каким-н шаблонам будут собирать страницы из кусочков, но для краткости пока для примера просто по кнопке page1 откроем первую страницу, по кнопке page2 — вторую (имена кнопок в разметке указывать обязательно, иначе из post-параметров не определить какую именно кнопку нажали), а также заменим все строки в круглых скобках на значения параметров с такими именами:
Полученную строку с HTML-текстом записываем в свойство DocumentText WebBrowser-а.
И тут же получим бесконечный цикл перезагрузки страницы, поскольку установка этого свойства спровоцирует новый вызов OnBeforeNavigate2.
Временно отписаться от этого события не получится, поскольку вызывается оно откуда то из цикла обработки сообщений уже после того как установка DocumentText возвращает управление.
Т.о. необходимо всегда игнорировать каждый второй вызов обработчика, поскольку первое срабатывание это отправка формы в результате действий пользователя, которое обрабатывать нужно, а второе — отображение результата которое обрабатывать не нужно. Для простоты будем в начале обработчика OnBeforeNavigate2 переключать bool переменную.
И вот результат:
Это все что необходимо для минимального приложения. Но работать таким образом будет не все — за рамками осталось например получение данных о файлах для input type=«file», а также работа с XMLHttpRequest для корректной работы скриптов со всякими там ajax.
Creating an HTML UI for Desktop .NET Applications
Dec 30, 2016 11 min read
Key takeaways
- The UI looks of the desktop .NET applications can be significantly improved if created not with standard means, but using HTML.
- Chromium-based browser components perform well rendering UI created with modern web instruments.
- Support of JavaScript calls and DOM access are essential criteria to implement two-way communication and should be considered before going for HTML UI
- The Chromium DevTools simplify debugging your HTML UI significantly, that’s why support of this set of tools can be crucial for the component.
- It is possible to create the modern HTML UI not only for WPF applications, but also for Windows Forms.
Why Create HTML UI for Desktop Apps?
There are a great number of .NET applications built for desktop, meant for desktop and working great on desktop, but looking painfully archaic due to the UI, created with the good old Windows Forms or Windows Presentation Foundation (WPF). This detail, while often insignificant for developers, can be perceived as deadly sin by the design-savvy user audience.
Related Sponsored Content
Best Practices for Creating Secure Applications
Related Sponsor
What are today’s hot technology trends?
Join our upcoming Tech Talks to learn how you can quickly create applications that evolve as business needs and technology trends change.
Unlike desktop, trends in web development evolve rapidly, constantly presenting new tools for ever better look of web apps. The mighty combo of HTML5 and CSS3 allows creating attractive and functional interfaces with loads of room for customization.
No wonder then that developers are looking for ways to employ the richness of the Web UI in desktop applications. The common approach to do this is to embed a browser component to render the HTML UI within the desktop app.
Choosing the Tool
When it comes to choosing a browser component for the .NET app, the choice is among a number of alternatives: from the default WebBrowser control to open source solutions and the components, licensed commercially.
Since we’re looking for options to display the UI created with the modern web tools, we’ll have to pass the default WebBrowser since it is lacking the essential functionality required to render complex pages that use HTML5 or CSS3.
Open source components, while being quite functional and generally pulling their weight, are not always appropriate for use in the commercial projects. This may be due to several reasons:
including corporate procurement policies that disallow the use of the open source software, and massive legal effort required to check and approve the licensing terms for hundreds of components. Another important concern, often posed by the creators of the commercial products, is absence of dedicated support and no exact commitments for the fixes and updates of the open source solutions. In fact, when selecting an open source solution you are frequently left on your own with all its challenges. There are quite a number of teams who would gladly have someone qualified take care of the component-specific issues so that they are free to work on their product.
Finally, there’s a number of commercial browser components suitable for developers, willing to opt for the safety and support of the proprietary software. Picking one of the available alternatives is a matter of the one’s taste. However, there are some universal criteria to look at, when choosing a software provider, e.g.: availability and qualification of support, frequency of updates and compliance with the modern standards.
In this tutorial, we’ll use the proprietary Chromium-based web browser component – DotNetBrowser by TeamDev Ltd. It is well-documented, updated on a monthly basis and comes with the professional support packages for any team size.
The underlying Chromium engine allows DotNetBrowser to display modern UI, built with HTML, as well as more complicated things like WebGL, WebRTC and Flash. For the purpose of this tutorial we’ll use the browser component to tackle following tasks:
- Load and display a web page as an integral part of a WPF Application
- Implement two-way communication between C# and JS
- Listen to DOM events
- Debug the loaded content using Chrome Developer Tools
Moreover, among existing browser components for .NET only DotNetBrowser provides API that allows to work with the DOM directly without adding JavaScript injections to your code. This API significantly simplifies access and modification of the web page data from the .NET side, as you will be able to see further in this article.
Getting Started
To use DotNetBrowser in your project, you’ll need to download it from its page and while there obtain a free 30-days evaluation licence. DotNetBrowser is also available at nuget.org as a regular NuGet package. You can install it directly from Visual Studio using its NuGet manager.
Also, there is a VSIX package in the Visual Studio Gallery. This package adds DotNetBrowser UI controls directly to the Visual Studio Toolbox, and then you can use them in the UI designer.
Using DotNetBrowser API
Let’s proceed to creating HTML5 UI for a WPF application with the DotNetBrowser.
Adding BrowserView to Window
DotNetBrowser supports XAML markup, so you can describe a BrowserView in XAML right after creating a sample WPF application and setting up the DotNetBrowser dependencies:
Now let’s load a URL and run the sample to be sure that everything is set properly:
Chromium DevTools
DotNetBrowser supports Chromium Developer Tools, so it is possible to inspect HTML, view CSS styles, run various commands and debug JavaScript code right from the DotNetBrowser control. Enabling DevTools is described in the article “Remote Debugging” on DotNetBrowser support site. The obtained remote debugging URL can be then loaded into Google Chrome.
To try this feature, we’ll add a context menu with “Copy Debug URL To Clipboard” item to the component. Here is the modified XAML:
The modified source code looks like shown below:
Now let’s try to use remote debugging.
After selecting the menu item, a message box appears, saying:
After pasting and loading this URL in Google Chrome, we are able to inspect the loaded page.
Loading Web Page
When we are sure that everything is configured properly, the next step is to create a web page that will act as interface for our application. Here is the source code of the UI page we’ve created:
After that, we’ll need to save this page as ui.html and include this page to our sample project. Then we’ll modify the LoadURL() call as shown below:
After compiling and starting the sample application, the main window looks like this:
As you can see, this sample form already looks like an integral part of the application. But we still need to obtain its data when a Submit button is clicked.
DOM Events
DotNetBrowser provides DOM API that allows to access each and every part of the application. Moreover, we are able to register event listeners for particular DOM elements and be informed about the DOM events.
First of all, let’s add the FinishLoadingFrameEvent handler to the Browser:
The event handler implementation:
This event handler should be installed right before LoadURL() is called.
The OnSubmitClicked is an event handler that reads the form data and displays a message with obtained values.
After running the application and clicking the Submit button, we can see the following message:
Improving Interaction
During further testing of this simple application, you will face the following problem: the first name and last name values are always equal to the “value” attribute of the field, even if the real value of the field has already been changed. This is the known behavior: we’re running up against the difference between attributes and properties. When you set the value of the element from JavaScript or manually, you are actually setting the property ‘value’ but the attribute of the element in the page source is not changed. Fortunately, there is another way to get actual data from the form fields.
DotNetBrowser provides a specific API to access the ‘value’ property directly. Let’s modify the OnSubmitClicked event handler and obtain the actual values via the DOMInputElement class:
As you can see, the values are obtained in a separate thread. Such approach allows to avoid deadlocks during call.
Let’s start the modified application and change the form data:
After the submit button is hit, the following message is displayed:
As you can see, the message contains up-to-date values.
Using VB.NET or WinForms
If you prefer VB.NET to C#, or require HTML UI for Windows Forms application, the general idea remains the same. If you use VB.NET, almost all the differences will be syntax-related.
If you use WinForms instead of WPF, the main difference would be in the process of adding the BrowserView control to your form. You can add it directly in the source code, but of course this is not an optimal way of doing it. It would be more natural to drag and drop the control to your form from the Visual Studio Toolbox. You can add DotNetBrowser controls to the Toolbox quite easily via the VSIX package available at the Visual Studio gallery. This package installs both WPF and WinForms controls to the Toolbox automatically.
When you have the BrowserView control added, next step would be to add a context menu, this time using the built in capabilities of WinForms. Then you can go back to follow this instruction starting with the Loading Web Page section.
Conclusion
As you can see, implementing the HTML-based UI in your .NET app doesn’t have to be painful. The approach described here can be used to effectively combine the advantages of the modern web technologies with your expertise in .NET.
About the Author
Anna Dolbina is a technical lead at TeamDev Ltd. A savvy .NET developer, Anna is in charge of development of DotNetBrowser – a company’s Chromium-based .NET browser component. Apart from .NET framework, she is interested in developing integration software in Java and C++, especially if the solution involves interaction with operating systems and native libraries and components.