Unfortunately OnFrameLoadStart is called before the DOM is loaded, so you'll need to use one of the follow: FrameLoadEnd/LoadingStateChanged/IRenderProcessMessageHandler.OnContextCreated. Here are a few examples
browser.RenderProcessMessageHandler = new RenderProcessMessageHandler();public class RenderProcessMessageHandler : IRenderProcessMessageHandler{ // Wait for the underlying `Javascript Context` to be created, this is only called for the main frame.
// If the page has no javascript, no context will be created.
void IRenderProcessMessageHandler.OnContextCreated(IWebBrowser browserControl, IBrowser browser, IFrame frame)
{ const string script = "document.addEventListener('DOMContentLoaded', function(){ alert('DomLoaded'); });";
frame.ExecuteJavaScriptAsync(script);
}
}//Wait for the page to finish loading (all resources will have been loaded, rendering is likely still happening)browser.LoadingStateChanged += (sender, args) =>
{ //Wait for the Page to finish loading
if (args.IsLoading == false)
{
browser.ExecuteJavaScriptAsync("alert('All Resources Have Loaded');");
}
}//Wait for the MainFrame to finish loadingbrowser.FrameLoadEnd += (sender, args) =>
{ //Wait for the MainFrame to finish loading
if(args.Frame.IsMain)
{
args.Frame.ExecuteJavaScriptAsync("alert('MainFrame finished loading');");
}
};
Note: Scripts are executed at the frame level, ever page has at least one frame (MainFrame). The IWebBrowser.ExecuteScriptAsync extension method is left for backwards compatibility, you can use it as a shortcut to execute js on the main frame.
2. How do you call a Javascript method that return a result?
If you need to evaluate code which returns a value, use the Task<JavascriptResponse> EvaluateScriptAsync(string script, TimeSpan? timeout) method. Javascript code is executed asynchronously and as such uses the .Net Task class to return a response, which contains error message, result and a success (bool) flag.
// Get Document Heightvar task = frame.EvaluateScriptAsync("(function() { var body = document.body, html = document.documentElement; return Math.max( body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight ); })();", null);
task.ContinueWith(t =>
{ if (!t.IsFaulted)
{ var response = t.Result;
EvaluateJavaScriptResult = response.Success ? (response.Result ?? "null") : response.Message;
}
}, TaskScheduler.FromCurrentSynchronizationContext());
Scripts are executed at the frame level, ever page has at least one frame (MainFrame)
Only trivial values can be returned (like int, bool, string etc) - not a complex (user-defined) type which you have defined yourself. This is because there is no (easy) way to expose a random Javascript object to the .NET world, at least not today. However, one possible technique is to turn the Javascript object you wish to return to your .NET code into a JSON string with the Javascript JSON.toStringify() method and return that string to your .NET code. Then you can decode that string into a .NET object with something like JSON.net. See this MSDN link for more information. (https://msdn.microsoft.com/en-us/library/ie/cc836459(v=vs.94).aspx)
3. How do you expose a .NET class to Javascript?
Like this:
public class BoundObject{ public string MyProperty { get; set; } public void MyMethod()
{ // Do something really cool here.
}
}// ...// After your ChromiumWebBrowser has been createdbrowser.RegisterJsObject("bound", new BoundObject());
In the actual JS code, you would use the object like this:
bound.myProperty; // use this syntax to access the propertybound.myMethod(); // use this to call the method.
Please note:
By default methods and properties are changed into CamelCase, i.e. the first letter is lower-cased, to make its usage be more smooth together with the rest of your Javascript code. For 39.0.1 and greater this is optional and this behavior can be specified using the camelCaseJavascriptNames boolean param
RegisterJsObject should be called directly after you create an instance of ChromiumWebBrowser. After the internal CEF browser instance has been initialized subsequent calls to RegisterJsObject will throw an exception (there's no on the fly binding as yet RegisterJsObject see #602)
Complex objects are supported for properties so you can now do bound.subObject.myFunction() and bound.subObject.myProperty = 1.
Complex object support for functions is limited to trivial values (like int, bool, string etc)
For those upgrading from CefSharp1 the global CEF.RegisterJsObject has been removed, for now you have to bind using the method directly on ChromiumWebBrowser.
4. Why do I get an error about "Could not load file or assembly 'CefSharp.Core.dll' or one of its dependencies. The specified module could not be found." when trying to run my CefSharp-based application? It compiles successfully, but does not run? It runs on my developer machine, though throws an exception when I copy it to another computer?
This is a common error, typically one of the following
VC++ 2012/2013 Redistributable Package is required in order to run CefSharp on non developer machines. See FAQ #6 below for more information. You can include the required dlls as part of your application.
Not all dependencies are present in the executing folder. CefSharp includes unmanaged dll's and resources, these are copied to the executing folder via two .props file which are included in your project when you install the Nuget packages. See list of required files below, make sure the required files are present.
You packaged your application for distribution via an installer and it doesn't run on the target machine. Installers don't include the unmanaged resources by default, you'll need to add them manually. For ClickOnce, see #1314 for some pointers and solutions other users have come up with.
NOTE: This also applies if you get a FileNotFoundException when initializing the WPF control in XAML.
NOTE 2: If compiling from source (not recommended, use the Nuget packages) and you notice that you can no longer build in debug mode, but release builds work just fine you may need to repair your version of Visual Studio. This happens in rare cases where you will get the same exact message as a missing unmanaged .dll file as shown above.
5. Why does the Visual Studio WPF designer not work when I add a ChromiumWebBrowser to my app?
This is unfortunate, and a consequence of the fact that CefSharp is written in C++ code which in turn references CEF DLL:s. That scenario isn't so well-supported by the Visual Studio designer. This forum thread explains it a bit further and also gives a possible workaround. I think (unfortunately) that the easiest workaround is to just accept the fact that it's not easy to support and just live with it, but there are also other approaches if you really feel you need it.
CefSharp requires the VC++ Runtime. You have a few options for installing/including this with your app:
You can install VC++ on every machine on which you wish to run your CefSharp based application. Once installed updates can then be managed via Windows Update.
You can either set the Visual Studio C++ redistributables as pre-requisites of the installer (i.e. ClickOnce or WiX Toolset)
By copying over to your project the contents of this folder (Only present if you have the matching version of Visual Studio installed):
# For VC++ 2012 (x86)
C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\redist\x86\Microsoft.VC110.CRT
# For VC++ 2012 (x64)
C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\redist\x64\Microsoft.VC110.CRT
# For VC++ 2013 (x86)
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\redist\x86\Microsoft.VC120.CRT
# For VC++ 2013 (x64)
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\redist\x64\Microsoft.VC120.CRT
With the 3rd approach you won't need to install the prerequisite Visual C++ 2012/2013 Runtime Files to your client. For the time being the plan is to stay on VC2013 for official CefSharp binary releases. We might switch to VC2015 when feasible. If you build your own from source what you deploy of course has to match your build environment. For the official Nuget releases see the Releases Branches table for details.
A new option is JetBrains have a Microsoft.VC120.CRT.JetBrains package on Nuget.org, appears to include the relevant files, you would still need to hook up some sort of post build task to copy them to your bin folder.
Note When building from source make sure you compile in Release mode when deploying to machines that don't have Visual Studio installed. Visual C++ uses a different set of run-time libraries for Debug and Release builds. The Debug run-time libraries are only installed with Visual Studio. If you use the official Nuget packages they're already built in Release mode and you can subsequently build your app in debug mode as only the Visual C++ projects need to be compiled in Release mode.