Displaying html from string in WPF WebBrowser control
The WebBrowser
has a NavigateToString method that you can use to navigate to HTML content. If you want to be able to bind to it, you can create an attached property that can just call the method when the value changes:
public static class BrowserBehavior
{
public static readonly DependencyProperty HtmlProperty = DependencyProperty.RegisterAttached(
"Html",
typeof(string),
typeof(BrowserBehavior),
new FrameworkPropertyMetadata(OnHtmlChanged));
[AttachedPropertyBrowsableForType(typeof(WebBrowser))]
public static string GetHtml(WebBrowser d)
{
return (string)d.GetValue(HtmlProperty);
}
public static void SetHtml(WebBrowser d, string value)
{
d.SetValue(HtmlProperty, value);
}
static void OnHtmlChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
WebBrowser wb = d as WebBrowser;
if (wb != null)
wb.NavigateToString(e.NewValue as string);
}
}
And you would use it like so (where lcl
is the xmlns-namespace-alias):
<WebBrowser lcl:BrowserBehavior.Html="{Binding HtmlToDisplay}" />
How to show an HTML string in WebBrowser control when the address is about:blank
A document Refresh simply reloads the current page, so the Navigating
, Navigated
, and DocumentCompleted
events do not occur when you call the Refresh
method.
Using Navigating
or Navigated
event you should check if the browser is navigating or navigated to about:blank
then disable the ways that user can refresh page, including browser shortcuts, browser context menu or any other point like custom toolbar buttons and context menus you created or refresh.
For other urls, enable them again.
private void webBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
var state = (e.Url.ToString().ToLower() == "about:blank");
this.webBrowser1.WebBrowserShortcutsEnabled = !state;
this.webBrowser1.IsWebBrowserContextMenuEnabled = !state;
}
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
var content = "Custom Content";
if (e.Url.ToString().ToLower() == "about:blank" &&
this.webBrowser1.DocumentText != content)
{
this.webBrowser1.DocumentText = content;
}
}
How to properly display ' and in a WPF WebBrowser that is bound to HTML string
For that you can use a verbatim string and simply escape double quotes with an added double quote.
This sample works for me.
public partial class MainWindow : Window
{
private string html = @"<!DOCTYPE html>
<html lang=""en"">
<body>
<div>My Test HTML 'single quote', ""double quote""</div>
</body>
</html>";
public MainWindow()
{
InitializeComponent();
MyWebBrowser.NavigateToString(html);
}
}
If you are reading the HTML from a file you shouldn't need to do anything special.
MyWebBrowser.NavigateToString(File.ReadAllText(@"C:\myfilepath\myfile.htm"));
generate an HTML-file and display it immediately in a WebBrowser-Control in C#
Try to add the HTML Code to the webbrowser.DocumentText
Attribute.
StringBuilder sb = new StringBuilder();
sb.Append("<html><body>");
sb.Append("<a href=");
sb.Append("\"");
sb.Append("http://wwww.microsoft.com");
sb.Append("\"");
sb.Append(">Microsoft</a><p>");
sb.Append("Specify a URL:<br>");
sb.Append("<form method='GET'><input type='text' name='address'/>");
sb.Append("<br><input type='submit'>");
sb.Append("</body></html>");
webBrowser1.DocumentText = sb.ToString();
That's the example from http://msdn.microsoft.com/en-us/library/ms229657%28v=vs.80%29.aspx.
I hope it helps. :-)
How to load HTML string to embedded WebBrowser control?
Navigate(L"about:blank");
The posted source code does not demonstrate the problem well. It shows no errors, but also no "Hello". Only by omitting the Navigate() call does it get close to failing on nullptr errors. The code is simply not finished, it is missing the required plumbing to capture the DocumentComplete
event. Only after this event is fired can the code inside WebBrowser::setHtml() work.
Have the WebBrowser class implement the IDispatch and IUnknown interfaces:
class WebBrowser :
public IDispatch,
public IUnknown,
public IOleClientSite,
public IOleInPlaceSite,
public IStorage
{
private:
HRESULT OnCompleted(DISPPARAMS* args);
wchar_t* htmlSource;
IConnectionPoint* callback;
DWORD eventCookie;
// etc...
};
Note how the htmlSource variable is now a class member, the string needs to be stored until the DocumentComplete event fires.
We need to implement IDispatch. That's pretty easy to do, I put the code inline:
// ---------- IDispatch ----------
HRESULT GetTypeInfoCount(UINT *pctinfo) { return E_FAIL; }
HRESULT GetTypeInfo(UINT, LCID, ITypeInfo **) { return E_FAIL; }
HRESULT GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) { return E_FAIL; }
HRESULT Invoke(DISPID dispIdMember, REFIID, LCID, WORD,
DISPPARAMS *pDispParams, VARIANT *pVarResult,
EXCEPINFO*, UINT*) {
if (dispIdMember == DISPID_DOCUMENTCOMPLETE) return OnCompleted(pDispParams);
else return S_OK;
}
QueryInterface() needs to be tweaked:
HRESULT STDMETHODCALLTYPE WebBrowser::QueryInterface(REFIID riid, void**ppvObject)
{
if (riid == __uuidof(IUnknown)) *ppvObject = static_cast<IUnknown*>(this);
else if (riid == __uuidof(IDispatch)) *ppvObject = static_cast<IDispatch*>(this);
else if (riid == __uuidof(IOleClientSite)) *ppvObject = static_cast<IOleClientSite*>(this);
else if (riid == __uuidof(IOleInPlaceSite)) *ppvObject = static_cast<IOleInPlaceSite*>(this);
else
return E_NOINTERFACE;
AddRef();
return S_OK;
}
The constructor needs to subscribe the event interface:
WebBrowser::WebBrowser(HWND _hWndParent)
{
//...
// appended:
htmlSource = nullptr;
IConnectionPointContainer* container = nullptr;
webBrowser2->QueryInterface(IID_IConnectionPointContainer, (void**)&container);
container->FindConnectionPoint(__uuidof(DWebBrowserEvents2), &callback);
IUnknown* punk = nullptr;
this->QueryInterface(IID_IUnknown, (void**)&punk);
callback->Advise(punk, &eventCookie);
punk->Release();
container->Release();
}
The setText() function becomes very simple, we're not going to worry about setHtml() at all. We'll just set the htmlSource member so we know what to do when the DocumentComplete event fires:
void WebBrowser::SetText(const wchar_t* t)
{
const wchar_t* html = L"<html><head><meta http-equiv='x-ua-compatible' content='IE=edge'></head><body><code>%ls</code></body></html>";
if (htmlSource) delete[] htmlSource;
htmlSource = tkString::Format(html, t);
this->Navigate(L"about::blank");
}
And finally the added function that runs when the DocumentComplete event fires. Most of the code got moved from setHtml:
HRESULT WebBrowser::OnCompleted(DISPPARAMS* args) {
HRESULT hr;
IDispatch *pDispatch = 0;
IHTMLDocument2 *pHtmlDoc2 = 0;
IPersistStreamInit *pPSI = 0;
IStream *pStream = 0;
HGLOBAL hHTMLContent;
if (!htmlSource) return S_OK;
hr = webBrowser2->get_Document(&pDispatch);
if (SUCCEEDED(hr) && pDispatch) hr = pDispatch->QueryInterface(IID_IHTMLDocument2, (void **)&pHtmlDoc2);
if (SUCCEEDED(hr) && pHtmlDoc2) hr = pHtmlDoc2->QueryInterface(IID_IPersistStreamInit, (void **)&pPSI);
// allocate global memory to copy the HTML content to
hHTMLContent = ::GlobalAlloc(GMEM_MOVEABLE, (::wcslen(htmlSource) + 1) * sizeof(TCHAR));
if (hHTMLContent)
{
wchar_t * p_content(static_cast<wchar_t *>(GlobalLock(hHTMLContent)));
::wcscpy(p_content, htmlSource);
GlobalUnlock(hHTMLContent);
// create a stream object based on the HTML content
if (SUCCEEDED(hr) && pPSI) hr = ::CreateStreamOnHGlobal(hHTMLContent, TRUE, &pStream);
if (SUCCEEDED(hr) && pStream) hr = pPSI->InitNew();
if (SUCCEEDED(hr)) hr = pPSI->Load(pStream);
}
if (pStream) pStream->Release();
if (pPSI) pPSI->Release();
if (pHtmlDoc2) pHtmlDoc2->Release();
if (pDispatch) pDispatch->Release();
delete[] htmlSource;
htmlSource = nullptr;
return S_OK;
}
I'll leave proper cleanup as a // todo. Running this code now produces the desired outcome:
How to save-as html file, an embeded browser display?
Thanks to Jimi and the following two posts:https://weblog.west-wind.com/posts/2011/may/21/web-browser-control-specifying-the-ie-version. Save WebBrowser Control Content to HTML I have a very nice solution. It is necessary to Imports System.IO and Imports System.Text. Here is the code:
Private Sub BtHTML_Click(sender As Object, e As EventArgs) Handles BtHTML.Click
Dim htmlFile As String = "C:\users\name\fileName"
File.WriteAllText(htmlFile, WebBrowser1.Document.Body.Parent.OuterHtml, Encoding.GetEncoding(WebBrowser1.Document.Encoding))
End Sub
Related Topics
Get Ipv4 Addresses from Dns.Gethostentry()
How to Run External Program via a C# Program
C# 8 Switch Expression with Multiple Cases with Same Result
The Entity or Complex Type ' ' Cannot Be Constructed in a Linq to Entities Query
Using a List as a Data Source for Datagridview
When Is It Ok to Catch an Outofmemoryexception and How to Handle It
Check If a Property Exists in a Class
How to Run Commands on Ssh Server in C#
How to Convert Namevaluecollection to JSON String
C# Linq Where Date Between 2 Dates
Lambda Expressions in Immediate Window for VS2015
How to Split a Number into Individual Digits in C#
How to Get the Colour of a Pixel at X,Y Using C#
Should I Transform Entity (Persistent) Objects to Dto Objects