Demonstration (for Internet Explorer)

This page is a demonstration of the control, running as a control in Internet Explorer.

Browser Setup

This page works for Internet Explorer (IE) only. IE can host .NET user controls, embedded in the HTML as an <object> element. The requirements are:

  • Internet Explorer,
  • .NET framework (version 2 or later) installed on your machine,
  • JavaScript enabled (so that the page can interact with the control).

Version-specific setup:

Before IE8 Before IE8, this demonstration runs in the 'Internet' security zone (which shows it's able to run in a limited trust environment).
IE8 and later

IE8 and later restricted the ability to run .NET controls (see DotNet UserControls Restricted in IE8).

So, IE8 and above must run this in the 'Local intranet' or 'Trusted sites' zone.

.NET 4.5 and later

There's an additional registry change required to make it work with .NET 4.5 (documented in this Stack Overflow answer: Loading .NET UserControls in IE with .NET 4.5).

The registry setting is named EnableIEHosting. It's a DWORD setting whose value should be set to 1. It's defined in the following registry key:

  • In the HKCU Hive: HKCU\SOFTWARE\Microsoft\.NETFramework
  • In the the HKLM hive, but under different paths depending on the 32/64bit type of Windows:
    • 32-bit System: HKLM\SOFTWARE\MICROSOFT\.NETFramework
    • 64-bit System: HKLM\SOFTWARE\Wow6432Node\Microsoft\.NETFramework

In December 2017 I added the above registry setting to both the above keys, and ran it successfully on Windows 10 (64-bit), using Internet Explorer v11.

Live Sample

This in-browser demonstration is disabled: because it is only supported by Internet Explorer.

You can try the control by downloading and running it on your Windows machine. The download includes sample programs which embed and initialize the edit control.

Or configure your machine as described above, and then use Internet Explorer (not Edge) to view this page.

Here is the actual ModelText control in action, embedded as an <object> in this web page.


Here is the code which implements the sample shown above (the server side for this page is implemented using ASP MVC)).

In the Browser

Here is the relevant HTML (implemented as a MVC Partial View, using Razor syntax):

@model WebSite.Models.DemoData

<form method="post">

    <object id="modelTextControl"
            height="300" style="width: 100%"></object>
    <input type="hidden" name="modelTextHidden" id="modelTextHidden" value="@Model.ToString()" />
        <input type="submit" name="modelTextSubmit" value="Submit" onclick="modelTextOnSubmit();" id="modelTextSubmit" />
        <span id="modelTextError" class="hidden"></span>

    @if (Model.HasPostBack)
            You submitted the following text:

    <script type="text/javascript" src="~/Scripts/demo-in-browser.js"></script>


Here is the correspondng JavaScript (the demo-in-browser.js file referenced in the HTML above):

(function () {

    function isInternetExplorer()
        return (navigator.userAgent.indexOf('MSIE') !== -1)
        || (navigator.appVersion.indexOf('Trident/') > 0);

    function hide(id) {
        var el = document.getElementById(id);
        el.className += " d-none";

    if (!isInternetExplorer()) {
    } else {

    function getHiddenControl() {
        return document.getElementById('modelTextHidden');
    function getSubmitControl() {
        return document.getElementById('modelTextSubmit');
    function getEditControl() {
        return document.getElementById('modelTextControl');
    function getErrorSpan() {
        return document.getElementById('modelTextError');

    // we want to submit a postback if the user presses the Save button on the embedded control's toolbar,
    // or if the user presses the Ctrl+S keyboard shortcut to Save ... the control can't raise an event into
    // this javascript code, so instead we poll here -- test the control's haveSaveRequest() method once per
    // second, and if it returns true then simulate clicking on the control button.
    function startPolling() {
        setTimeout(pollForEvents, 1000);
    function pollForEvents() {
        var editControl = getEditControl();
        var haveSaveRequest = editControl.haveSaveRequest();
        if (haveSaveRequest) {
            var submitControl = getSubmitControl();

    function showError(text) {
        var span = getErrorSpan();
        var msg = document.createTextNode(text);
        span.className = 'failure';
        getSubmitControl().disabled = true;

    // called once, when the document is loaded
    function initializeEditControl() {
        var editControl = getEditControl();
        var hiddenControl = getHiddenControl();
        editControl.text = hiddenControl.value;
        try {
        } catch (failure) {
            // I don't know how to test whether the control was successfully loaded into the object
            // except by trying to invoke it, and catching the exception if it's thrown

    function htmlEscape(str) {
        return str
            .replace(/&/g, '&amp;')
            //.replace(/"/g, '&quot;')
            //.replace(/'/g, '&#39;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;');

    // this method is called when the Submit button is pressed
    window['modelTextOnSubmit'] = function () {
        var editControl = getEditControl();
        var hiddenControl = getHiddenControl();
        var document = editControl.getDocumentFragment();
        // HTML-encode the string which is now contained in the document variable, otherwise the server throws an exception like
        // [HttpRequestValidationException (0x80004005): A potentially dangerous Request.Form value was detected from the client
        // ASP.NET has detected data in the request that is potentially dangerous because it might include HTML markup or script.
        // The data might represent an attempt to compromise the security of your application, such as a cross-site scripting attack.
        document = htmlEscape(document);
        hiddenControl.value = document;

On the Server

Here are the relevant methods from the MVC controller class:

        public ActionResult Demonstration()
            // get previously-posted data from this user session
            // (alternatively you could load it from a database or something)
            DemoData demoData = (DemoData)Session["demoData"];
            if (demoData == null)
                // or get the initial default data
                demoData = DemoData.defaultDemoData;
            // pass the data into the view
            return View(demoData);
        public ActionResult Demonstration(string modelTextHidden)
            // data in the modelTextHidden field was HTML-escaped by the javascript in the form
            modelTextHidden = htmlUnescape(modelTextHidden);
            DemoData demoData = new DemoData(modelTextHidden);
            // save the data in the user session 
            // (alternatively you could save it in a database or something)
            Session["demoData"] = demoData;
            // redirect after postback
            return RedirectToAction("Demonstration", "Html");
        static string htmlUnescape(string str)
            // this implementation reverses the escaping defined in the htmlEscape function in javascript
            return str
                //.Replace("&quot;", "\"")
                //.Replace("&#39;", "'")
                .Replace("&lt;", "<")
                .Replace("&gt;", ">")
                .Replace("&amp;", "&");

Here is the definition of the MVC data model class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;

namespace WebSite.Models
    // This includes two types of data:
    // - a boolean to show whether this is default input data, or whether it's output which the user posted back
    // - the HTML string (which is input or output from the ModelText control)
    public class DemoData
        public bool HasPostBack { get; private set; }

        // don't HTML-encode the string; it will be HTML encoded automatically
        // by the Razor statements which write the data into the View.
        readonly private string rawHtmlData;

        public DemoData(string postBackData)
            : this(postBackData, true)
        { }
        DemoData(string rawHtmlData, bool hasPostBack)
            this.HasPostBack = hasPostBack;
            this.rawHtmlData = rawHtmlData;

        public override string ToString() { return rawHtmlData; }

        public static DemoData defaultDemoData
            get { return new DemoData(defaultHtml, false); }

        static string defaultHtml =
 @" <body>
  <h1>Sample programs</h1>
  <p>Please contact me (the author) at <a href=""mailto:modeltext2018""></a> to say whether you like this software, to make suggestions, to ask questions, and any/or for bug reports. For further details, see also the <a href="""">Contact</a> page.</p>
  <h2>How to</h2>
  <p>Here are some notes about how I wrote the sample programs (for example, the FileOpenAndSave project):</p>
   <li>Use Visual Studio to create a new, empty Windows Forms Application.</li>
   <li>Use the Visual Studio Designer, to design the layout of the form: the form for this example project simply includes one application menu strip, plus a panel on which the ModelText HTML control is superimposed at run-time. Also use the Visual Studio Designer to define the menu items, and to declare the events handlers which implement each menu item.</li>
   <li>Read <a href="""">APIs for the HTML Control</a> for a description of how to use the ModelText HTML control, and add the corresponding statements to the Form1.cs source file.</li>
  <h2>List of samples</h2>
  <p>There are two sample programs:</p>
    <td>This program shows how to include the following functionality:
      <li>Load and save a document</li>
      <li>Implement the 'Save' and 'Insert Hyperlink' commands</li>
      <li>Implement your own, custom, edit command (e.g. 'Merge Paragraphs')</li>
    <td>This program shows how to display a form, and get the contents of the form controls when the user clicks the submit button.</td>

The control itself (i.e. ModelEditControl1.dll), which is referenced in the classid attribute of the <object> element, is located in the same folder of the web server as this page in which it's embedded (so, /html/ModelEditControl1.dll).

It seems to be necessary to rename the DLL (e.g. use ModelEditControl1.dll instead of ModelEditControl.dll). I don't know why that is -- possibly some problem with having or cacheing two versions of the same assembly.