Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I load HTML into Webbrowser control for WPF?

My WPF client application is building a custom HTML page, I can load the HTML like this,

this.myWebBrowser.NavigateToString("<html><body><p>test page</p></body></html>");

The problem I have is how do I load custom HTML into the Webbrowser control, if the HTML has images and css file in it?

How do you reference the images and css? Can the images and css be embedded into the application, or do they need to be in a directory somewhere?

Thanks for the help.

like image 846
Tony Avatar asked Dec 08 '10 18:12

Tony


People also ask

How to use WebBrowser control in WPF?

The WebBrowser ControlOpen the MainWindow. xaml and add below xml code. It consist of 3 buttons 2 of whic are for navigating, 1 for refreshing between pages, a textbox for entering url and a WebBrowser control for displaying our web contents. The WebBrowser control comes with various features by default.

How do I open an HTML file in WPF?

Process. Start method. But before you have to open your file, you must be included in the application folder for this, you can click right on the file go -> properties and the properties box, select Copy if newer on the property Copy to Output Directory .


3 Answers

Actually, there is such a thing as an HTML page with embedded images.

You can embed both images and CSS inside an HTML string, using the data URI scheme. However, not all versions of IE support this, and the WebBrowser control is really IE. If your code might run on a machine with IE < 8, this approach won't help you.

Another option would be to store your images and CSS as embedded resources, write them out to temp files, and then insert absolute URL's to the temp files when you generate your HTML.

like image 76
Joel Mueller Avatar answered Sep 20 '22 18:09

Joel Mueller


Since you are generating the HTML, you can set the base url of all script/image by generating a base element which points to somewhere you have control over, like file:/// url pointing to a folder on the disk, a url pointing to localhost where your local web server is listening (too many http server samples on the internet so I don't get into details here), or your web site on the www.

When you navigate to string, the HTML would be rendered in the same interenet zone as about:blank. Depending on the client's IE security zone settings, your HTML may not have have permission to load files in certain locations (like script files on the computer if the page is in the Internet zone).

You can use the Mark of the Web to change your HTML page's internet zone.

like image 35
Sheng Jiang 蒋晟 Avatar answered Sep 17 '22 18:09

Sheng Jiang 蒋晟


For the reference, I've stumbled upon this question and used the Joel Mueller answer, but decided to automate parsing the image paths. Maybe somebody will found my code useful for a starter of a similar solution - it's quite rough and dirty, but seems to do the job well.

I am using C# resources, inside my html files I only put image filenames. It also allows me to open the file in a normal browser for testing how it'll look. The code automatically looks for the resource with the same name as filename inside the html, saves it under application data directory, and substitutes the path.

It's also worth noting that the application will overwrite the file if it differs from the already saved one. It was mainly needed for the development, but I didn't really had many of those files, so I didn't care about the performance loss here. Omitting this check and assuming the files are up-to-date should enhance the performance.

Settings.Default.ApplicationId is a simple string with an application name, used for the directory name inside application data.

That's how my class ended up looking:

    class MyHtmlImageEmbedder
    {
        static protected string _appDataDirectory =
            Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
                Settings.Default.ApplicationId);

        static public string getHtml()
        {
            String apiHelp = Resources.html_file;
            Regex regex = new Regex(@"src=\""(.*)\""", RegexOptions.IgnoreCase);
            MatchCollection mc = regex.Matches(apiHelp);
            foreach (Match m in mc)
            {
                string filename = m.Groups[1].Value;
                Image image = Resources.ResourceManager.GetObject(Path.GetFileNameWithoutExtension(filename)) as Image;
                if (image != null)
                {
                    var path = getPathTo(Path.GetFileNameWithoutExtension(filename) + ".png", imageToPngByteArray(image));
                    apiHelp = apiHelp.Replace(filename, path);
                }
            }
            return apiHelp;
        }

        static public string getPathTo(string filename, byte[] contentBytes)
        {
            Directory.CreateDirectory(_appDataDirectory);
            var path = Path.Combine(_appDataDirectory, filename);
            if (!File.Exists(path) || !byteArrayCompare(contentBytes, File.ReadAllBytes(path)))
            {
                File.WriteAllBytes(path, contentBytes);
            }
            return path;
        }

        [DllImport("msvcrt.dll", CallingConvention = CallingConvention.Cdecl)]
        static extern int memcmp(byte[] b1, byte[] b2, long count);

        public static bool byteArrayCompare(byte[] b1, byte[] b2)
        {
            // Validate buffers are the same length.
            // This also ensures that the count does not exceed the length of either buffer.  
            return b1.Length == b2.Length && memcmp(b1, b2, b1.Length) == 0;
        }

        public static byte[] imageToPngByteArray(Image image)
        {
            MemoryStream ms = new MemoryStream();
            image.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
            return ms.ToArray();
        }
    }

Please note that the byteArrayCompareFunction uses memcmp only for performance reasons, but it can be easily substituted with a simple compare loop.

Then, I'm just calling browser.NavigateToString(MyHtmlImageEmbedder.getHtml());.

like image 32
trakos Avatar answered Sep 17 '22 18:09

trakos