NEW!
CSHTML5 has now become OpenSilver!
We are happy to announce that CSHTML5 has been significantly improved and rebranded
to 'OpenSilver', which stands for 'Open-source reimplementation of Silverlight'. It is fully backward compatible and it can be downloaded from
OpenSilver.net. Upgrading from
CSHTML5 to OpenSilver is very easy.
Read the FAQ
MessageBox.Show("The current URL is: " + CSHTML5.Interop.ExecuteJavaScript("location.toString()"));gets compiled into the following JavaScript code:
alert('The current URL is: ' + location.toString());
double screenWidth = Convert.ToDouble(CSHTML5.Interop.ExecuteJavaScript("screen.width"));
void DisplayAMessage(string messageToDisplay) { CSHTML5.Interop.ExecuteJavaScript("alert($0)", messageToDisplay); }IMPORTANT: creating JavaScript code by concatenating strings such as in "alert(" + messageToDisplay + ")" or by using String.Format will NOT work, because the JavaScript code needs to exist at compile-time rather than at runtime. In other words, the first argument of the "ExecuteJavaScript" method must be a string literal.
CSHTML5.Interop.ExecuteJavaScript("alert('" + messageToDisplay + "')");The following code will also NOT work:
CSHTML5.Interop<.ExecuteJavaScript(String.Format("alert({0})", messageToDisplay));However, the following code WILL work:
CSHTML5.Interop.ExecuteJavaScript("alert($0)", messageToDisplay);The reason is that the compiler needs to know the string at compile-time, whereas the "String.Format" method is only executed at runtime.
void Main() { CSHTML5.Interop.ExecuteJavaScript(@" // This is JavaScript code alert('Hello from JavaScript'); // Let's call the C# method "MyCSharpMethod" from this JavaScript code. Due to the fact that it is passed as the first parameter to this ExecuteJavaScript call, we can access it with $0: $0(); ", (Action)MyCSharpMethod); } void MyCSharpMethod() { System.Windows.MessageBox.Show("Hello from C#"); }You can see another example in the source code of the WebSocket extension (where the JavaScript-based websocket calls the C#-based OnOpenCallback method) or the File Open Dialog extension (where the Open Dialog of the browser calls the OnFileOpened method of C#).
You can add JS/CSS files to your CSHTML5 project. Those files will be automatically copied "as is" to the output folder.
You can then load them by calling "Interop.LoadJavaScriptFile()" and "Interop.LoadCssFile()".
You can use the method CHSTML5.Interop.GetDiv(FrameworkElement) in order to get the DIV associated to a XAML element. For this method to succeed, the XAML element must be in the Visual Tree. To ensure that it is in the Visual Tree, you can read the IsLoaded property, or you can place your code in the "Loaded" event handler. This approach works best with simple XAML elements, such as Border or Canvas.
Alternatively, you can use the HtmlPresenter control to put arbitrary HTML/CSS code in your XAML, and then read the ".DomElement" property of the HtmlPresenter control to get a reference to the instantiated DOM element in order to pass it to the JavaScript library.
A C#/XAML-based wrapper around a JavaScript library is useful because it allows the person who uses the wrapper to consume the JavaScript library in pure C# and XAML, without ever having to write any JavaScript code.
For example, the ZIP Compression extension is a C#-based wrapper around the JSZip JavaScript library. It encapsulates all the interop between JS and C# so that the rest of the application can interact with the JavaScript library using only pure C# code.
To create such a wrapper, follow these steps:
Example | Source Code | How it works |
---|---|---|
WebSockets extension | Link | It wraps the native JavaScript "WebSocket" class into a C#-based class that can be consumed by CSHTML5 applications. |
Print extension | Link | It extracts the HTML DOM element that corresponds to the specified FrameworkElement, copies it into a new browser window, and then calls the browser Print command on the new window. |
File Open Dialog extension | Link | It adds the <input type='file'> tag to the HTML DOM, and listens to the JavaScript "Change" event to return a JS blob or text. |
File Save extension | Link | It wraps the open-source JavaScript "FileSaver.js" library into a C#/XAML class for consumption by CSHTML5-based apps. |
Unofficial ArcGIS Mapping Control for CSHTML5 | Link | It wraps the JavaScript-based version of the ArcGIS mapping library into a C#/XAML-based control that can be consumed from pure C#/XAML code. |
ZIP Compression extension | Link | It wraps the open-source JavaScript "JSZip.js" library into a C#/XAML class that mimics the method signatures of Ionic.Zip (DotNetZip). |
Many more open-source extensions can be found on the Extensions Gallery page.
Use this method to call JavaScript code from within your C# code.
For example, the following C# code will display the current URL:MessageBox.Show("The current URL is: " + CSHTML5.Interop.ExecuteJavaScript("location.toString()"));The following C# code will retrieve the current Width of the browser window by reading the JavaScript "screen.width" property:
double screenWidth = Convert.ToDouble(CSHTML5.Interop.ExecuteJavaScript("screen.width"));You can pass C# variables to your JavaScript code by passing them as additional arguments to the "Interop.ExecuteJavaScript" method, and using the placeholders $0, $1, $2.... Here is an example:
void DisplayAMessage(string messageToDisplay) { CSHTML5.Interop.ExecuteJavaScript("alert($0)", messageToDisplay); }Note that creating JavaScript code by concatenating strings such as in "alert(" + messageToDisplay + ")" would NOT work, because the JavaScript code needs to exist at compile-time rather than at runtime.
You can also do it the other way round, that is, call C# from within your JavaScript code
To call C# from JavaScript, you need to pass a C#-based callback to your "ExecuteJavaScript" code, like in the following C# example:
void Main() { CSHTML5.Interop.ExecuteJavaScript(@" // This is JavaScript code alert('Hello from JavaScript'); // Let's call the C# method "MyCSharpMethod" from this JavaScript code. Due to the fact that it is passed as the first parameter to this ExecuteJavaScript call, we can access it with $0: $0(); ", (Action)MyCSharpMethod); } void MyCSharpMethod() { System.Windows.MessageBox.Show("Hello from C#"); }
You can see another example in the source code of the WebSocket extension (where the JavaScript-based websocket calls the C#-based OnOpenCallback method) or the File Open Dialog extension (where the Open Dialog of the browser calls the OnFileOpened method of C#).
Use this method to load a JavaScript file from either an online location (http/https) or the local project.
The following C# example loads the "FileSaver.js" file from an online location:
await CSHTML5.Interop.LoadJavaScriptFile("https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2014-11-29/FileSaver.min.js");
To load a file that you have added locally to your CSHTML5 project, use any of the two following URL syntaxes:
Here is an example:
await CSHTML5.Interop.LoadJavaScriptFile("ms-appx:///MyProject/FileSaver.min.js");
Important note: in the current version, you must take care by yourself of ensuring that the same file does not get loaded twice. You can do that for example by creating a static boolean variable that remembers whether the JavaScript file was already loaded or not.
Use this method to load a list of JavaScript files from either an online location (http/https) or the local project.
Unlike the method LoadJavaScriptFile, this one does not use the async/await pattern. Instead, the provided "callback" is called when the scripts have been loaded.
The following C# example loads two JavaScript files from an online location and displays a message when done:
CSHTML5.Interop.LoadJavaScriptFilesAsync(new string[] { @"https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.2/jspdf.min.js", @"https://cdnjs.cloudflare.com/ajax/libs/kendo-ui-core/2014.1.416/js/kendo.core.min.js" }, () => { MessageBox.Show("The scripts have been loaded."); });
To load a file that you have added locally to your CSHTML5 project, use any of the two following URL syntaxes:
Important note: in the current version, you must take care by yourself of ensuring that the same file does not get loaded twice. You can do that for example by creating a static boolean variable that remembers whether the JavaScript file was already loaded or not.
This method works the same as Interop.LoadJavaScriptFile()
This method works the same as Interop.LoadJavaScriptFilesAsync()
This method returns the HTML DOM element that corresponds to the specified FrameworkElement.
Important note: the FrameworkElement must be in the Visual Tree for this method to succeed. To ensure that the element is in the Visual Tree, you can read the IsLoaded property, or you can place your code in the "Loaded" event handler.
Here is an example:
public partial class MainPage : Page { public MainPage() { this.InitializeComponent(); this.Loaded += MainPage_Loaded; } void MainPage_Loaded(object sender, RoutedEventArgs e) { object rootDiv = CSHTML5.Interop.GetDiv(this); MessageBox.Show("The width of the root div is: " + Convert.ToDouble(CSHTML5.Interop.ExecuteJavaScript("$0.offsetWidth", rootDiv)).ToString()); } }
You can see a more advanced example by looking at the source code of the File Open Dialog extension.
You may also be interested by the HtmlPresenter control.
Returns "True" if the application is running in C# inside the Simulator, and "False" if the application is running in JavaScript in the web browser.
This property is useful when you need to do something different depending on whether the application is running in the browser or in the Simulator, due to the fact that some JavaScript features are not possible in the Simulator.
For example, if you want to open a new browser window, which cannot be done in the Simulator, you may want to display a "Not supported" message if the value of this property is True.
Returns True if the FrameworkElement is in the Visual Tree, and False otherwise.
This property is particularly useful when used in conjunction with the Interop.GetDiv method, which only works when the FrameworkElement is in the Visual Tree.
When this property returns True, it also means that the FrameworkElement is present on the HTML DOM tree.
Note: you can listen to the Loaded and Unloaded events to be notified when this property changes.