If You Like It, Put an HTML5 UI on It

CodeGuru content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Okay, cheesy title I know, but it got your attention, right?

I’m guessing you’re already thinking that in this post we’re going to be discussing HTML5 User Interfaces.

Well, we are, but not quite in the context you might be expecting. Because this column tries to cater to general .NET-related things, dedicating an entire post specifically to HTML5 (even if it is being generated by C# and/or .NET code) doesn’t do it justice.

There is, however, an area of HTML5 that often gets overlooked, but depending on your needs can actually be quite useful, and that’s the subject of adding an HTML5 User Interface directly to your desktop applications, as Figure 1 shows:

Like01
Figure 1: The HTML5 interface

This is actually a regular Windows Forms application. You can tell this by the normal windows window furniture, and the two buttons in the top left corner. In the middle, however, we have a regular HTML5 page, styled and using the popular Twitter Bootstrap UI toolkit.

The question arises, however, why might we want to create a desktop application this way?

Desktop Applications, as Browsers…

It’s not as silly as it might seem. There are still many users out there who have to use a PC in a normal office environment on a day-to-day basis.

In places like customer call centres, or tourist information kiosks, you often want to be able to control the web/browser access, and libraries or training and learning centres may have specialist requirements that mean an access card, or barcode, bluetooth key fob, and many other devices may be needed to allow a student to have access.

There are still many areas of the world where a person’s only access to the Internet is via an Internet cafe (where they may have to pay for a time limit) or where government regulations mean that access to certain sites is denied or heavily monitored.

In situations like this, using a regular browser might not be desired. It might even be a case that the only application running on the machine is the custom browser you’ve written, meaning there’s no desktop or settings or anything else for the user to interact with.

As a parent, you might want to wrap your child’s Internet experience so you can be sure that they can only access certain sites. For example, not too long ago I was asked to write a custom browser that would scan incoming images and give them a “Nudity Score”, reporting images that had a score of 50% or more to a given email address.

Lastly, there’s the re-use argument too. If a company has several web-based products that they also need to supply as traditional desktop apps, it makes sense to reuse the user interface elements that existing users are familiar with where possible.

I’m Sold. So How Do I Do This, Then?

Many of the browsers you know and love (IE, Chrome, Firefox, and so on) actually have embedded versions. Many of you might already know this if you’re a heavy .NET developer and I’ve written previously in this column about using embedded IE to scrape data from websites.

In the case of this post, however, we’re going to take a look at “CEF” the “Chrome Embedded Framework” or more specifically, the .NET bindings for it called “CEF Sharp”:

https://github.com/cefsharp

CEF Sharp is a set of .NET assemblies that allows you to embed a Chrome browser directly into your Windows Forms and WPF-based applications. There’s even a version that you can use that performs off-screen rendering. You can’t see the output, but you can render it, monitor things like the JavaScript code for errors, and such like.

Because you’re effectively controlling the browser from inside your application, you can do a lot of things you wouldn’t normally do from a regular Chrome browser. You can, for example, store session and login information in the local computer’s memory; you can make the app top-most full screen and enforce it so nothing else can be used, and many other things.

Let’s give it a try. Fire up Visual Studio and create a new winforms application. (You can do a WPF app if you want; the steps are broadly the same, but my example will be a winforms-based app.)

Once you have an application skeleton created, head to NuGet and search for, then install, “CefSharp”:

Like02
Figure 2: Installing “CefSharp”

Word of warning: When I did my initial install, I got an error about not being able to install “CefSharp.Common”. I chose to install the Winforms assembly, thinking that the dependencies would install automatically, and I had to install cefsharp.common separately first, and then go back and install the winforms assembly before things succeeded.

There do seem to be some glitches with the package, which the development team are aware of. Their advice, and advice that I’ll repeat here is, install CefSharp; then, close down Visual Studio completely, followed by re-opening it, and then reloading your project before doing anything else.

Based on previous use, I can 100% tell you, this will save a lot of head scratching, and it’s always an excuse to go make a cup of coffee. 🙂

Once you get back up and running, the next thing you should do is to choose a platform target for your application.

Because of the unmanaged DLLs used behind the scenes, you cannot use the “AnyCPU” profile. You must choose x86 or x64 and your .NET version must be .NET v4 or higher.

The trick here, however, is slightly different to what you might normally do.

Most people would instinctively head for the “Project Options” dialog, and change from “AnyCPU” to X86/X64 in there:

Like03
Figure 3: The Project Options page

This won’t, however, stop CefSharp from stopping your project building.

You also need to change the build platform, too, by right-clicking your solution folder, opening the configuration manager, and adding a 64 bit or 32 bit platform target.

Open the Configuration Manager:

Like04
Figure 4: Opening the Configuration Manager

Then, click “Active Solution Platform”, choose New, and create a new configuration based on either your Debug or Release build:

Like05
Figure 5: Creating a new configuration

Once you’ve created the correct build configuration, you should be able to build your app without getting a platform selection error.

Now the fun begins….

You can add a CefSharp object directly to a window if you want, but to better control the positioning, it’s advised that you add it to a panel or some other similar container.

In my case for the sample, I’ve created a window layout consisting of three panels.

In the top panel, I’ve added a couple of standard .NET buttons; in the bottom panel, I’ve added a list box to add as an “Event Log”; and the middle panel is blank because this is where I’ll be placing the browser. My form layout looks as follows:

Like06
Figure 6: Adding the event log

To make use of CefSharp, you need to add a “using CefSharp” and a “using CefSharp.WinForms” statement to your form code behind. Then, you need to create a private variable as follows:

private ChromiumWebBrowser _browser;

In your Solution Explorer, create a folder called “pages”. Then, add a simple HTML file called “start.html”:

Like07
Figure 7: Creating the Pages folder

As you can see from Figure 7, I’ve added other pages, including scripts/styles to my project because I’m also using twitter bootstrap to style my pages. I’ll be making the entire project available on my git-hub account at:

https://github.com/shawty/CefSharpExample

so feel free to clone it and explore the code in more detail; in the post I’ll only be mentioning the important points. I encourage you to clone the repo if you want to play with the fully working example.

Once you have everything set up, add the following code to your Form’s code behind, and run your application by pressing F5:

private static readonly string _pagesPath =
   Path.Combine(_myPath, "Pages");
private ChromiumWebBrowser _browser;

private string GetPagePath(string pageName)
{
   return Path.Combine(_pagesPath, pageName);
}

private void ChangePage(string pageName)
{
   _browser.Load(GetPagePath(pageName));
}

public FrmMainForm()
{
   InitializeComponent();

   WindowState = FormWindowState.Maximized;
   InitializeBrowserControl();
}

private void InitializeBrowserControl()
{
   _browser = new
      ChromiumWebBrowser(GetPagePath("start.html"))
   {
      Dock = DockStyle.Fill
   };

   PnlHtml.Controls.Add(_browser);
}

If everything’s worked, your application should start up, go full screen, and have your “start.html” page loaded in the middle of it:

Like08
Figure 8: The “start.html” page on your screen

If you want to start up on a specific website, change the line where it says

_browser = new ChromiumWebBrowser(GetPagePath("start.html"))

to be something like

_browser = new ChromiumWebBrowser("http://www.google.co.uk")

With using local files, however, you now have the option to build your entire WinForms application UI using HTML5 and JavaScript.

The best part, however, is that your .NET code can easily interact with the JavaScript code in the loaded page.

In my example, the page title, where it says “.NET Nuts and Bolts….”, is implemented using a DIV tag and the Bootstrap page header styles.

Because I’m using Bootstrap, that means that I also have jQuery loaded in the page.

By using jQuery, we can easily find our page header with an id = “pageHeader” and change its contents using the following snippet of JavaScript:

var header = $('#pageHeader');
$(header).children('h1').children('small').text
   ('Welcome to the future of UI').addClass('text-success');

In my example, I’ve attached this script to one of the .NET buttons on my top blue panel, and then asked the CEFSharp browser to execute the above JavaScript on my page for me, using the following method:

private void BtnChangeHeaderClick(object sender, EventArgs e)
{
   string script = "";
   script += "var header = $('#pageHeader');";
   script += "$(header).children('h1').children('small')
      .text('Welcome to the future of UI')
      .addClass('text-success');";

   _browser.ExecuteScriptAsync(script);
}

The ExecuteScriptAsync call will take the string passed to it, and execute that in your page’s JavaScript interpreter, and, in this case, will change the page header from:

Like09
Figure 9: Page header 1

to:

Like10
Figure 10: Page header 2

In the example project, I’ve provided a couple more examples that save and populate the contents of the two fields you can see on the form in the page.

It’s also possible to call .NET functions from within your JavaScript code in the page.

You do this by creating classes containing your data and methods that you want to expose to the page.

At the moment, properties in a class are read only. You can set them by using a method, but you can’t set them directly from .NET code.

To expose a .NET object to your JS code, you have to register it when you create your browser object. First, create a simple class:

using System.Windows.Forms;

namespace cefsharp_v2
{
   public class MyObject
   {
      public void MyThingToCallFromJavaScript
         (string parameterOne, int parameterTwo)
      {
         MessageBox.Show("This is a message box in .NET
            that got " + parameterOne + " and a value
            of " + parameterTwo);
      }

   }
}

Once you’ve created the class in your project, go to the code you added earlier, where you created the CefSharp browser object, and made it visible.

Alter that code so that it now looks like the following:

private void InitializeBrowserControl()
{
   _browser = new ChromiumWebBrowser
      (GetPagePath("start.html"))
   {
      Dock = DockStyle.Fill
   };

   PnlHtml.Controls.Add(_browser);

   _browser.RegisterJsObject("myObject",
      new MyObject());
}

As you can see, we create a new instance of our class and register it to the browser object.

The first parameter, “myObject”, is the prefix you’d like to make available to call your object by.

There’s also a third parameter that defaults to “true”, which means call my methods as “camel Case” methods, that is, make all my identifiers when registering, so that the first letter of each method name is in lowercase. If you set this third parameter to “false”, the calling scheme for the function names will exactly match how you spelled them when defining the function.

I’ll leave things as they are for this example, and use camel case. With your class registered, somewhere inside any of your pages, and using JavaScript you now can do the following:

myObject.MyThingToCallFromJavaScript
   ("Some text in a string", 20);

and when you trigger this, either as a form post, or from an HTML button, you’ll find that your HTML page calls directly into your .NET code.

In my example project, I’ve provided a much better example, where the contents of the form can be saved, and when the form is “posted” its inputs are validated not by the server, but by the Windows Forms application hosting things.

There’s lots more you can do here. You intercept downloads, see the request URLs before they’re dispatched, and there are lots of different events you can hook to provide your application with all sorts of feedback.

You also can use CEF Sharp for data scraping, much more effectively than the built-in IE control. My sample application is just a small snippet of what’s available.

Got a tricky .NET issue you want to solve, or think you’ve spotted some strange APIs in the wild you’re curious about? Tweet me at “@shawty_ds”, and you might just see it featured in a future column.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read